@leabankab/component-library 7.3.0 → 8.1.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/CHANGELOG.md +745 -0
- package/README.md +2 -5
- package/dist/component-library.es.js +2948 -5676
- package/dist/component-library.es.js.map +1 -1
- package/dist/component-library.umd.js +2 -28
- package/dist/component-library.umd.js.map +1 -1
- package/dist/components/animations/icons/status-icon.d.ts +4 -0
- package/dist/components/animations/illustrations/check-animation.d.ts +8 -0
- package/dist/components/animations/illustrations/pulse-animation.d.ts +5 -1
- package/dist/components/animations/illustrations/status-animation.d.ts +8 -1
- package/dist/components/animations/shared.d.ts +6 -32
- package/dist/components/animations/spinner.d.ts +18 -0
- package/dist/components/animations/use-animation-labels.d.ts +0 -5
- package/dist/components/buttons/action-button.d.ts +8 -10
- package/dist/components/buttons/button-base.d.ts +26 -12
- package/dist/components/buttons/button.d.ts +2 -2
- package/dist/components/buttons/close-button.d.ts +1 -1
- package/dist/components/buttons/icon-button.d.ts +1 -13
- package/dist/components/buttons/skip-link.d.ts +21 -4
- package/dist/components/color-roles.d.ts +8 -0
- package/dist/components/data-display/card.d.ts +54 -4
- package/dist/components/data-display/chip.d.ts +50 -8
- package/dist/components/data-display/data-field.d.ts +15 -4
- package/dist/components/data-display/tooltip.d.ts +74 -22
- package/dist/components/feedback/alert-parts.d.ts +10 -9
- package/dist/components/feedback/alert.d.ts +1 -1
- package/dist/components/feedback/simple-dialog.d.ts +1 -1
- package/dist/components/form/amount-slider.d.ts +68 -0
- package/dist/components/form/autocomplete.d.ts +56 -59
- package/dist/components/form/checkbox-box.d.ts +11 -0
- package/dist/components/form/checkbox.d.ts +67 -7
- package/dist/components/form/combo-field.d.ts +68 -0
- package/dist/components/form/email-input.d.ts +28 -26
- package/dist/components/form/field-parts.d.ts +50 -0
- package/dist/components/form/index.d.ts +3 -9
- package/dist/components/form/input.d.ts +57 -13
- package/dist/components/form/multi-select.d.ts +12 -14
- package/dist/components/form/number-input-unit.d.ts +28 -0
- package/dist/components/form/number-input.d.ts +46 -18
- package/dist/components/form/phone-number-input/phone-number-input.d.ts +44 -14
- package/dist/components/form/radio-card.d.ts +94 -43
- package/dist/components/form/radio-circle.d.ts +14 -13
- package/dist/components/form/radio-group-root.d.ts +88 -0
- package/dist/components/form/radio.d.ts +68 -24
- package/dist/components/form/select-field.d.ts +78 -0
- package/dist/components/form/select.d.ts +30 -42
- package/dist/components/form/slider-parts.d.ts +34 -0
- package/dist/components/form/slider.d.ts +40 -16
- package/dist/components/form/use-autocomplete-labels.d.ts +3 -16
- package/dist/components/form/use-blur-outside.d.ts +7 -0
- package/dist/components/form/use-focus-target-ref.d.ts +11 -0
- package/dist/components/form/use-tooltip-trigger-labels.d.ts +5 -0
- package/dist/components/index.d.ts +0 -1
- package/dist/components/navigation/form-stepper.d.ts +1 -1
- package/dist/components/navigation/index.d.ts +1 -1
- package/dist/components/navigation/linear-form-stepper.d.ts +1 -1
- package/dist/components/navigation/progress-circle.d.ts +14 -8
- package/dist/components/navigation/tabs.d.ts +37 -34
- package/dist/components/navigation/use-stepper-labels.d.ts +1 -1
- package/dist/components/typography/link.d.ts +25 -16
- package/dist/components/typography/lists.d.ts +20 -23
- package/dist/components/typography/text.d.ts +46 -10
- package/dist/components/ui/app-header.d.ts +9 -1
- package/dist/cookie-consent/react.d.ts +0 -1
- package/dist/cookie-consent-react.cjs +1 -1
- package/dist/cookie-consent-react.cjs.map +1 -1
- package/dist/cookie-consent-react.mjs +106 -96
- package/dist/cookie-consent-react.mjs.map +1 -1
- package/dist/cookie-consent.css +1 -1
- package/dist/date-picker/datepicker.d.ts +140 -0
- package/dist/date-picker/index.d.ts +18 -0
- package/dist/date-picker/theme/field-base.d.ts +23 -0
- package/dist/date-picker/theme/form-control.theme.d.ts +7 -0
- package/dist/date-picker/theme/index.d.ts +12 -0
- package/dist/date-picker/theme/input.theme.d.ts +6 -0
- package/dist/{components/form/datepicker → date-picker}/use-view-toggle-labels.d.ts +1 -1
- package/dist/date-picker.cjs +2 -0
- package/dist/date-picker.cjs.map +1 -0
- package/dist/date-picker.mjs +1012 -0
- package/dist/date-picker.mjs.map +1 -0
- package/dist/{components/dev-panel → dev-panel}/dev-panel-payload.d.ts +1 -1
- package/dist/{components/dev-panel → dev-panel}/dev-panel-status.d.ts +2 -2
- package/dist/{components/dev-panel → dev-panel}/dev-panel-steps.d.ts +2 -1
- package/dist/dev-panel/dev-panel.d.ts +118 -0
- package/dist/dev-panel/index.d.ts +10 -0
- package/dist/{components/dev-panel → dev-panel}/json-highlight.d.ts +2 -2
- package/dist/dev-panel/parts.d.ts +9 -0
- package/dist/{components/dev-panel → dev-panel}/segmented-control.d.ts +5 -4
- package/dist/{components/dev-panel → dev-panel}/use-dev-panel-labels.d.ts +1 -1
- package/dist/{components/dev-panel → dev-panel}/use-roving-radio.d.ts +2 -2
- package/dist/dev-panel.cjs +3 -0
- package/dist/dev-panel.cjs.map +1 -0
- package/dist/dev-panel.css +1 -0
- package/dist/dev-panel.mjs +919 -0
- package/dist/dev-panel.mjs.map +1 -0
- package/dist/fonts/ClashGrotesk-Variable.woff2 +0 -0
- package/dist/index.css +1 -1
- package/dist/index.d.ts +1 -3
- package/dist/provider/lea-provider.d.ts +4 -7
- package/dist/react-hook-form/form-field.d.ts +76 -0
- package/dist/react-hook-form/index.d.ts +1 -0
- package/dist/react-hook-form.cjs +2 -0
- package/dist/react-hook-form.cjs.map +1 -0
- package/dist/react-hook-form.mjs +33 -0
- package/dist/react-hook-form.mjs.map +1 -0
- package/dist/tailwind.css +103 -17
- package/dist/theme/index.d.ts +0 -4
- package/dist/theme/token-types.d.ts +15 -3
- package/dist/theme/tokens/colors.d.ts +13 -0
- package/dist/theme/tokens/font-family.d.ts +9 -0
- package/dist/theme/tokens/font-sizes.d.ts +8 -0
- package/dist/theme/tokens/index.d.ts +4 -1
- package/dist/theme/tokens/line-heights.d.ts +11 -0
- package/dist/theme/tokens/spacing.d.ts +6 -0
- package/dist/theme/tokens/text-styles.d.ts +61 -0
- package/dist/theme/tokens/type-scale.d.ts +21 -0
- package/dist/theme/types.d.ts +19 -30
- package/dist/validation/email.d.ts +18 -0
- package/dist/validation/mobile-patterns.d.ts +10 -0
- package/dist/validation/national-id.d.ts +26 -0
- package/dist/validation/phone.d.ts +30 -0
- package/package.json +45 -6
- package/dist/components/dev-panel/dev-panel.d.ts +0 -61
- package/dist/components/dev-panel/index.d.ts +0 -9
- package/dist/components/form/datepicker/datepicker.d.ts +0 -99
- package/dist/components/form/datepicker/index.d.ts +0 -1
- package/dist/components/form/fields/autocomplete-field.d.ts +0 -17
- package/dist/components/form/fields/boolean-radio-field.d.ts +0 -3
- package/dist/components/form/fields/checkbox-field.d.ts +0 -12
- package/dist/components/form/fields/datepicker-field.d.ts +0 -9
- package/dist/components/form/fields/email-field.d.ts +0 -10
- package/dist/components/form/fields/field-types.d.ts +0 -18
- package/dist/components/form/fields/index.d.ts +0 -14
- package/dist/components/form/fields/input-field.d.ts +0 -9
- package/dist/components/form/fields/multi-select-field.d.ts +0 -9
- package/dist/components/form/fields/number-field.d.ts +0 -10
- package/dist/components/form/fields/phone-number-field.d.ts +0 -11
- package/dist/components/form/fields/radio-card-field.d.ts +0 -22
- package/dist/components/form/fields/radio-field.d.ts +0 -16
- package/dist/components/form/fields/select-field.d.ts +0 -9
- package/dist/components/form/fields/use-field-control.d.ts +0 -6
- package/dist/components/form/fields/use-tooltip-trigger-labels.d.ts +0 -5
- package/dist/components/form/form-control/form-control-context.d.ts +0 -35
- package/dist/components/form/form-control/form-control-label.d.ts +0 -1
- package/dist/components/form/form-control/form-control.d.ts +0 -13
- package/dist/components/form/form-control/form-helper-text.d.ts +0 -9
- package/dist/components/form/form-control/form-label.d.ts +0 -9
- package/dist/components/form/form-control/index.d.ts +0 -5
- package/dist/components/form/input-label.d.ts +0 -9
- package/dist/theme/components/accordion.theme.d.ts +0 -7
- package/dist/theme/components/action-button.theme.d.ts +0 -45
- package/dist/theme/components/alert.theme.d.ts +0 -2
- package/dist/theme/components/autocomplete.theme.d.ts +0 -2
- package/dist/theme/components/baseline-css.d.ts +0 -2
- package/dist/theme/components/button.theme.d.ts +0 -2
- package/dist/theme/components/card.theme.d.ts +0 -2
- package/dist/theme/components/checkbox.theme.d.ts +0 -2
- package/dist/theme/components/chip.theme.d.ts +0 -2
- package/dist/theme/components/dev-panel.theme.d.ts +0 -95
- package/dist/theme/components/dialog.theme.d.ts +0 -2
- package/dist/theme/components/drawer.theme.d.ts +0 -4
- package/dist/theme/components/field-base.d.ts +0 -31
- package/dist/theme/components/form-control-label.theme.d.ts +0 -2
- package/dist/theme/components/form-control.theme.d.ts +0 -2
- package/dist/theme/components/index.d.ts +0 -2
- package/dist/theme/components/input.theme.d.ts +0 -3
- package/dist/theme/components/link.theme.d.ts +0 -2
- package/dist/theme/components/menu-item.theme.d.ts +0 -2
- package/dist/theme/components/number-input.theme.d.ts +0 -23
- package/dist/theme/components/phone-number-input.theme.d.ts +0 -43
- package/dist/theme/components/radio.theme.d.ts +0 -2
- package/dist/theme/components/select.theme.d.ts +0 -2
- package/dist/theme/components/slider.theme.d.ts +0 -2
- package/dist/theme/components/tabs.theme.d.ts +0 -34
- package/dist/theme/components/tooltip.theme.d.ts +0 -110
- package/dist/theme/components/typography.theme.d.ts +0 -2
- package/dist/theme/mui-augmentation.d.ts +0 -147
- package/dist/theme/sx-config.d.ts +0 -10
- /package/dist/{components/form/datepicker → date-picker}/calendar-header.d.ts +0 -0
- /package/dist/{components/form/datepicker → date-picker}/drawer-toolbar.d.ts +0 -0
- /package/dist/{theme/components → date-picker/theme}/date-picker.theme.d.ts +0 -0
- /package/dist/{theme/components → date-picker/theme}/icon-button.theme.d.ts +0 -0
- /package/dist/{theme/tokens → date-picker/theme}/typography.d.ts +0 -0
- /package/dist/{components/form/datepicker → date-picker}/use-calendar-header-labels.d.ts +0 -0
- /package/dist/{components/form/datepicker → date-picker}/use-datepicker-title-labels.d.ts +0 -0
- /package/dist/{components/form/datepicker → date-picker}/view-renderers.d.ts +0 -0
- /package/dist/{components/form/datepicker → date-picker}/view-toggle.d.ts +0 -0
- /package/dist/{components/dev-panel → dev-panel}/dev-panel-country.d.ts +0 -0
- /package/dist/{components/dev-panel → dev-panel}/dev-panel-flow.d.ts +0 -0
- /package/dist/{components/dev-panel → dev-panel}/dev-panel-footer.d.ts +0 -0
- /package/dist/{components/dev-panel → dev-panel}/dev-panel-step-state.d.ts +0 -0
- /package/dist/{components/dev-panel → dev-panel}/dev-panel-variant.d.ts +0 -0
- /package/dist/{components/dev-panel → dev-panel}/use-copy.d.ts +0 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"component-library.es.js","names":[],"sources":["../src/components/animations/shared.tsx","../src/i18n/languages.ts","../src/i18n/language-context.tsx","../src/i18n/create-translation.ts","../src/components/animations/use-animation-labels.ts","../src/components/animations/icons/status-icon.tsx","../src/components/animations/illustrations/check-animation.tsx","../src/components/animations/illustrations/pulse-animation.tsx","../src/components/animations/illustrations/status-animation.tsx","../src/components/buttons/action-button.tsx","../src/utils/merge-class-name.ts","../src/components/buttons/button.module.css","../src/components/buttons/button-base.tsx","../src/components/buttons/button.tsx","../src/components/feedback/use-close-label.ts","../src/components/buttons/icon-button.tsx","../src/components/buttons/close-button.tsx","../src/utils/downloadFile.ts","../src/components/buttons/use-download-labels.ts","../src/components/buttons/download-trigger.tsx","../src/theme/tokens/breakpoints.ts","../src/theme/tokens/colors.ts","../src/theme/tokens/font-sizes.ts","../src/theme/tokens/font-weights.ts","../src/theme/tokens/palette.ts","../src/theme/tokens/shadows.ts","../src/theme/tokens/shape.ts","../src/theme/tokens/spacing.ts","../src/theme/tokens/transitions.ts","../src/theme/tokens/typography.ts","../src/components/typography/link.tsx","../src/components/typography/lists.tsx","../src/components/typography/text.tsx","../src/components/data-display/data-field.tsx","../src/components/data-display/card.tsx","../src/components/data-display/use-chip-labels.ts","../src/components/data-display/chip.tsx","../src/theme/components/tooltip.theme.ts","../src/components/data-display/tooltip.tsx","../src/theme/utils/focus-visible-styles.ts","../src/theme/components/dev-panel.theme.ts","../src/components/dev-panel/use-dev-panel-labels.ts","../src/components/dev-panel/dev-panel.tsx","../src/components/dev-panel/use-roving-radio.ts","../src/components/dev-panel/segmented-control.tsx","../src/components/dev-panel/dev-panel-country.tsx","../src/components/dev-panel/dev-panel-variant.tsx","../src/components/dev-panel/dev-panel-step-state.tsx","../src/components/dev-panel/dev-panel-steps.tsx","../src/components/dev-panel/dev-panel-status.tsx","../src/components/dev-panel/use-copy.ts","../src/components/dev-panel/dev-panel-flow.tsx","../src/components/dev-panel/json-highlight.tsx","../src/components/dev-panel/dev-panel-payload.tsx","../src/components/dev-panel/dev-panel-footer.tsx","../src/components/feedback/alert.module.css","../src/components/feedback/alert-parts.tsx","../src/components/feedback/alert.tsx","../src/components/feedback/dialog.module.css","../src/components/feedback/dialog.tsx","../src/components/feedback/drawer.module.css","../src/components/feedback/drawer.tsx","../src/components/layout/container.module.css","../src/components/layout/container.tsx","../src/components/feedback/global-alert.tsx","../src/components/feedback/simple-dialog.tsx","../src/components/feedback/simple-drawer.tsx","../src/validation/types.ts","../src/validation/national-id.ts","../src/validation/phone.ts","../src/validation/modulo-97.ts","../src/validation/bank-account.ts","../src/validation/reference-number.ts","../src/validation/email.ts","../src/components/form/form-control/form-control-context.tsx","../src/components/form/form-control/form-helper-text.tsx","../src/components/form/input-label.tsx","../src/components/form/use-autocomplete-labels.ts","../src/components/form/autocomplete.tsx","../src/components/form/checkbox.tsx","../src/components/form/datepicker/use-calendar-header-labels.ts","../src/components/form/datepicker/calendar-header.tsx","../src/components/form/datepicker/datepicker-sheet.module.css","../src/components/form/datepicker/drawer-toolbar.tsx","../src/components/form/datepicker/use-view-toggle-labels.ts","../src/components/form/datepicker/view-toggle.tsx","../src/components/form/datepicker/view-renderers.tsx","../src/components/form/datepicker/use-datepicker-title-labels.ts","../src/components/form/datepicker/datepicker.tsx","../src/components/form/email-input.tsx","../src/components/form/fields/use-field-control.ts","../src/components/form/fields/autocomplete-field.tsx","../src/components/form/form-control/form-control.tsx","../src/components/form/form-control/form-label.tsx","../src/components/form/radio-circle.tsx","../src/components/form/radio.tsx","../src/components/form/radio-card.tsx","../src/components/form/fields/use-tooltip-trigger-labels.ts","../src/components/form/fields/radio-card-field.tsx","../src/components/form/fields/boolean-radio-field.tsx","../src/components/form/fields/checkbox-field.tsx","../src/components/form/fields/datepicker-field.tsx","../src/components/form/fields/email-field.tsx","../src/components/form/input.tsx","../src/components/form/fields/input-field.tsx","../src/components/form/select.tsx","../src/components/form/multi-select.tsx","../src/components/form/fields/multi-select-field.tsx","../src/theme/components/number-input.theme.ts","../src/components/form/number-input.tsx","../src/components/form/fields/number-field.tsx","../src/theme/components/accordion.theme.ts","../src/theme/components/action-button.theme.ts","../src/theme/components/alert.theme.ts","../src/theme/components/field-base.ts","../src/theme/components/autocomplete.theme.ts","../src/assets/fonts/ClashGrotesk-Bold.woff","../src/assets/fonts/ClashGrotesk-Extralight.woff","../src/assets/fonts/ClashGrotesk-Light.woff","../src/assets/fonts/ClashGrotesk-Medium.woff","../src/assets/fonts/ClashGrotesk-Regular.woff","../src/assets/fonts/ClashGrotesk-Semibold.woff","../src/theme/components/baseline-css.ts","../src/theme/components/button.theme.ts","../src/theme/components/card.theme.ts","../src/theme/components/chip.theme.ts","../src/theme/components/checkbox.theme.ts","../src/theme/components/date-picker.theme.ts","../src/theme/components/dialog.theme.ts","../src/theme/components/drawer.theme.ts","../src/theme/components/form-control-label.theme.ts","../src/theme/components/form-control.theme.ts","../src/theme/components/icon-button.theme.ts","../src/theme/components/input.theme.ts","../src/theme/components/link.theme.ts","../src/theme/components/menu-item.theme.ts","../src/theme/components/radio.theme.ts","../src/theme/components/select.theme.ts","../src/theme/components/slider.theme.ts","../src/theme/components/typography.theme.ts","../src/theme/components/index.ts","../src/theme/sx-config.ts","../src/theme/index.ts","../src/theme/components/phone-number-input.theme.ts","../src/components/form/phone-number-input/countries.ts","../src/components/form/phone-number-input/phone-number-input.tsx","../src/components/form/fields/phone-number-field.tsx","../src/components/form/fields/radio-field.tsx","../src/components/form/fields/select-field.tsx","../src/components/form/slider.tsx","../src/components/form/switch.module.css","../src/components/form/switch.tsx","../src/components/layout/grid.module.css","../src/components/layout/responsive.ts","../src/components/layout/grid.tsx","../src/components/layout/stack.module.css","../src/components/layout/stack.tsx","../src/components/navigation/progress-circle.tsx","../src/components/navigation/use-stepper-labels.ts","../src/components/navigation/form-stepper.tsx","../src/components/navigation/linear-form-stepper.module.css","../src/components/navigation/linear-form-stepper.tsx","../src/components/navigation/step-progress.tsx","../src/theme/components/tabs.theme.ts","../src/components/navigation/tabs.tsx","../src/components/surfaces/accordion.module.css","../src/components/surfaces/accordion.tsx","../src/components/surfaces/simple-accordion.tsx","../src/components/ui/brand-divider.module.css","../src/components/ui/brand-divider.tsx","../src/components/ui/app-header.module.css","../src/components/ui/app-header.tsx","../src/hooks/country/countries.ts","../src/hooks/country/country-context.tsx","../src/hooks/use-format-currency.ts","../src/hooks/use-format-date.ts","../src/hooks/use-format-number.ts","../src/hooks/validation/use-validation.ts","../src/provider/lea-provider.tsx","../src/utils/formatDecimal.ts","../src/utils/formatDecimalString.ts","../src/utils/formatPercentage.ts","../src/utils/parseExpirationDate.ts"],"sourcesContent":["import { Box, type SxProps, type Theme } from \"@mui/material\";\nimport { motion } from \"motion/react\";\nimport { Check } from \"lucide-react\";\nimport { type ReactNode } from \"react\";\n\nexport type AnimationSize = \"small\" | \"large\";\n\nexport type AnimationColor = \"purple\" | \"green\";\n\nexport const colorMap: Record<\n AnimationColor,\n { base: string; contrast: string }\n> = {\n purple: { base: \"purple.base\", contrast: \"purple.contrast\" },\n green: { base: \"teal.base\", contrast: \"teal.contrast\" },\n};\n\nexport const visuallyHidden = {\n position: \"absolute\",\n width: \"1px\",\n height: \"1px\",\n overflow: \"hidden\",\n clip: \"rect(0 0 0 0)\",\n whiteSpace: \"nowrap\",\n} as const;\n\nexport const reducedMotionOverride = {\n \"@media (prefers-reduced-motion: reduce)\": {\n animation: \"none\",\n },\n} as const;\n\nexport const reducedMotionHidden = {\n \"@media (prefers-reduced-motion: reduce)\": {\n animation: \"none\",\n opacity: 0,\n },\n} as const;\n\nexport const illustrationBadgeShadow =\n \"rgba(255, 255, 255, 0.1) 0px 1px 1px 0px inset, rgba(50, 50, 93, 0.25) 0px 30px 60px -20px, rgba(0, 0, 0, 0.25) 0px 18px 36px -18px\";\n\nexport type ConfettiParticle = {\n id: number;\n x: number;\n y: number;\n dotSize: number;\n round: boolean;\n colour?: string;\n spin?: number;\n};\n\ntype BuildParticlesOptions = {\n count: number;\n burst: number;\n distanceAt: (index: number) => number;\n dotSizeAt: (index: number) => number;\n colourAt?: (index: number) => string | undefined;\n withSpin?: boolean;\n};\n\nexport const buildParticles = ({\n count,\n burst,\n distanceAt,\n dotSizeAt,\n colourAt,\n withSpin = false,\n}: BuildParticlesOptions): ConfettiParticle[] =>\n Array.from({ length: count }, (_, i) => {\n const angle = (i / count) * Math.PI * 2;\n const distance = burst * distanceAt(i);\n return {\n id: i,\n x: Math.cos(angle) * distance,\n y: Math.sin(angle) * distance,\n dotSize: dotSizeAt(i),\n round: i % 2 === 0,\n ...(colourAt\n ? { colour: colourAt(i) }\n : {}),\n ...(withSpin ? { spin: (i % 2 === 0 ? 1 : -1) * 120 } : {}),\n };\n });\n\ntype ConfettiParticlesProps = {\n particles: ConfettiParticle[];\n /** Illustration confetti drifts down slightly and spins. */\n variant?: \"illustration\" | \"icon\";\n delay?: number;\n duration?: number;\n /** When set, particles use currentColor instead of per-particle colours. */\n useCurrentColor?: boolean;\n};\n\nexport const ConfettiParticles = ({\n particles,\n variant = \"illustration\",\n delay = variant === \"illustration\" ? 0.18 : 0.1,\n duration = variant === \"illustration\" ? 1.1 : 0.8,\n useCurrentColor = variant === \"icon\",\n}: ConfettiParticlesProps) =>\n particles.map((p) => (\n <motion.span\n key={p.id}\n initial={{ x: 0, y: 0, scale: 0, opacity: 0 }}\n animate={\n variant === \"illustration\"\n ? {\n x: [0, p.x],\n y: [0, p.y, p.y + 10],\n scale: [0, 1, 0.7],\n opacity: [0, 1, 0],\n rotate: p.spin != null ? [0, p.spin] : undefined,\n }\n : {\n x: [0, p.x],\n y: [0, p.y],\n scale: [0, 1, 0.6],\n opacity: [0, 1, 0],\n }\n }\n transition={{\n duration,\n ease: \"easeOut\",\n times: variant === \"illustration\" ? [0, 0.25, 1] : [0, 0.3, 1],\n delay,\n }}\n style={{\n position: \"absolute\",\n width: p.dotSize,\n height: p.dotSize,\n borderRadius: p.round ? \"50%\" : 1,\n backgroundColor: useCurrentColor ? \"currentColor\" : p.colour,\n pointerEvents: \"none\",\n }}\n />\n ));\n\ntype AnimationBadgeProps = {\n size: number;\n base: string;\n contrast: string;\n iconSize: number;\n boxShadow?: string;\n sx?: SxProps<Theme>;\n children?: ReactNode;\n};\n\nexport const AnimationBadge = ({\n size,\n base,\n contrast,\n iconSize,\n boxShadow,\n sx,\n children,\n}: AnimationBadgeProps) => (\n <Box\n sx={[\n {\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n width: size,\n height: size,\n borderRadius: \"50%\",\n backgroundColor: base,\n color: contrast,\n ...(boxShadow ? { boxShadow } : {}),\n },\n ...(Array.isArray(sx) ? sx : sx ? [sx] : []),\n ]}\n >\n {children ?? <Check size={iconSize} strokeWidth={3} aria-hidden />}\n </Box>\n);\n","/**\n * Languages supported by the component library's built-in translations. The\n * consumer selects one via `LeaProvider`'s `language` prop; components read it\n * with `useLanguage` (usually through `createTranslation`).\n */\nexport const LANGUAGES = [\"no\", \"se\", \"fi\", \"es\"] as const;\n\nexport type Language = (typeof LANGUAGES)[number];\n\n/** Fallback language used when no provider is present or a key is missing. */\nexport const DEFAULT_LANGUAGE = \"no\" satisfies Language;\n","\"use client\";\n\nimport { createContext, useContext } from \"react\";\nimport { DEFAULT_LANGUAGE, type Language } from \"./languages\";\n\n/**\n * Holds the currently selected language. Provided by `LeaProvider` and read by\n * components (typically via `createTranslation`). Defaults to `DEFAULT_LANGUAGE`\n * so components still render sensibly when used without the provider.\n */\nexport const LanguageContext = createContext<Language>(DEFAULT_LANGUAGE);\n\n/** Returns the language from the nearest `LeaProvider`, or `DEFAULT_LANGUAGE`. */\nexport const useLanguage = (): Language => useContext(LanguageContext);\n","\"use client\";\n\nimport { useLanguage } from \"./language-context\";\nimport { DEFAULT_LANGUAGE, type Language } from \"./languages\";\n\n/**\n * Translations for a single string, keyed by language. The `no` key is required\n * so the `DEFAULT_LANGUAGE` fallback always resolves; the others are optional.\n */\nexport type TranslationMap = { no: string } & Partial<Record<Language, string>>;\n\n/** A named set of translatable strings, each keyed by language. */\nexport type TranslationSchema = Record<string, TranslationMap>;\n\n/**\n * Creates a hook that returns co-located strings for the current language,\n * each falling back to `no`. Define the schema at module scope and call the\n * returned hook inside a component:\n *\n * ```tsx\n * const useLabels = createTranslation({\n * increase: { no: \"Øk\", se: \"Öka\", fi: \"Lisää\", es: \"Aumentar\" },\n * decrease: { no: \"Reduser\", se: \"Minska\", fi: \"Vähennä\", es: \"Disminuir\" },\n * });\n *\n * function Stepper() {\n * const t = useLabels();\n * return <button aria-label={t.increase} />;\n * }\n * ```\n */\nexport function createTranslation<T extends TranslationSchema>(schema: T) {\n return function useTranslation(): Record<keyof T, string> {\n const language = useLanguage();\n const result = {} as Record<keyof T, string>;\n (Object.keys(schema) as (keyof T)[]).forEach((key) => {\n const map = schema[key];\n result[key] = map[language] ?? map[DEFAULT_LANGUAGE];\n });\n return result;\n };\n}\n","import { createTranslation } from \"../../i18n\";\n\n/**\n * Translated accessible names for the status animations (`StatusIcon`,\n * `StatusAnimation`, `CheckAnimation`, `PulseAnimation`). Each component takes\n * a label prop so a consumer can say something more specific than \"loading\".\n */\nexport const useAnimationLabels = createTranslation({\n pending: {\n no: \"Venter\",\n se: \"Väntar\",\n fi: \"Odottaa\",\n es: \"Esperando\",\n },\n loading: {\n no: \"Laster\",\n se: \"Laddar\",\n fi: \"Ladataan\",\n es: \"Cargando\",\n },\n done: { no: \"Ferdig\", se: \"Klart\", fi: \"Valmis\", es: \"Completado\" },\n confirmed: {\n no: \"Bekreftet\",\n se: \"Bekräftat\",\n fi: \"Vahvistettu\",\n es: \"Confirmado\",\n },\n});\n","import { Box, CircularProgress } from \"@mui/material\";\nimport { AnimatePresence, motion, useReducedMotion } from \"motion/react\";\nimport { useMemo } from \"react\";\n\nimport {\n AnimationBadge,\n type AnimationColor,\n buildParticles,\n colorMap,\n ConfettiParticles,\n} from \"../shared\";\nimport { useAnimationLabels } from \"../use-animation-labels\";\n\ntype StatusIconStatus = \"pending\" | \"loading\" | \"done\";\n\ntype StatusIconProps = {\n status: StatusIconStatus;\n /** Rendered size in px. */\n size?: number;\n color?: AnimationColor;\n /**\n * Accessible name; defaults to the translated label for the current status in\n * the `LeaProvider` language.\n */\n label?: string;\n};\n\nconst CONFETTI_COUNT = 8;\n\n/**\n * A small, inline status icon for step / progress lists. Transitions through\n * `pending` (empty ring) → `loading` (spinner) → `done` (filled check with a\n * one-time confetti pop). One-shot, not infinite. Respects\n * `prefers-reduced-motion`.\n */\nexport const StatusIcon = ({\n status,\n size = 24,\n color = \"purple\",\n label,\n}: StatusIconProps) => {\n const prefersReducedMotion = useReducedMotion();\n const labels = useAnimationLabels();\n const { base, contrast } = colorMap[color];\n\n const ring = Math.max(2, Math.round(size * 0.09));\n const thickness = (ring * 44) / size;\n const checkSize = Math.round(size * 0.6);\n const burst = size;\n\n const particles = useMemo(\n () =>\n buildParticles({\n count: CONFETTI_COUNT,\n burst,\n distanceAt: (i) => 0.7 + (i % 2) * 0.25,\n dotSizeAt: (i) => Math.max(2, Math.round(size * 0.1)) + (i % 2),\n }),\n [burst, size],\n );\n\n const fadeDuration = prefersReducedMotion ? 0 : 0.2;\n\n return (\n <Box\n role=\"img\"\n aria-label={label ?? labels[status]}\n sx={{\n position: \"relative\",\n display: \"inline-flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n width: size,\n height: size,\n flexShrink: 0,\n overflow: \"visible\",\n color: base,\n }}\n >\n <AnimatePresence mode=\"wait\">\n {status === \"pending\" && (\n <motion.span\n key=\"pending\"\n initial={{ opacity: 0 }}\n animate={{ opacity: 1 }}\n exit={{ opacity: 0 }}\n transition={{ duration: fadeDuration }}\n style={{ position: \"absolute\", inset: 0 }}\n >\n <Box\n sx={{\n width: size,\n height: size,\n borderRadius: \"50%\",\n border: `${ring}px solid`,\n borderColor: \"border.base\",\n boxSizing: \"border-box\",\n }}\n />\n </motion.span>\n )}\n\n {status === \"loading\" && (\n <motion.span\n key=\"loading\"\n initial={{ opacity: 0 }}\n animate={{ opacity: 1 }}\n exit={{ opacity: 0 }}\n transition={{ duration: fadeDuration }}\n style={{\n position: \"absolute\",\n inset: 0,\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n }}\n >\n <CircularProgress\n size={size}\n thickness={thickness}\n disableShrink\n sx={{ color: base }}\n />\n </motion.span>\n )}\n\n {status === \"done\" && (\n <motion.span\n key=\"done\"\n initial={{ opacity: 0 }}\n animate={{ opacity: 1 }}\n exit={{ opacity: 0 }}\n transition={{ duration: fadeDuration }}\n style={{\n position: \"absolute\",\n inset: 0,\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n }}\n >\n <motion.div\n initial={prefersReducedMotion ? false : { scale: 0 }}\n animate={prefersReducedMotion ? {} : { scale: [0, 1.18, 1] }}\n transition={{ duration: 0.4, ease: \"easeOut\", times: [0, 0.6, 1] }}\n style={{ display: \"flex\" }}\n >\n <AnimationBadge\n size={size}\n base={base}\n contrast={contrast}\n iconSize={checkSize}\n />\n </motion.div>\n </motion.span>\n )}\n </AnimatePresence>\n\n {!prefersReducedMotion && status === \"done\" && (\n <ConfettiParticles particles={particles} variant=\"icon\" />\n )}\n </Box>\n );\n};\n","import { Box, useTheme } from \"@mui/material\";\nimport { motion, useReducedMotion } from \"motion/react\";\nimport { useMemo } from \"react\";\n\nimport {\n AnimationBadge,\n type AnimationColor,\n type AnimationSize,\n buildParticles,\n colorMap,\n ConfettiParticles,\n illustrationBadgeShadow,\n reducedMotionHidden,\n reducedMotionOverride,\n} from \"../shared\";\nimport { useAnimationLabels } from \"../use-animation-labels\";\n\ntype CheckAnimationProps = {\n size?: AnimationSize;\n color?: AnimationColor;\n /**\n * Accessible name for the illustration; defaults to the translated word for\n * \"confirmed\" in the `LeaProvider` language.\n */\n label?: string;\n};\n\n// Shared square footprint with PulseAnimation: `box` is the rendered square and\n// `badge` matches the pulse centre circle, so both animations line up at a given\n// size. The confetti is free to overflow the square.\nconst sizeMap = {\n small: { box: 90, badge: 60, icon: 30, burst: 60 },\n large: { box: 150, badge: 100, icon: 50, burst: 100 },\n};\n\nconst CONFETTI_COUNT = 14;\n\nexport const CheckAnimation = ({\n size = \"large\",\n color = \"purple\",\n label,\n}: CheckAnimationProps) => {\n const theme = useTheme();\n const prefersReducedMotion = useReducedMotion();\n const labels = useAnimationLabels();\n const { box, badge, icon, burst } = sizeMap[size];\n const { base, contrast } = colorMap[color];\n\n const confettiColors = useMemo(\n () => [\n theme.palette.purple.base,\n theme.palette.teal.base,\n theme.palette.status.info.base,\n theme.palette.status.warning.base,\n ],\n [theme],\n );\n\n const particles = useMemo(() => {\n const fallbackColour = confettiColors[0] ?? theme.palette.purple.base;\n return buildParticles({\n count: CONFETTI_COUNT,\n burst,\n distanceAt: (i) => 0.6 + (i % 3) * 0.15,\n dotSizeAt: (i) => 5 + (i % 3) * 2,\n colourAt: (i) =>\n confettiColors[i % confettiColors.length] ?? fallbackColour,\n withSpin: true,\n });\n }, [burst, confettiColors, theme.palette.purple.base]);\n\n return (\n <Box\n role=\"img\"\n aria-label={label ?? labels.confirmed}\n sx={{\n position: \"relative\",\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n width: box,\n height: box,\n overflow: \"visible\",\n }}\n >\n <Box\n component=\"span\"\n sx={{\n position: \"absolute\",\n width: badge,\n height: badge,\n borderRadius: \"50%\",\n backgroundColor: base,\n opacity: 0.25,\n animation: \"checkHalo 2.6s ease-in-out infinite\",\n \"@keyframes checkHalo\": {\n \"0%, 100%\": { transform: \"scale(1)\", opacity: 0.28 },\n \"50%\": { transform: \"scale(1.45)\", opacity: 0 },\n },\n ...reducedMotionHidden,\n }}\n />\n\n {!prefersReducedMotion && (\n <ConfettiParticles particles={particles} variant=\"illustration\" />\n )}\n\n <motion.div\n initial={prefersReducedMotion ? false : { scale: 0, rotate: -25 }}\n animate={\n prefersReducedMotion ? {} : { scale: [0, 1.12, 1], rotate: [-25, 0] }\n }\n transition={{\n duration: 0.55,\n ease: \"easeOut\",\n times: [0, 0.65, 1],\n }}\n style={{ display: \"flex\" }}\n >\n <AnimationBadge\n size={badge}\n base={base}\n contrast={contrast}\n iconSize={icon}\n boxShadow={illustrationBadgeShadow}\n sx={{\n animation: prefersReducedMotion\n ? \"none\"\n : \"checkBreathe 2.6s ease-in-out infinite\",\n \"@keyframes checkBreathe\": {\n \"0%, 100%\": { transform: \"scale(1)\" },\n \"50%\": { transform: \"scale(1.04)\" },\n },\n ...reducedMotionOverride,\n }}\n />\n </motion.div>\n </Box>\n );\n};\n","import { Box, CircularProgress } from \"@mui/material\";\n\nimport {\n type AnimationSize,\n illustrationBadgeShadow,\n reducedMotionOverride,\n} from \"../shared\";\nimport { useAnimationLabels } from \"../use-animation-labels\";\n\ntype PulseAnimationProps = {\n size?: AnimationSize;\n /**\n * Accessible name for the spinner; defaults to the translated word for\n * \"loading\" in the `LeaProvider` language. `StatusAnimation` hides the pulse\n * from assistive tech and announces its own status text instead.\n */\n label?: string;\n};\n\n// Ratios are kept constant across variants so the pulse expands the same\n// amount relative to the centre circle, and the spinner stays proportional.\nconst sizeMap = {\n small: { container: 90, circle: 60, spinner: 28 },\n large: { container: 150, circle: 100, spinner: 48 },\n};\n\nexport const PulseAnimation = ({\n size = \"large\",\n label,\n}: PulseAnimationProps) => {\n const { container, circle, spinner } = sizeMap[size];\n const labels = useAnimationLabels();\n\n return (\n <Box\n sx={{\n position: \"relative\",\n display: \"flex\",\n justifyContent: \"center\",\n alignItems: \"center\",\n width: container,\n height: container,\n }}\n >\n <PulseCircle circleSize={circle} />\n <PulseCircle circleSize={circle} delay=\"0.4s\" />\n <Box\n sx={{\n position: \"absolute\",\n width: circle,\n height: circle,\n backgroundColor: \"purple.base\",\n borderRadius: \"50%\",\n boxShadow: illustrationBadgeShadow,\n }}\n />\n <CircularProgress\n sx={{\n color: \"purple.contrast\",\n }}\n disableShrink\n size={spinner}\n aria-label={label ?? labels.loading}\n />\n </Box>\n );\n};\n\nconst PulseCircle = ({\n circleSize,\n delay = \"0s\",\n}: {\n circleSize: number;\n delay?: string;\n}) => {\n return (\n <Box\n sx={{\n position: \"absolute\",\n width: circleSize,\n height: circleSize,\n backgroundColor: \"purple.base\",\n borderRadius: \"50%\",\n animation: \"pulse 2s ease-in-out infinite\",\n animationDelay: delay,\n opacity: 0.5,\n \"@keyframes pulse\": {\n \"0%\": {\n transform: \"scale(0.4)\",\n opacity: 0.6,\n },\n \"100%\": {\n transform: \"scale(1.6)\",\n opacity: 0,\n },\n },\n ...reducedMotionOverride,\n }}\n />\n );\n};\n","import { Box } from \"@mui/material\";\nimport { AnimatePresence, motion, useReducedMotion } from \"motion/react\";\nimport { useEffect, useRef, useState } from \"react\";\n\nimport {\n type AnimationColor,\n type AnimationSize,\n visuallyHidden,\n} from \"../shared\";\nimport { useAnimationLabels } from \"../use-animation-labels\";\nimport { CheckAnimation } from \"./check-animation\";\nimport { PulseAnimation } from \"./pulse-animation\";\n\ntype StatusAnimationProps = {\n /** While `true`, shows the pulse; when it flips to `false`, transitions to the check. */\n loading: boolean;\n size?: AnimationSize;\n /** Colour of the resulting check (and its halo). */\n color?: AnimationColor;\n /**\n * Minimum time (ms) the pulse stays visible once mounted in the loading\n * state, so a very fast response doesn't make the spinner flash. The check\n * appears as soon as `loading` is `false` *and* this minimum has elapsed.\n */\n minLoadingMs?: number;\n /**\n * Visually-hidden status text announced while loading. Defaults to the\n * translated word for \"loading\" in the `LeaProvider` language.\n */\n loadingLabel?: string;\n /**\n * Visually-hidden status text announced once done. Defaults to the translated\n * word for \"done\".\n */\n doneLabel?: string;\n};\n\nconst boxSize = { small: 90, large: 150 };\n\n/**\n * A controlled loading → success indicator: shows {@link PulseAnimation} while\n * `loading`, then cross-fades into {@link CheckAnimation} (firing its one-time\n * confetti) once `loading` becomes `false`. Announces state changes politely\n * and respects `prefers-reduced-motion`.\n */\nexport const StatusAnimation = ({\n loading,\n size = \"large\",\n color = \"purple\",\n minLoadingMs = 0,\n loadingLabel,\n doneLabel,\n}: StatusAnimationProps) => {\n const prefersReducedMotion = useReducedMotion();\n const labels = useAnimationLabels();\n const [done, setDone] = useState(!loading);\n const loadingStart = useRef<number | null>(loading ? Date.now() : null);\n\n useEffect(() => {\n if (loading) {\n loadingStart.current = Date.now();\n setDone(false);\n return;\n }\n\n const elapsed =\n loadingStart.current != null\n ? Date.now() - loadingStart.current\n : minLoadingMs;\n const remaining = Math.max(0, minLoadingMs - elapsed);\n\n if (remaining === 0) {\n setDone(true);\n return;\n }\n\n const timer = window.setTimeout(() => setDone(true), remaining);\n return () => window.clearTimeout(timer);\n }, [loading, minLoadingMs]);\n\n const side = boxSize[size];\n const duration = prefersReducedMotion ? 0 : 0.35;\n\n return (\n <Box\n role=\"status\"\n aria-live=\"polite\"\n sx={{ position: \"relative\", width: side, height: side }}\n >\n <AnimatePresence mode=\"sync\">\n {done ? (\n <motion.div\n key=\"check\"\n aria-hidden\n initial={{ opacity: 0 }}\n animate={{ opacity: 1 }}\n exit={{ opacity: 0 }}\n transition={{ duration }}\n style={{\n position: \"absolute\",\n inset: 0,\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n }}\n >\n <CheckAnimation size={size} color={color} />\n </motion.div>\n ) : (\n <motion.div\n key=\"pulse\"\n aria-hidden\n initial={{ opacity: 0 }}\n animate={{ opacity: 1 }}\n exit={{ opacity: 0 }}\n transition={{ duration }}\n style={{\n position: \"absolute\",\n inset: 0,\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n }}\n >\n <PulseAnimation size={size} />\n </motion.div>\n )}\n </AnimatePresence>\n <Box component=\"span\" sx={visuallyHidden}>\n {done ? (doneLabel ?? labels.done) : (loadingLabel ?? labels.loading)}\n </Box>\n </Box>\n );\n};\n","import {\n Button as MuiButton,\n ButtonProps as MuiButtonProps,\n} from \"@mui/material\";\nimport { ArrowRight } from \"lucide-react\";\nimport { ElementType } from \"react\";\n\ntype ActionButtonProps<C extends ElementType = \"button\"> = Omit<\n MuiButtonProps<C>,\n \"variant\"\n> & {\n component?: C;\n};\n\n/**\n * A pill-shaped call-to-action button with a built-in arrow icon.\n *\n * Used for primary navigation actions on the website, such as hero sections\n * and landing pages. Supports polymorphic rendering:\n *\n * ```tsx\n * <ActionButton component={Link} to=\"/loans\">Se våra lån</ActionButton>\n * <ActionButton component={NextLink} href=\"/loans\">Se våra lån</ActionButton>\n * ```\n */\nexport const ActionButton = ({ children, ...rest }: ActionButtonProps) => (\n <MuiButton {...rest} variant=\"action\" disableElevation>\n {children}\n <ArrowRight />\n </MuiButton>\n);\n","type ClassNameProp<State> =\n | string\n | ((state: State) => string | undefined)\n | undefined;\n\n/**\n * Base UI replaces `className` wholesale, which would drop the module class of\n * a wrapper component. Returning a callback keeps the state argument working\n * for consumers who pass a function.\n *\n * Internal helper — not part of the public API, so it isn't re-exported from\n * `src/utils/index.ts`.\n */\nexport const mergeClassName =\n <State,>(base: string, className: ClassNameProp<State>) =>\n (state: State) =>\n [base, typeof className === \"function\" ? className(state) : className]\n .filter(Boolean)\n .join(\" \");\n","/*\n * Shared by Button, IconButton, CloseButton and DownloadTrigger. Design tokens\n * come from src/theme/tokens.css, so these render styled without a provider.\n *\n * Each colour sets local properties that the variants read, which keeps the\n * variant x colour matrix to one rule per cell.\n */\n\n.Button {\n --button-solid: var(--lea-palette-purple-base);\n --button-solid-hover: var(--lea-palette-purple-hover);\n --button-on-solid: var(--lea-palette-purple-contrast);\n --button-fg: var(--lea-palette-purple-base);\n --button-border: var(--lea-palette-purple-base);\n /* Translucent white, so outline and ghost hovers lighten whatever surface\n the button sits on; the hint of --button-fg keeps them visible on white. */\n --button-tint: color-mix(\n in srgb,\n var(--button-fg) calc(var(--lea-opacity-hover) * 100%),\n color-mix(\n in srgb,\n var(--lea-color-white) calc(var(--lea-opacity-highlight) * 100%),\n transparent\n )\n );\n\n --button-height: 2.75rem;\n --button-icon-size: 1.25rem;\n --button-padding-inline: calc(var(--lea-spacing) * 2.5);\n\n box-sizing: border-box;\n display: inline-flex;\n min-height: var(--button-height);\n flex-shrink: 0;\n align-items: center;\n justify-content: center;\n gap: var(--lea-spacing);\n /* Height comes from min-height, so text and icon buttons line up; this only\n pads labels that wrap onto several lines. */\n padding-block: calc(var(--lea-spacing) * 0.5);\n padding-inline: var(--button-padding-inline);\n margin: 0;\n border: 1px solid transparent;\n border-radius: var(--lea-radius-full);\n background-color: transparent;\n color: var(--button-fg);\n font-family: inherit;\n font-size: var(--lea-font-size-md);\n font-weight: var(--lea-font-weight-medium);\n line-height: 1.25;\n text-align: center;\n text-decoration: none;\n cursor: pointer;\n user-select: none;\n -webkit-tap-highlight-color: transparent;\n transition: background-color var(--lea-duration-normal)\n var(--lea-easing-standard),\n border-color var(--lea-duration-normal) var(--lea-easing-standard),\n color var(--lea-duration-normal) var(--lea-easing-standard),\n opacity var(--lea-duration-normal) var(--lea-easing-standard);\n}\n\n.Button svg {\n width: var(--button-icon-size);\n height: var(--button-icon-size);\n flex-shrink: 0;\n}\n\n.Button:focus-visible {\n outline: 2px solid var(--lea-palette-text-base);\n outline-offset: 0.125rem;\n}\n\n/* Colours */\n\n.Button[data-color=\"neutral\"] {\n --button-solid: var(--lea-palette-bg-contrast);\n --button-solid-hover: var(--lea-color-neutral-800);\n --button-on-solid: var(--lea-palette-text-contrast);\n --button-fg: var(--lea-palette-text-base);\n --button-border: var(--lea-palette-border-strong);\n}\n\n.Button[data-color=\"danger\"] {\n --button-solid: var(--lea-color-red-600);\n --button-solid-hover: var(--lea-color-red-500);\n --button-on-solid: var(--lea-palette-text-contrast);\n --button-fg: var(--lea-color-red-600);\n --button-border: var(--lea-color-red-600);\n}\n\n/* Variants */\n\n.Button[data-variant=\"solid\"] {\n background-color: var(--button-solid);\n color: var(--button-on-solid);\n}\n\n.Button[data-variant=\"outline\"] {\n border-color: var(--button-border);\n}\n\n@media (hover: hover) {\n .Button[data-variant=\"solid\"]:not([data-disabled]):hover {\n background-color: var(--button-solid-hover);\n }\n\n .Button[data-variant=\"outline\"]:not([data-disabled]):hover,\n .Button[data-variant=\"ghost\"]:not([data-disabled]):hover {\n background-color: var(--button-tint);\n }\n}\n\n/* Sizes */\n\n.Button[data-size=\"sm\"] {\n --button-height: 2.25rem;\n --button-icon-size: 1rem;\n --button-padding-inline: calc(var(--lea-spacing) * 2);\n}\n\n.Button[data-size=\"lg\"] {\n --button-height: 3.25rem;\n --button-icon-size: 1.5rem;\n --button-padding-inline: calc(var(--lea-spacing) * 2.5);\n}\n\n/* An icon carries its own visual weight, so its side needs less padding. */\n\n.Button[data-start-icon] {\n padding-inline-start: calc(var(--button-padding-inline) - var(--lea-spacing));\n}\n\n.Button[data-end-icon] {\n padding-inline-end: calc(var(--button-padding-inline) - var(--lea-spacing));\n}\n\n/* Icon-only: a square the same height as a text button of the same size. */\n\n.Button.IconButton {\n width: var(--button-height);\n height: var(--button-height);\n padding: 0;\n}\n\n/* Disabled is greyscale; loading also disables, but keeps its colour. */\n\n.Button[data-disabled]:not([data-loading]) {\n color: var(--lea-color-neutral-400);\n cursor: not-allowed;\n}\n\n.Button[data-variant=\"solid\"][data-disabled]:not([data-loading]) {\n background-color: var(--lea-color-neutral-200);\n color: var(--lea-color-neutral-600);\n}\n\n.Button[data-variant=\"outline\"][data-disabled]:not([data-loading]) {\n border-color: var(--lea-palette-border-base);\n}\n\n.Button[data-loading] {\n cursor: progress;\n opacity: 0.7;\n}\n\n.Spinner {\n box-sizing: border-box;\n display: inline-block;\n width: var(--button-icon-size);\n height: var(--button-icon-size);\n flex-shrink: 0;\n border: 2px solid currentColor;\n border-inline-end-color: transparent;\n border-radius: var(--lea-radius-full);\n animation: button-spin 0.8s linear infinite;\n}\n\n@keyframes button-spin {\n to {\n rotate: 360deg;\n }\n}\n\n.SrOnly {\n position: absolute;\n width: 1px;\n height: 1px;\n padding: 0;\n margin: -1px;\n overflow: hidden;\n clip-path: inset(50%);\n white-space: nowrap;\n border: 0;\n}\n\n@media (prefers-reduced-motion: reduce) {\n .Button {\n transition-duration: 0.01ms;\n }\n\n .Spinner {\n animation: none;\n }\n}\n","\"use client\";\n\nimport { Button as BaseButton } from \"@base-ui/react/button\";\nimport { useRender } from \"@base-ui/react/use-render\";\nimport {\n forwardRef,\n isValidElement,\n type MouseEvent,\n type ReactElement,\n} from \"react\";\n\nimport { mergeClassName } from \"../../utils/merge-class-name\";\nimport styles from \"./button.module.css\";\n\nexport type ButtonVariant = \"solid\" | \"outline\" | \"ghost\";\nexport type ButtonColor = \"accent\" | \"neutral\" | \"danger\";\nexport type ButtonSize = \"sm\" | \"md\" | \"lg\";\n\nexport type ButtonBaseProps = Omit<BaseButton.Props, \"color\"> & {\n /**\n * Visual weight.\n * - `\"solid\"` — filled, for the main action.\n * - `\"outline\"` — bordered, no fill.\n * - `\"ghost\"` — no border or fill until hovered.\n * @default \"solid\"\n */\n variant?: ButtonVariant;\n /**\n * Colour scheme. `\"danger\"` is for destructive actions.\n * @default \"accent\"\n */\n color?: ButtonColor;\n /**\n * @default \"md\"\n */\n size?: ButtonSize;\n /**\n * Shows the busy state: the button is disabled, keeps its colour at reduced\n * opacity and sets `aria-busy`.\n * @default false\n */\n loading?: boolean;\n};\n\n/**\n * A `render` element carrying `href` (an `<a>`, Next.js `Link`) or `to`\n * (React Router `Link`) is a link. Base UI's `Button` would give it\n * `role=\"button\"`, so links are rendered without button semantics.\n */\nconst isLinkElement = (\n render: ButtonBaseProps[\"render\"],\n): render is ReactElement<{ href?: unknown; to?: unknown }> =>\n isValidElement<{ href?: unknown; to?: unknown }>(render) &&\n (render.props.href != null || render.props.to != null);\n\nconst preventDefault = (event: MouseEvent) => event.preventDefault();\n\n/**\n * The root shared by `Button`, `IconButton`, `CloseButton` and\n * `DownloadTrigger`. Internal — not exported from the package.\n */\nexport const ButtonBase = forwardRef<HTMLElement, ButtonBaseProps>(\n function ButtonBase(\n {\n variant = \"solid\",\n color = \"accent\",\n size = \"md\",\n loading = false,\n disabled,\n className,\n render,\n nativeButton,\n focusableWhenDisabled,\n ...rest\n },\n ref,\n ) {\n const isDisabled = Boolean(disabled || loading);\n const isLink = isLinkElement(render);\n\n const shared = {\n \"aria-busy\": loading || undefined,\n \"data-variant\": variant,\n \"data-color\": color,\n \"data-size\": size,\n \"data-loading\": loading || undefined,\n };\n\n const link = useRender({\n enabled: isLink,\n render: isLink ? render : undefined,\n ref,\n defaultTagName: \"a\",\n props: {\n ...rest,\n ...shared,\n \"aria-disabled\": isDisabled || undefined,\n \"data-disabled\": isDisabled ? \"\" : undefined,\n className: mergeClassName(styles.Button, className)({\n disabled: isDisabled,\n }),\n onClick: isDisabled ? preventDefault : rest.onClick,\n },\n });\n\n if (link) return link;\n\n return (\n <BaseButton\n {...rest}\n {...shared}\n ref={ref}\n render={render}\n nativeButton={nativeButton}\n focusableWhenDisabled={focusableWhenDisabled}\n disabled={isDisabled}\n className={mergeClassName(styles.Button, className)}\n />\n );\n },\n);\n","\"use client\";\n\nimport { forwardRef, type ReactNode } from \"react\";\n\nimport { ButtonBase, type ButtonBaseProps } from \"./button-base\";\nimport styles from \"./button.module.css\";\n\nexport type {\n ButtonColor,\n ButtonSize,\n ButtonVariant,\n} from \"./button-base\";\n\nexport type ButtonProps = ButtonBaseProps & {\n /** Icon before the label. Replaced by the spinner while `loading`. */\n startIcon?: ReactNode;\n /** Icon after the label. */\n endIcon?: ReactNode;\n /**\n * Text announced to screen readers while `loading`, through a\n * visually-hidden `role=\"status\"` region, e.g. \"Saving…\".\n */\n loadingLabel?: string;\n};\n\n/**\n * A button built on Base UI's `Button` primitive and styled with Lea's design\n * tokens. Pick a `variant` (`solid`, `outline`, `ghost`), a `color`\n * (`accent`, `neutral`, `danger`) and a `size` (`sm`, `md`, `lg`).\n *\n * ```tsx\n * <Button variant=\"outline\" startIcon={<Plus aria-hidden />}>Add</Button>\n * ```\n *\n * To render a link that looks like a button, pass the link through `render`.\n * An element with `href` or `to` is rendered as a real link, without button\n * semantics:\n *\n * ```tsx\n * <Button render={<a href=\"/about\" />}>About</Button>\n * <Button render={<NextLink href=\"/about\" />}>About</Button>\n * <Button render={<RouterLink to=\"/about\" />}>About</Button>\n * ```\n *\n * For a link inside running text, use `Link` instead.\n */\nexport const Button = forwardRef<HTMLElement, ButtonProps>(function Button(\n { startIcon, endIcon, loading = false, loadingLabel, children, ...rest },\n ref,\n) {\n return (\n <>\n <ButtonBase\n {...rest}\n ref={ref}\n loading={loading}\n data-start-icon={loading || startIcon != null || undefined}\n data-end-icon={endIcon != null || undefined}\n >\n {loading ? <span className={styles.Spinner} aria-hidden /> : startIcon}\n {children}\n {endIcon}\n </ButtonBase>\n {loadingLabel != null && (\n <span role=\"status\" className={styles.SrOnly}>\n {loading ? loadingLabel : null}\n </span>\n )}\n </>\n );\n});\n","import { createTranslation } from \"../../i18n\";\n\n/**\n * Translated accessible name for the close (X) button shared by the feedback\n * overlays (`SimpleDialog`, `SimpleDrawer`). Consumers can override per-instance\n * via a `closeLabel` prop.\n */\nexport const useCloseLabel = createTranslation({\n close: {\n no: \"Lukk\",\n se: \"Stäng\",\n fi: \"Sulje\",\n es: \"Cerrar\",\n },\n});\n","\"use client\";\n\nimport { forwardRef, type ReactNode } from \"react\";\n\nimport { mergeClassName } from \"../../utils/merge-class-name\";\nimport { ButtonBase, type ButtonBaseProps } from \"./button-base\";\nimport styles from \"./button.module.css\";\n\n/**\n * Requires an accessible name so the button is never nameless. Provide exactly\n * one of `aria-label` or `aria-labelledby`.\n */\ntype IconButtonAccessibleName =\n | { \"aria-label\": string; \"aria-labelledby\"?: never }\n | { \"aria-labelledby\": string; \"aria-label\"?: never };\n\nexport type IconButtonProps = Omit<\n ButtonBaseProps,\n \"children\" | \"aria-label\" | \"aria-labelledby\"\n> &\n IconButtonAccessibleName & {\n /** The icon. Mark it `aria-hidden` — the name comes from `aria-label`. */\n children: ReactNode;\n };\n\n/**\n * A square, icon-only button with the same variants, colours and sizes as\n * `Button`. Because it has no visible text, TypeScript requires an\n * `aria-label` or `aria-labelledby`.\n *\n * ```tsx\n * <IconButton aria-label=\"Add\" variant=\"outline\">\n * <Plus aria-hidden />\n * </IconButton>\n * ```\n */\nexport const IconButton = forwardRef<HTMLElement, IconButtonProps>(\n function IconButton({ loading = false, className, children, ...rest }, ref) {\n return (\n <ButtonBase\n {...rest}\n ref={ref}\n loading={loading}\n className={mergeClassName(styles.IconButton, className)}\n >\n {loading ? <span className={styles.Spinner} aria-hidden /> : children}\n </ButtonBase>\n );\n },\n);\n","\"use client\";\n\nimport { X } from \"lucide-react\";\nimport { forwardRef } from \"react\";\n\nimport { useCloseLabel } from \"../feedback/use-close-label\";\nimport type { ButtonBaseProps } from \"./button-base\";\nimport { IconButton } from \"./icon-button\";\n\nexport type CloseButtonProps = Omit<\n ButtonBaseProps,\n \"children\" | \"aria-label\" | \"aria-labelledby\"\n> & {\n /** Accessible name. Defaults to a translated \"Close\". */\n label?: string;\n};\n\n/**\n * An `IconButton` with a built-in X icon. It always has an accessible name —\n * a translated \"Close\" unless you pass `label`.\n *\n * ```tsx\n * <CloseButton onClick={() => setOpen(false)} />\n * ```\n */\nexport const CloseButton = forwardRef<HTMLElement, CloseButtonProps>(\n function CloseButton(\n { label, variant = \"ghost\", color = \"neutral\", ...rest },\n ref,\n ) {\n const t = useCloseLabel();\n\n return (\n <IconButton\n {...rest}\n ref={ref}\n variant={variant}\n color={color}\n aria-label={label ?? t.close}\n >\n <X aria-hidden />\n </IconButton>\n );\n },\n);\n","export type DownloadableData =\n | string\n | Blob\n | File\n | ArrayBuffer\n | Uint8Array;\n\nexport type DownloadDataSource =\n | DownloadableData\n | (() => DownloadableData | Promise<DownloadableData>);\n\nexport async function resolveDownloadData(\n data: DownloadDataSource,\n): Promise<DownloadableData> {\n return typeof data === \"function\" ? data() : data;\n}\n\nexport function downloadFile(\n data: DownloadableData,\n fileName: string,\n mimeType?: string,\n): void {\n const blob =\n data instanceof Blob\n ? data\n : new Blob([data as BlobPart], mimeType ? { type: mimeType } : undefined);\n\n const url = URL.createObjectURL(blob);\n const anchor = document.createElement(\"a\");\n anchor.href = url;\n anchor.download = fileName;\n anchor.rel = \"noopener\";\n anchor.click();\n URL.revokeObjectURL(url);\n}\n","import { createTranslation } from \"../../i18n\";\n\n/**\n * Translated default copy for `DownloadTrigger`. Consumers can override it by\n * passing `children`.\n */\nexport const useDownloadLabels = createTranslation({\n download: {\n no: \"Last ned\",\n se: \"Ladda ner\",\n fi: \"Lataa\",\n es: \"Descargar\",\n },\n});\n","\"use client\";\n\nimport {\n downloadFile,\n resolveDownloadData,\n type DownloadDataSource,\n} from \"@/utils/downloadFile\";\nimport { useState } from \"react\";\n\nimport { Button, type ButtonProps } from \"./button\";\nimport { useDownloadLabels } from \"./use-download-labels\";\n\ntype DownloadTriggerProps = Omit<ButtonProps, \"onClick\"> & {\n /** File contents, or a function/promise that resolves to them. */\n data: DownloadDataSource;\n /** File name. */\n fileName: string;\n /** MIME type. */\n mimeType?: string;\n /** Callback for when the download starts. */\n onDownload?: () => void;\n /** Callback for when the download fails. */\n onDownloadError?: (error: unknown) => void;\n};\n\n/**\n * A button that triggers a download of a file. Shares `Button`'s variants,\n * colours and sizes, and shows the loading state while `data` resolves.\n *\n * Without `children` the label is the translated word for \"download\" in the\n * `LeaProvider` language.\n */\n\nexport const DownloadTrigger = ({\n data,\n fileName,\n mimeType,\n onDownload,\n onDownloadError,\n loading: loadingProp,\n children,\n ...rest\n}: DownloadTriggerProps) => {\n const labels = useDownloadLabels();\n const [pending, setPending] = useState(false);\n const loading = loadingProp ?? pending;\n\n const handleClick = async () => {\n setPending(true);\n try {\n const resolved = await resolveDownloadData(data);\n downloadFile(resolved, fileName, mimeType);\n onDownload?.();\n } catch (error) {\n onDownloadError?.(error);\n } finally {\n setPending(false);\n }\n };\n\n return (\n <Button {...rest} loading={loading} onClick={handleClick}>\n {children ?? labels.download}\n </Button>\n );\n};\n","/**\n * Viewport widths in pixels where layouts may change. Mobile-first: each value\n * is the `min-width` at which the breakpoint starts. The values match MUI's\n * defaults, so the MUI wrappers and the CSS Modules switch at the same widths.\n *\n * CSS custom properties can't be used in `@media`, so CSS Modules write the\n * pixel value literally; tests/tokens.test.ts checks it against this scale.\n */\nexport const breakpoints = {\n xs: 0,\n sm: 600,\n md: 900,\n lg: 1200,\n xl: 1536,\n} as const;\n\nexport type Breakpoint = keyof typeof breakpoints;\n","export const colors = {\n purple: {\n 50: \"#FAF7FB\",\n 100: \"#E2D8E4\",\n 200: \"#C5B1CA\",\n 300: \"#C29AC2\",\n 400: \"#9E6DA8\",\n 500: \"#855888\",\n 600: \"#70427B\",\n 700: \"#5A3463\",\n 800: \"#422349\",\n 900: \"#2E1834\",\n 950: \"#1A0E1E\",\n },\n teal: {\n 50: \"#F0FCFA\",\n 100: \"#DAF6F1\",\n 200: \"#CEF3ED\",\n 300: \"#08C2A7\",\n 400: \"#46D1BD\",\n 500: \"#06A892\",\n 600: \"#058F7D\",\n 700: \"#047568\",\n 800: \"#035C53\",\n 900: \"#02433E\",\n 950: \"#012A28\",\n },\n blue: {\n 50: \"#EFF6FF\",\n 100: \"#CBE5FD\",\n 200: \"#93CBFC\",\n 300: \"#4DA8F7\",\n 400: \"#057EF2\",\n 500: \"#0468C9\",\n 600: \"#0354A3\",\n 700: \"#02417D\",\n 800: \"#012E57\",\n 900: \"#011B31\",\n 950: \"#000E19\",\n },\n orange: {\n 50: \"#FFF5F2\",\n 100: \"#FFDFD7\",\n 200: \"#FFC4B5\",\n 300: \"#FF9E87\",\n 400: \"#FE653E\",\n 500: \"#E54E28\",\n 600: \"#C43E1C\",\n 700: \"#A33218\",\n 800: \"#822814\",\n 900: \"#611E0F\",\n 950: \"#401408\",\n },\n red: {\n 50: \"#FEF2F2\",\n 100: \"#FCDCDC\",\n 200: \"#F9BBBB\",\n 300: \"#F28888\",\n 400: \"#E85555\",\n 500: \"#D32F2F\",\n 600: \"#AD2121\",\n 700: \"#8A1919\",\n 800: \"#6F1313\",\n 900: \"#4D0E0E\",\n 950: \"#2E0808\",\n },\n beige: {\n 50: \"#FAF7F5\",\n 100: \"#F0E9E5\",\n 200: \"#E0D4CD\",\n 300: \"#C9B8AD\",\n 400: \"#B09A8C\",\n 500: \"#977C6B\",\n 600: \"#7E6556\",\n 700: \"#654F42\",\n 800: \"#4C3A32\",\n 900: \"#332722\",\n 950: \"#1A1411\",\n },\n neutral: {\n 50: \"#F7F7F6\",\n 100: \"#EBEBEB\",\n 200: \"#DBDBDB\",\n 300: \"#C4C4C4\",\n 400: \"#A2A2A2\",\n 500: \"#757575\",\n 600: \"#5E5E5E\",\n 700: \"#454545\",\n 800: \"#2E2E2E\",\n 900: \"#1A1A1A\",\n 950: \"#0F1010\",\n },\n white: \"#FFFFFF\",\n black: \"#0F1010\",\n} as const;\n","export const fontSizes = {\n xs: \"0.75rem\",\n sm: \"0.875rem\",\n md: \"1rem\",\n lg: \"1.25rem\",\n xl: \"1.5rem\",\n \"2xl\": \"2rem\",\n \"3xl\": \"2.5rem\",\n \"4xl\": \"3rem\",\n \"5xl\": \"3.5rem\",\n \"6xl\": \"4rem\",\n} as const;\n","export const fontWeights = {\n thin: 200,\n light: 300,\n regular: 400,\n medium: 500,\n semibold: 600,\n bold: 700,\n black: 800,\n} as const;\n","import { Palette } from \"../types\";\nimport { colors } from \"./colors\";\n\nconst { purple, teal, blue, orange, red, neutral, white, beige } = colors;\n\nexport const palette: Palette = {\n bg: {\n base: white,\n subtle: neutral[50],\n muted: beige[100],\n contrast: neutral[950],\n accent: purple[100],\n },\n text: {\n base: neutral[950],\n subtle: neutral[500],\n muted: neutral[400],\n accent: purple[600],\n contrast: white,\n },\n border: {\n base: neutral[200],\n subtle: neutral[100],\n strong: neutral[950],\n accent: purple[600],\n contrast: white,\n },\n primary: {\n main: purple[600],\n dark: purple[700],\n light: purple[100],\n contrastText: white,\n },\n purple: {\n base: purple[600],\n hover: purple[700],\n subtle: purple[100],\n contrast: white,\n },\n teal: {\n base: teal[300],\n hover: teal[400],\n subtle: teal[100],\n contrast: white,\n },\n secondary: {\n main: teal[300],\n dark: teal[400],\n light: teal[100],\n contrastText: white,\n },\n status: {\n error: {\n base: red[500],\n subtle: red[100],\n },\n warning: {\n base: orange[400],\n subtle: orange[100],\n },\n info: {\n base: blue[400],\n subtle: blue[100],\n },\n success: {\n base: teal[400],\n subtle: teal[100],\n },\n },\n} as const;\n","export const shadows = {\n xs: \"0 1px 2px 0 rgb(0 0 0 / 0.05)\",\n sm: \"0px 1px 3px 0px rgba(0, 0, 0, 0.10), 0px 1px 2px -1px rgba(0, 0, 0, 0.10)\",\n md: \"0px 4px 6px -1px rgba(0, 0, 0, 0.10), 0px 2px 4px -2px rgba(0, 0, 0, 0.10)\",\n lg: \"0px 10px 15px -3px rgba(0, 0, 0, 0.10), 0px 4px 6px -4px rgba(0, 0, 0, 0.10)\",\n xl: \"0px 20px 25px -5px rgba(0, 0, 0, 0.10), 0px 8px 10px -6px rgba(0, 0, 0, 0.10)\",\n \"2xl\": \"0px 25px 50px -12px rgba(0, 0, 0, 0.25)\",\n inner: \"0px 2px 4px 0px rgba(0, 0, 0, 0.05) inset\",\n} as const;\n","export const shape = {\n sm: 4,\n md: 5,\n lg: 6,\n xl: 8,\n \"2xl\": 10,\n \"3xl\": 12,\n \"4xl\": 16,\n \"5xl\": 32,\n huge: 64,\n full: 100,\n} as const;\n","const BASE = 8;\nconst ROOT_FONT_SIZE = 16;\n\nexport const spacing = (factor: number) =>\n `${(factor * BASE) / ROOT_FONT_SIZE}rem`;\n","export const easings = {\n standard: \"ease-in-out\",\n spring: \"cubic-bezier(0.34, 1.56, 0.64, 1)\",\n} as const;\n\nexport const durations = {\n fast: \"0.15s\",\n normal: \"0.2s\",\n emphasis: \"0.3s\",\n} as const;\n\nexport const transition = (\n properties: string[],\n duration: string = durations.normal,\n easing: string = easings.standard,\n) => properties.map((p) => `${p} ${duration} ${easing}`).join(\", \");\n","import { fontSizes } from \"./font-sizes\";\nimport { fontWeights } from \"./font-weights\";\nimport { palette } from \"./palette\";\n\nconst fontFamily = \"'ClashGrotesk', sans-serif\";\n\n/**\n *\n * We are not following the MUI typography tokens because\n * sometimes we need the size of an h1 but not the h1 component.\n * Overriding it here at the root will give us more control over the typography.\n *\n */\n\nexport const typography = {\n fontFamily: fontFamily,\n fontWeight: fontWeights.regular,\n color: palette.text.base,\n \"& strong\": {\n fontWeight: fontWeights.medium,\n },\n \"& a\": {\n color: `${palette.text.base} !important`,\n textDecorationColor: `${palette.text.base} !important`,\n fontWeight: fontWeights.regular,\n },\n h1: undefined,\n h2: undefined,\n h3: undefined,\n h4: undefined,\n h5: undefined,\n h6: undefined,\n subtitle1: undefined,\n subtitle2: undefined,\n heading: {\n fontFamily: fontFamily,\n fontWeight: fontWeights.medium,\n letterSpacing: \"0.02em\",\n },\n body1: {\n fontSize: fontSizes.md,\n fontWeight: fontWeights.regular,\n },\n body2: {\n fontSize: fontSizes.sm,\n fontWeight: fontWeights.regular,\n },\n button: undefined,\n caption: undefined,\n};\n","import { colors, palette } from \"@/theme/tokens\";\nimport { Link as MuiLink, LinkProps as MuiLinkProps } from \"@mui/material\";\nimport { ElementType } from \"react\";\n\ntype LinkColor = \"black\" | \"purple\" | \"teal\" | \"white\";\n\nconst linkColors: Record<LinkColor, string> = {\n black: palette.text.base,\n purple: colors.purple[700],\n teal: colors.teal[700],\n white: palette.text.contrast,\n};\n\ntype LinkProps<C extends ElementType = \"a\"> = Omit<MuiLinkProps<C>, \"color\"> & {\n /** The component to render the link as. */\n component?: C;\n /** The colour of the link. */\n color?: LinkColor;\n};\n\n/**\n * A link component — link-only in styling and behaviour.\n *\n * Supports polymorphic rendering via the `component` prop, which enables\n * type-safe usage with any router link component:\n *\n * ```tsx\n * <Link href=\"/about\">About</Link> // Plain anchor\n * <Link component={RouterLink} to=\"/about\">About</Link> // React Router\n * <Link component={NextLink} href=\"/about\">About</Link> // Next.js\n * ```\n */\nexport const Link = <C extends ElementType = \"a\">({\n color = \"black\",\n children,\n sx,\n ...rest\n}: LinkProps<C>) => {\n return (\n <MuiLink\n {...rest}\n sx={[{ color: linkColors[color] }, ...(Array.isArray(sx) ? sx : [sx])]}\n >\n {children}\n </MuiLink>\n );\n};\n","import { Box, type SxProps, type Theme, styled } from \"@mui/material\";\nimport { type ReactNode, createContext, useContext } from \"react\";\nimport { Text } from \".\";\n/**\n * List is a composition component for rendering ordered or unordered lists.\n *\n * `List.Root` renders the wrapping `<ul>` (default) or `<ol>` element via the\n * `variant` prop. Each `List.Item` shows a marker: a dot for `ul`, an\n * auto-incrementing number for `ol`, or a custom icon when one is passed.\n *\n * @example Unordered list with default dots\n * <List.Root>\n * <List.Item>Fast response</List.Item>\n * <List.Item>Account data report</List.Item>\n * </List.Root>\n *\n * @example Ordered list with auto-numbering\n * <List.Root variant=\"ol\">\n * <List.Item>First step</List.Item>\n * <List.Item>Second step</List.Item>\n * </List.Root>\n *\n * @example Per-item icon marker\n * <List.Root>\n * <List.Item icon={<CircleCheck size={20} />}>Verified</List.Item>\n * </List.Root>\n */\n\ntype ListVariant = \"ul\" | \"ol\";\n\ninterface ListContextValue {\n variant: ListVariant;\n}\n\nconst ListContext = createContext<ListContextValue | null>(null);\n\nconst useListContext = () => {\n const context = useContext(ListContext);\n if (!context) {\n throw new Error(\"List parts must be used within <List.Root>\");\n }\n return context;\n};\n\ninterface RootProps {\n /** The type of list to render. */\n variant?: ListVariant;\n /** The content of the list. */\n children: ReactNode;\n /** The style of the list. */\n sx?: SxProps<Theme>;\n /** The class name of the list. */\n className?: string;\n /** The gap between the list items. */\n gap?: number;\n}\n\nexport const Root = ({\n variant = \"ul\",\n children,\n sx,\n gap = 1.5,\n ...rest\n}: RootProps) => (\n <ListContext.Provider value={{ variant }}>\n <Box\n component={variant}\n sx={[\n {\n margin: 0,\n padding: 0,\n listStyle: \"none\",\n display: \"flex\",\n flexDirection: \"column\",\n gap,\n counterReset: \"list-counter\",\n },\n ...(Array.isArray(sx) ? sx : [sx]),\n ]}\n {...rest}\n >\n {children}\n </Box>\n </ListContext.Provider>\n);\n\nconst Marker = styled(Box)({\n flexShrink: 0,\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n minWidth: 24,\n height: 24,\n});\n\nconst NumberMarker = styled(Marker)(({ theme }) => ({\n color: theme.palette.text.base,\n fontWeight: 600,\n fontSize: \"1rem\",\n lineHeight: 1,\n \"&::before\": {\n content: 'counter(list-counter) \".\"',\n },\n}));\n\nconst DotMarker = styled(Marker)(({ theme }) => ({\n \"&::before\": {\n content: '\"\"',\n width: 6,\n height: 6,\n borderRadius: \"50%\",\n backgroundColor: theme.palette.text.base,\n },\n}));\n\ninterface ItemProps {\n /** Custom marker rendered in place of the default dot/number. */\n icon?: ReactNode;\n /** The content of the list item. */\n children: ReactNode;\n /** The style of the list item. */\n sx?: SxProps<Theme>;\n /** The class name of the list item. */\n className?: string;\n /** The gap between the list items. */\n gap?: number;\n}\n\nexport const Item = ({ icon, children, sx, gap = 1.5, ...rest }: ItemProps) => {\n const { variant } = useListContext();\n\n const renderMarker = () => {\n if (icon) {\n return <Marker>{icon}</Marker>;\n }\n return variant === \"ol\" ? <NumberMarker /> : <DotMarker />;\n };\n\n return (\n <Box\n component=\"li\"\n sx={[\n {\n display: \"flex\",\n alignItems: \"flex-start\",\n gap: icon ? gap : 0,\n counterIncrement: \"list-counter\",\n },\n ...(Array.isArray(sx) ? sx : [sx]),\n ]}\n {...rest}\n >\n {renderMarker()}\n <Box sx={{ flex: 1, minWidth: 0 }}>\n {typeof children === \"string\" ? (\n <Text variant=\"body1\">{children}</Text>\n ) : (\n children\n )}\n </Box>\n </Box>\n );\n};\n","import { fontSizes, fontWeights } from \"@/theme/tokens\";\nimport {\n Typography as MuiTypography,\n TypographyProps,\n type SxProps,\n type Theme,\n} from \"@mui/material\";\n\ntype FontSizeToken = keyof typeof fontSizes;\ntype FontWeightToken = keyof typeof fontWeights;\n\ntype TextProps = TypographyProps & {\n fontWeight?: FontWeightToken;\n component?: string;\n fontSize?: FontSizeToken;\n};\n\n// MUI shorthand palette colours that resolve to their `.main` shade. The system\n// `sx` resolver would otherwise return the whole palette object for these keys.\nconst SIMPLE_PALETTE_COLORS = new Set([\n \"primary\",\n \"secondary\",\n \"error\",\n \"warning\",\n \"info\",\n \"success\",\n]);\n\n/**\n * A token-aware wrapper around MUI `Typography`. The `fontSize` and\n * `fontWeight` props accept Lea design tokens (resolved to their underlying\n * values). `color` is applied through `sx`, so design-token palette paths\n * (`text.base`, `purple.subtle`, …) and raw CSS colours work, and the MUI\n * shorthands (`primary`, `error`, …) still map to their `.main` shade.\n */\nexport const Text = ({\n children,\n fontSize,\n fontWeight,\n component = \"p\",\n color = \"text.base\",\n sx,\n ...props\n}: TextProps) => {\n const resolvedFontSize =\n typeof fontSize === \"string\" && fontSize in fontSizes\n ? fontSizes[fontSize as FontSizeToken]\n : fontSize;\n\n const resolvedFontWeight =\n typeof fontWeight === \"string\" && fontWeight in fontWeights\n ? fontWeights[fontWeight as FontWeightToken]\n : fontWeight;\n\n const resolvedColor =\n typeof color === \"string\" && SIMPLE_PALETTE_COLORS.has(color)\n ? `${color}.main`\n : color;\n\n const mergedSx: SxProps<Theme> = [\n {\n color: resolvedColor,\n fontWeight: resolvedFontWeight,\n fontSize: resolvedFontSize,\n },\n ...(Array.isArray(sx) ? sx : [sx]),\n ];\n\n return (\n <MuiTypography {...props} component={component} sx={mergedSx}>\n {children}\n </MuiTypography>\n );\n};\n","import { Box, type BoxProps } from \"@mui/material\";\nimport { ReactNode } from \"react\";\nimport { Text } from \"../typography\";\n\nexport type DataFieldProps = Omit<BoxProps, \"children\"> & {\n label: ReactNode;\n value: ReactNode;\n divider?: boolean;\n};\n\nconst renderLabel = (content: ReactNode) =>\n typeof content === \"string\" || typeof content === \"number\" ? (\n <Text component=\"span\" variant=\"body1\" color=\"text.subtle\">\n {content}\n </Text>\n ) : (\n content\n );\n\nconst renderValue = (content: ReactNode) =>\n typeof content === \"string\" || typeof content === \"number\" ? (\n <Text\n component=\"span\"\n variant=\"body1\"\n color=\"text.base\"\n fontWeight=\"medium\"\n >\n {content}\n </Text>\n ) : (\n content\n );\n\n/**\n * A single label/value row for presenting read-only details, with an optional\n * bottom divider so several fields can be stacked into a summary list.\n */\nexport const DataField = ({\n label,\n value,\n divider = true,\n sx,\n ...rest\n}: DataFieldProps) => (\n <Box\n {...rest}\n sx={[\n {\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"space-between\",\n gap: 2,\n px: 1,\n py: 1.75,\n borderBottom: divider ? \"1px solid\" : \"none\",\n borderColor: \"border.base\",\n width: \"100%\",\n },\n ...(Array.isArray(sx) ? sx : [sx]),\n ]}\n >\n <Box sx={{ minWidth: 0, flex: 1 }}>{renderLabel(label)}</Box>\n <Box sx={{ minWidth: 0, textAlign: \"right\" }}>{renderValue(value)}</Box>\n </Box>\n);\n","import { Card as MuiCard, CardProps as MuiCardProps } from \"@mui/material\";\n\n/**\n * A surface container that wraps MUI `Card` with Lea's design tokens for\n * radius, elevation, and colours. Use it to group related content on a page.\n */\nexport const Card = ({ ...props }: MuiCardProps) => {\n return <MuiCard {...props} />;\n};\n","import { createTranslation } from \"../../i18n\";\n\n/**\n * Translated accessible name for `Chip`'s delete affordance, which MUI renders\n * as an unlabelled icon. Consumers can override it by passing their own\n * `deleteIcon`.\n */\nexport const useChipLabels = createTranslation({\n remove: { no: \"Fjern\", se: \"Ta bort\", fi: \"Poista\", es: \"Eliminar\" },\n});\n","import {\n Chip as MuiChip,\n ChipProps as MuiChipProps,\n SvgIcon,\n type SvgIconProps,\n} from \"@mui/material\";\nimport { useChipLabels } from \"./use-chip-labels\";\n\nexport type ChipProps = MuiChipProps;\n\n// MUI's own delete glyph, redrawn here so it can carry an accessible name\n// (`titleAccess`); the default it renders internally has none. Chip clones this\n// element to attach its `className` and delete handler, so both are forwarded.\nconst DeleteIcon = ({ title, ...rest }: SvgIconProps & { title: string }) => (\n <SvgIcon titleAccess={title} {...rest}>\n <path d=\"M12 2C6.47 2 2 6.47 2 12s4.47 10 10 10 10-4.47 10-10S17.53 2 12 2zm5 13.59L15.59 17 12 13.41 8.41 17 7 15.59 10.59 12 7 8.41 8.41 7 12 10.59 15.59 7 17 8.41 13.41 12 17 15.59z\" />\n </SvgIcon>\n);\n\n/**\n * A compact label for tags, statuses, or filter selections, styled with Lea's\n * design tokens on top of MUI `Chip`.\n *\n * With `onDelete`, the delete affordance is named in the `LeaProvider` language\n * and includes the chip's own label, so a row of chips reads unambiguously.\n * Pass `deleteIcon` to supply a different glyph and name.\n */\nexport const Chip = ({ label, onDelete, deleteIcon, ...rest }: ChipProps) => {\n const labels = useChipLabels();\n\n const deleteName =\n typeof label === \"string\" ? `${labels.remove} ${label}` : labels.remove;\n\n return (\n <MuiChip\n label={label}\n onDelete={onDelete}\n deleteIcon={deleteIcon ?? <DeleteIcon title={deleteName} />}\n {...rest}\n />\n );\n};\n","import { Components, Theme } from \"@mui/material\";\nimport {\n durations,\n easings,\n fontSizes,\n fontWeights,\n palette,\n shadows,\n shape,\n spacing,\n transition,\n} from \"../tokens\";\n\nexport type TooltipTriggerVariant = \"icon\" | \"filled\" | \"outlined\";\nexport type TooltipSurfaceVariant = \"light\" | \"dark\";\n\nexport const tooltipSurfaceStyles = (variant: TooltipSurfaceVariant) => {\n if (variant === \"dark\") {\n return {\n backgroundColor: palette.text.base,\n color: palette.text.contrast,\n boxShadow: shadows.md,\n };\n }\n\n return {\n backgroundColor: palette.bg.base,\n color: palette.text.base,\n boxShadow: shadows.md,\n };\n};\n\nexport const tooltipSurfaceSx = (variant: TooltipSurfaceVariant) =>\n tooltipSurfaceStyles(variant);\n\nexport const tooltipTriggerSx = (variant: TooltipTriggerVariant) => ({\n display: \"inline-flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n boxSizing: \"border-box\",\n width: spacing(5.5),\n height: spacing(5.5),\n margin: spacing(-1.75),\n border: 0,\n backgroundColor: \"transparent\",\n cursor: \"pointer\",\n lineHeight: 0,\n color:\n variant === \"filled\"\n ? palette.primary.contrastText\n : variant === \"outlined\"\n ? palette.text.base\n : palette.primary.main,\n transition: transition(\n [\"background-color\", \"color\", \"border-color\"],\n durations.fast,\n easings.standard,\n ),\n \"&:hover\": {\n color:\n variant === \"filled\"\n ? palette.primary.contrastText\n : variant === \"outlined\"\n ? palette.primary.main\n : palette.primary.dark,\n },\n \"&:focus-visible\": {\n outline: `${spacing(0.25)} solid ${palette.primary.main}`,\n outlineOffset: spacing(0.25),\n borderRadius: shape.full,\n },\n});\n\nexport const tooltipIconMarkSx = (variant: TooltipTriggerVariant) => {\n const base = {\n display: \"inline-flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n position: \"relative\",\n flexShrink: 0,\n boxSizing: \"border-box\",\n \"&::before\": {\n content: '\"\"',\n position: \"absolute\",\n width: spacing(0.25),\n height: spacing(0.625),\n borderRadius: shape.full,\n backgroundColor: \"currentColor\",\n left: \"50%\",\n top: \"50%\",\n transform: \"translate(-50%, -8%)\",\n },\n \"&::after\": {\n content: '\"\"',\n position: \"absolute\",\n width: spacing(0.25),\n height: spacing(0.25),\n borderRadius: shape.full,\n backgroundColor: \"currentColor\",\n left: \"50%\",\n top: \"50%\",\n transform: \"translate(-50%, -190%)\",\n },\n } as const;\n\n if (variant === \"filled\") {\n return {\n ...base,\n width: spacing(2),\n height: spacing(2),\n borderRadius: shape.full,\n backgroundColor: palette.primary.main,\n color: palette.primary.contrastText,\n \"&:hover\": {\n backgroundColor: palette.primary.dark,\n },\n };\n }\n\n if (variant === \"outlined\") {\n return {\n ...base,\n width: spacing(2.25),\n height: spacing(2.25),\n borderRadius: shape.full,\n border: `${spacing(0.125)} solid ${palette.border.strong}`,\n backgroundColor: palette.bg.base,\n color: palette.text.base,\n };\n }\n\n return {\n ...base,\n width: spacing(2),\n height: spacing(2),\n borderRadius: shape.full,\n border: `${spacing(0.125)} solid ${palette.primary.main}`,\n backgroundColor: \"transparent\",\n color: palette.primary.main,\n };\n};\n\nexport const tooltipTheme: Pick<Components<Theme>, \"MuiTooltip\"> = {\n MuiTooltip: {\n defaultProps: {\n arrow: true,\n },\n styleOverrides: {\n arrow: {\n color: palette.text.base,\n },\n tooltip: {\n fontSize: fontSizes.sm,\n fontWeight: fontWeights.regular,\n lineHeight: 1.5,\n padding: spacing(1),\n ...tooltipSurfaceStyles(\"light\"),\n } as unknown as NonNullable<\n NonNullable<Components<Theme>[\"MuiTooltip\"]>[\"styleOverrides\"]\n >[\"tooltip\"],\n },\n },\n};\n","import {\n Box,\n ClickAwayListener,\n Tooltip as MuiTooltip,\n type TooltipProps as MuiTooltipProps,\n} from \"@mui/material\";\nimport { type SxProps, type Theme } from \"@mui/material/styles\";\nimport {\n useId,\n useState,\n type ReactElement,\n type ReactNode,\n} from \"react\";\nimport {\n tooltipIconMarkSx,\n tooltipSurfaceSx,\n tooltipTriggerSx,\n type TooltipSurfaceVariant,\n type TooltipTriggerVariant,\n} from \"../../theme/components/tooltip.theme\";\n\nexport type { TooltipSurfaceVariant, TooltipTriggerVariant };\n\ntype WrappedTooltipProps = Omit<MuiTooltipProps, \"children\"> & {\n children: ReactElement;\n ariaLabel?: never;\n triggerIcon?: never;\n triggerVariant?: never;\n triggerSx?: never;\n surfaceVariant?: TooltipSurfaceVariant;\n};\n\ntype TriggerTooltipProps = Omit<MuiTooltipProps, \"children\"> & {\n children?: never;\n /** Accessible name for the built-in trigger button. */\n ariaLabel: string;\n /** Trigger icon or content. Defaults to `InfoIcon`. */\n triggerIcon?: ReactNode;\n /** Visual style of the built-in trigger button. @default \"icon\" */\n triggerVariant?: TooltipTriggerVariant;\n /** Optional `sx` override for the built-in trigger button. */\n triggerSx?: SxProps<Theme>;\n /** Tooltip bubble colour treatment. @default \"light\" */\n surfaceVariant?: TooltipSurfaceVariant;\n};\n\nexport type TooltipProps = WrappedTooltipProps | TriggerTooltipProps;\n\ntype TooltipSlotProps = NonNullable<MuiTooltipProps[\"slotProps\"]>;\ntype SlotObject<T> = Exclude<T, ((...args: never[]) => unknown) | undefined>;\ntype TooltipSlotObject = SlotObject<TooltipSlotProps[\"tooltip\"]>;\ntype ArrowSlotObject = SlotObject<TooltipSlotProps[\"arrow\"]>;\n\n/**\n * Tooltip wrapper around MUI's `Tooltip`.\n *\n * Use it two ways:\n * - **Wrapped child:** pass `children` to decorate any trigger you already have.\n * - **Built-in trigger:** omit `children` and pass `ariaLabel`; a small trigger\n * button is rendered for you, styled by `triggerVariant` and optionally\n * extended via `triggerSx`.\n */\nexport const Tooltip = ({\n title,\n placement = \"top\",\n children,\n ariaLabel,\n triggerIcon,\n triggerVariant = \"icon\",\n triggerSx,\n surfaceVariant = \"light\",\n slotProps,\n id: suppliedId,\n ...rest\n}: TooltipProps) => {\n const [open, setOpen] = useState(false);\n const tooltipId = useId();\n const tooltipSlot =\n typeof slotProps?.tooltip === \"object\"\n ? (slotProps.tooltip as TooltipSlotObject)\n : undefined;\n const arrowSlot =\n typeof slotProps?.arrow === \"object\"\n ? (slotProps.arrow as ArrowSlotObject)\n : undefined;\n const resolvedTriggerSx: SxProps<Theme> = triggerSx\n ? ([tooltipTriggerSx(triggerVariant), triggerSx] as SxProps<Theme>)\n : tooltipTriggerSx(triggerVariant);\n const resolvedSlotProps: TooltipSlotProps = {\n ...slotProps,\n tooltip: {\n ...tooltipSlot,\n sx: [\n tooltipSurfaceSx(surfaceVariant),\n tooltipSlot?.sx,\n ] as unknown as TooltipSlotObject[\"sx\"],\n },\n arrow: {\n ...arrowSlot,\n sx: [\n surfaceVariant === \"dark\"\n ? { color: \"text.base\" }\n : { color: \"bg.base\" },\n arrowSlot?.sx,\n ] as unknown as ArrowSlotObject[\"sx\"],\n },\n };\n\n const closeTooltip = () => setOpen(false);\n\n const resolvedTrigger = children ? (\n children\n ) : (\n <Box sx={{ display: \"inline-flex\" }}>\n <Box\n component=\"button\"\n type=\"button\"\n aria-label={ariaLabel}\n aria-controls={open ? tooltipId : undefined}\n aria-expanded={open}\n onClick={() => setOpen((current) => !current)}\n\n // this is to stop the tooltip from opening on touch devices\n onPointerEnter={(event) => {\n if (event.pointerType === \"mouse\") {\n setOpen(true);\n }\n }}\n onPointerLeave={(event) => {\n if (event.pointerType === \"mouse\") {\n closeTooltip();\n }\n }}\n sx={resolvedTriggerSx}\n >\n {triggerIcon ?? (\n <Box\n component=\"span\"\n aria-hidden\n sx={tooltipIconMarkSx(triggerVariant)}\n />\n )}\n </Box>\n </Box>\n );\n\n const tooltip = (\n <MuiTooltip\n title={title}\n arrow\n placement={placement}\n id={children ? suppliedId : tooltipId}\n open={children ? undefined : open}\n onClose={children ? rest.onClose : closeTooltip}\n disableFocusListener={children ? rest.disableFocusListener : true}\n disableHoverListener={children ? rest.disableHoverListener : true}\n disableTouchListener={children ? rest.disableTouchListener : true}\n slotProps={resolvedSlotProps}\n {...rest}\n >\n {resolvedTrigger}\n </MuiTooltip>\n );\n\n return children ? tooltip : (\n <ClickAwayListener onClickAway={closeTooltip}>{tooltip}</ClickAwayListener>\n );\n};\n","import { palette } from \"../tokens\";\n\nexport const focusVisibleStyles = {\n \"&:focus-visible\": {\n outline: \"2px solid\",\n outlineColor: palette.text.base,\n },\n};\n","import { SxProps, Theme } from \"@mui/material\";\n\nimport {\n colors,\n durations,\n easings,\n fontSizes,\n fontWeights,\n palette,\n shadows,\n shape,\n transition,\n} from \"../tokens\";\nimport { focusVisibleStyles } from \"../utils\";\n\n/**\n * Styling for the `DevPanel` compound component. `DevPanel` is a custom\n * (non-MUI) widget, so — like `tabs` — these are exported `sx` objects the\n * sub-components apply, keeping the component files lean while the visual tokens\n * live here. All transitions respect `prefers-reduced-motion`.\n */\n\nconst reducedMotion = {\n \"@media (prefers-reduced-motion: reduce)\": { transition: \"none\" },\n} as const;\n\n/** The outer card: a rounded, cream surface with a subtle border. */\nexport const devPanelSx: SxProps<Theme> = {\n display: \"flex\",\n flexDirection: \"column\",\n width: \"100%\",\n maxWidth: 460,\n borderRadius: `${shape[\"4xl\"]}px`,\n backgroundColor: colors.beige[50],\n border: `1px solid ${palette.border.subtle}`,\n overflow: \"hidden\",\n fontFamily: \"inherit\",\n color: palette.text.base,\n};\n\n/** The chrome strip: title + status dot, an optional badge, and the minimise control. */\nexport const devPanelHeaderSx: SxProps<Theme> = {\n display: \"flex\",\n flexDirection: \"row\",\n alignItems: \"center\",\n justifyContent: \"space-between\",\n gap: 1.5,\n paddingInline: 2.5,\n paddingBlock: 1.75,\n backgroundColor: colors.beige[100],\n borderBottom: `1px solid ${palette.border.subtle}`,\n};\n\nexport const devPanelHeaderTitleSx: SxProps<Theme> = {\n display: \"inline-flex\",\n alignItems: \"center\",\n gap: 1,\n fontSize: fontSizes.md,\n fontWeight: fontWeights.semibold,\n color: palette.text.base,\n};\n\n/** The small \"live\" indicator dot beside the panel title. */\nexport const devPanelHeaderDotSx: SxProps<Theme> = {\n width: 8,\n height: 8,\n borderRadius: `${shape.full}px`,\n backgroundColor: palette.teal.base,\n flexShrink: 0,\n};\n\n/** The \"MOCK\" / \"live\" pill next to the title. */\nexport const devPanelBadgeSx: SxProps<Theme> = {\n display: \"inline-flex\",\n alignItems: \"center\",\n paddingInline: 0.75,\n paddingBlock: 0.25,\n borderRadius: `${shape.sm}px`,\n backgroundColor: colors.neutral[200],\n color: colors.neutral[700],\n fontSize: fontSizes.xs,\n fontWeight: fontWeights.semibold,\n letterSpacing: \"0.08em\",\n textTransform: \"uppercase\",\n lineHeight: 1.4,\n};\n\n/** The scrollable body that holds the sections. */\nexport const devPanelBodySx: SxProps<Theme> = {\n display: \"flex\",\n flexDirection: \"column\",\n gap: 2.5,\n padding: 2.5,\n overflowY: \"auto\",\n};\n\n/** A single labelled section (COUNTRY, VARIANT, …). */\nexport const devPanelSectionSx: SxProps<Theme> = {\n display: \"flex\",\n flexDirection: \"column\",\n gap: 1.25,\n};\n\n/**\n * The uppercase section heading. Uses `neutral[600]` (not `text.subtle`) so the\n * small label clears WCAG AA (4.5:1) against the cream body — matching the\n * `Tabs` track decision.\n */\nexport const devPanelSectionLabelSx: SxProps<Theme> = {\n margin: 0,\n fontSize: fontSizes.xs,\n fontWeight: fontWeights.semibold,\n letterSpacing: \"0.08em\",\n textTransform: \"uppercase\",\n color: colors.neutral[600],\n};\n\n/** Optional trailing meta on a section heading row (e.g. the `6 / 10` count). */\nexport const devPanelSectionHeaderRowSx: SxProps<Theme> = {\n display: \"flex\",\n flexDirection: \"row\",\n alignItems: \"center\",\n justifyContent: \"space-between\",\n gap: 1,\n};\n\nexport const devPanelSectionMetaSx: SxProps<Theme> = {\n fontSize: fontSizes.xs,\n fontWeight: fontWeights.medium,\n color: colors.neutral[600],\n};\n\n/* ----------------------------------------------------------------------------\n * FLOW header row\n * ------------------------------------------------------------------------- */\n\nexport const devPanelFlowSx: SxProps<Theme> = {\n display: \"flex\",\n flexDirection: \"row\",\n alignItems: \"center\",\n justifyContent: \"space-between\",\n gap: 1,\n paddingInline: 1.5,\n paddingBlock: 1,\n borderRadius: `${shape.lg}px`,\n backgroundColor: colors.beige[100],\n};\n\nexport const devPanelFlowTextSx: SxProps<Theme> = {\n display: \"inline-flex\",\n alignItems: \"center\",\n gap: 0.75,\n minWidth: 0,\n fontSize: fontSizes.sm,\n color: palette.text.base,\n \"& > span\": {\n overflow: \"hidden\",\n textOverflow: \"ellipsis\",\n whiteSpace: \"nowrap\",\n },\n};\n\nexport const devPanelFlowLabelSx: SxProps<Theme> = {\n fontSize: fontSizes.xs,\n fontWeight: fontWeights.semibold,\n letterSpacing: \"0.08em\",\n textTransform: \"uppercase\",\n color: colors.neutral[600],\n flexShrink: 0,\n};\n\n/* ----------------------------------------------------------------------------\n * Segmented single-select (Country / Variant / Step state)\n * ------------------------------------------------------------------------- */\n\n/** The beige track that holds the segmented options. */\nexport const segmentedGroupSx: SxProps<Theme> = {\n display: \"flex\",\n flexDirection: \"row\",\n flexWrap: \"nowrap\",\n alignItems: \"stretch\",\n gap: 0.5,\n padding: 0.5,\n borderRadius: `${shape.full}px`,\n backgroundColor: palette.bg.muted,\n maxWidth: \"100%\",\n overflowX: \"auto\",\n scrollbarWidth: \"none\",\n msOverflowStyle: \"none\",\n \"&::-webkit-scrollbar\": { display: \"none\" },\n};\n\n/**\n * The \"pill\" variant used by Country/Variant: options grow to fill the track\n * and the selected one flips to a white pill.\n */\nexport const segmentedOptionSx = (selected: boolean): SxProps<Theme> => ({\n position: \"relative\",\n flex: \"1 1 0\",\n minWidth: 0,\n display: \"inline-flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n gap: 0.75,\n margin: 0,\n paddingInline: 1.5,\n paddingBlock: 1,\n border: \"none\",\n borderRadius: `${shape.full}px`,\n cursor: \"pointer\",\n whiteSpace: \"nowrap\",\n userSelect: \"none\",\n fontFamily: \"inherit\",\n fontSize: fontSizes.sm,\n fontWeight: selected ? fontWeights.semibold : fontWeights.medium,\n lineHeight: 1,\n backgroundColor: selected ? palette.bg.base : \"transparent\",\n color: selected ? palette.text.base : colors.neutral[600],\n boxShadow: selected ? `0 1px 2px ${colors.beige[300]}` : \"none\",\n transition: transition([\"background-color\", \"color\", \"box-shadow\"]),\n ...reducedMotion,\n \"& svg\": { flexShrink: 0, display: \"block\" },\n \"&[data-disabled]\": {\n opacity: 0.45,\n cursor: \"not-allowed\",\n pointerEvents: \"none\",\n },\n ...focusVisibleStyles,\n});\n\n/**\n * The \"chip\" variant used by Step state: pills that hug their content and carry\n * a small leading dot.\n */\nexport const segmentedChipGroupSx: SxProps<Theme> = {\n display: \"flex\",\n flexDirection: \"row\",\n flexWrap: \"wrap\",\n gap: 1,\n};\n\nexport const segmentedChipSx = (selected: boolean): SxProps<Theme> => ({\n display: \"inline-flex\",\n alignItems: \"center\",\n gap: 0.75,\n margin: 0,\n paddingInline: 1.5,\n paddingBlock: 0.75,\n borderRadius: `${shape.full}px`,\n border: `1px solid ${selected ? palette.border.accent : palette.border.base}`,\n backgroundColor: selected ? palette.purple.subtle : palette.bg.base,\n color: selected ? palette.text.accent : palette.text.base,\n cursor: \"pointer\",\n whiteSpace: \"nowrap\",\n userSelect: \"none\",\n fontFamily: \"inherit\",\n fontSize: fontSizes.sm,\n fontWeight: selected ? fontWeights.semibold : fontWeights.medium,\n lineHeight: 1.2,\n transition: transition([\"background-color\", \"color\", \"border-color\"]),\n ...reducedMotion,\n \"&[data-disabled]\": {\n opacity: 0.45,\n cursor: \"not-allowed\",\n pointerEvents: \"none\",\n },\n ...focusVisibleStyles,\n});\n\nexport const segmentedChipDotSx = (selected: boolean): SxProps<Theme> => ({\n width: 7,\n height: 7,\n borderRadius: `${shape.full}px`,\n flexShrink: 0,\n backgroundColor: selected ? palette.purple.base : colors.neutral[400],\n});\n\n/* ----------------------------------------------------------------------------\n * Jump-to-step grid\n * ------------------------------------------------------------------------- */\n\nexport const stepGridSx = (columns: number): SxProps<Theme> => ({\n display: \"grid\",\n gridTemplateColumns: `repeat(${columns}, minmax(0, 1fr))`,\n gap: 1.5,\n});\n\nexport const stepButtonSx: SxProps<Theme> = {\n display: \"flex\",\n flexDirection: \"column\",\n alignItems: \"center\",\n gap: 0.75,\n // Let the button shrink to its grid track so long labels wrap instead of\n // overflowing into neighbouring cells.\n minWidth: 0,\n margin: 0,\n padding: 0,\n border: \"none\",\n background: \"none\",\n cursor: \"pointer\",\n fontFamily: \"inherit\",\n borderRadius: `${shape.lg}px`,\n \"&[data-disabled]\": {\n opacity: 0.5,\n cursor: \"not-allowed\",\n pointerEvents: \"none\",\n },\n ...focusVisibleStyles,\n};\n\nexport type StepCircleState = \"complete\" | \"current\" | \"upcoming\";\n\nconst stepCircleColors: Record<\n StepCircleState,\n { bg: string; border: string; color: string }\n> = {\n complete: {\n bg: palette.teal.base,\n border: palette.teal.base,\n color: palette.teal.contrast,\n },\n current: {\n bg: palette.purple.base,\n border: palette.purple.base,\n color: palette.purple.contrast,\n },\n upcoming: {\n bg: \"transparent\",\n border: colors.neutral[400],\n color: colors.neutral[600],\n },\n};\n\nexport const stepCircleSx = (state: StepCircleState): SxProps<Theme> => {\n const c = stepCircleColors[state];\n return {\n position: \"relative\",\n width: 40,\n height: 40,\n borderRadius: `${shape.full}px`,\n display: \"inline-flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n flexShrink: 0,\n border: `2px solid ${c.border}`,\n backgroundColor: c.bg,\n color: c.color,\n fontSize: fontSizes.sm,\n fontWeight: fontWeights.semibold,\n lineHeight: 1,\n transition: transition([\"background-color\", \"border-color\", \"color\"]),\n ...reducedMotion,\n \"& svg\": { display: \"block\" },\n };\n};\n\n/** The small warning dot on a step that needs attention. */\nexport const stepFlagDotSx: SxProps<Theme> = {\n position: \"absolute\",\n top: -1,\n right: -1,\n width: 10,\n height: 10,\n borderRadius: `${shape.full}px`,\n backgroundColor: palette.status.warning.base,\n border: `2px solid ${colors.beige[50]}`,\n};\n\nexport const stepLabelSx = (isCurrent: boolean): SxProps<Theme> => ({\n fontSize: fontSizes.xs,\n fontWeight: isCurrent ? fontWeights.semibold : fontWeights.regular,\n color: isCurrent ? palette.text.base : colors.neutral[600],\n textAlign: \"center\",\n lineHeight: 1.2,\n // Constrain to the cell and break long words so labels never overlap.\n width: \"100%\",\n overflowWrap: \"anywhere\",\n});\n\n/* ----------------------------------------------------------------------------\n * Application status cards\n * ------------------------------------------------------------------------- */\n\nexport const statusGridSx: SxProps<Theme> = {\n display: \"grid\",\n gridTemplateColumns: \"repeat(2, minmax(0, 1fr))\",\n gap: 1.25,\n};\n\nexport type DevPanelStatusColor =\n | \"warning\"\n | \"success\"\n | \"info\"\n | \"error\"\n | \"neutral\";\n\nexport const statusColorValue: Record<DevPanelStatusColor, string> = {\n warning: palette.status.warning.base,\n success: palette.status.success.base,\n info: palette.status.info.base,\n error: palette.status.error.base,\n neutral: colors.neutral[400],\n};\n\nconst statusSubtleValue: Record<DevPanelStatusColor, string> = {\n warning: palette.status.warning.subtle,\n success: palette.status.success.subtle,\n info: palette.status.info.subtle,\n error: palette.status.error.subtle,\n neutral: colors.neutral[100],\n};\n\nexport const statusCardSx = (\n color: DevPanelStatusColor,\n selected: boolean,\n): SxProps<Theme> => ({\n display: \"inline-flex\",\n alignItems: \"center\",\n gap: 1,\n margin: 0,\n paddingInline: 1.5,\n paddingBlock: 1.25,\n width: \"100%\",\n border: `1px solid ${selected ? statusColorValue[color] : palette.border.base}`,\n borderRadius: `${shape.lg}px`,\n backgroundColor: selected ? statusSubtleValue[color] : palette.bg.base,\n color: palette.text.base,\n cursor: \"pointer\",\n textAlign: \"left\",\n fontFamily: \"inherit\",\n fontSize: fontSizes.sm,\n fontWeight: selected ? fontWeights.semibold : fontWeights.medium,\n lineHeight: 1.2,\n transition: transition([\"background-color\", \"border-color\"]),\n ...reducedMotion,\n \"&[data-disabled]\": {\n opacity: 0.5,\n cursor: \"not-allowed\",\n pointerEvents: \"none\",\n },\n ...focusVisibleStyles,\n});\n\nexport const statusDotSx = (color: DevPanelStatusColor): SxProps<Theme> => ({\n width: 10,\n height: 10,\n borderRadius: `${shape.full}px`,\n flexShrink: 0,\n backgroundColor: statusColorValue[color],\n});\n\n/* ----------------------------------------------------------------------------\n * Payload preview\n * ------------------------------------------------------------------------- */\n\nexport const payloadToggleSx: SxProps<Theme> = {\n display: \"flex\",\n flexDirection: \"row\",\n alignItems: \"center\",\n justifyContent: \"space-between\",\n gap: 1,\n width: \"100%\",\n margin: 0,\n paddingInline: 1.5,\n paddingBlock: 1.25,\n border: \"none\",\n borderRadius: `${shape.lg}px`,\n backgroundColor: palette.bg.accent,\n color: palette.text.accent,\n cursor: \"pointer\",\n fontFamily: \"inherit\",\n fontSize: fontSizes.sm,\n fontWeight: fontWeights.semibold,\n ...focusVisibleStyles,\n};\n\nexport const payloadToggleLabelSx: SxProps<Theme> = {\n display: \"inline-flex\",\n alignItems: \"center\",\n gap: 1,\n};\n\nexport const payloadChevronSx = (expanded: boolean): SxProps<Theme> => ({\n display: \"inline-flex\",\n transform: expanded ? \"rotate(90deg)\" : \"rotate(0deg)\",\n transition: transition([\"transform\"], durations.emphasis, easings.standard),\n ...reducedMotion,\n \"& svg\": { display: \"block\" },\n});\n\nexport const payloadPanelSx: SxProps<Theme> = {\n marginTop: 1.25,\n borderRadius: `${shape.lg}px`,\n backgroundColor: colors.neutral[950],\n overflow: \"hidden\",\n};\n\nexport const payloadPanelHeaderSx: SxProps<Theme> = {\n display: \"flex\",\n flexDirection: \"row\",\n alignItems: \"center\",\n justifyContent: \"space-between\",\n gap: 1,\n paddingInline: 1.75,\n paddingBlock: 1.25,\n borderBottom: `1px solid ${colors.neutral[800]}`,\n color: palette.text.contrast,\n fontSize: fontSizes.sm,\n fontWeight: fontWeights.semibold,\n};\n\nexport const payloadPreSx: SxProps<Theme> = {\n margin: 0,\n padding: 1.75,\n maxHeight: 320,\n overflow: \"auto\",\n fontFamily:\n \"ui-monospace, SFMono-Regular, Menlo, Consolas, 'Liberation Mono', monospace\",\n fontSize: fontSizes.xs,\n lineHeight: 1.6,\n color: colors.neutral[100],\n whiteSpace: \"pre\",\n};\n\n/* ----------------------------------------------------------------------------\n * Payload side flyout (placement=\"side\")\n * ------------------------------------------------------------------------- */\n\n/**\n * The chevron on the side toggle. It points left, toward where the flyout\n * appears beside the panel; the open state is conveyed via `aria-expanded`.\n */\nexport const payloadSideChevronSx: SxProps<Theme> = {\n display: \"inline-flex\",\n transform: \"rotate(180deg)\",\n \"& svg\": { display: \"block\" },\n};\n\n/**\n * The floating dark payload panel that opens beside the `DevPanel`. It is\n * portalled to the document body and positioned (top/left/width/height) inline\n * from the anchored panel's rect, so it can sit outside the panel's clipped\n * bounds. `zIndex` matches MUI's `modal` layer (1300).\n */\nexport const payloadFlyoutSx: SxProps<Theme> = {\n position: \"fixed\",\n zIndex: 1300,\n display: \"flex\",\n flexDirection: \"column\",\n borderRadius: `${shape[\"4xl\"]}px`,\n backgroundColor: colors.neutral[950],\n boxShadow: shadows[\"2xl\"],\n overflow: \"hidden\",\n color: palette.text.contrast,\n outline: \"none\",\n};\n\nexport const payloadFlyoutHeaderSx: SxProps<Theme> = {\n display: \"flex\",\n flexDirection: \"row\",\n alignItems: \"center\",\n justifyContent: \"space-between\",\n gap: 1,\n paddingInline: 1.75,\n paddingBlock: 1.25,\n borderBottom: `1px solid ${colors.neutral[800]}`,\n color: palette.text.contrast,\n fontSize: fontSizes.sm,\n fontWeight: fontWeights.semibold,\n};\n\nexport const payloadFlyoutTitleSx: SxProps<Theme> = {\n display: \"inline-flex\",\n alignItems: \"center\",\n gap: 1,\n minWidth: 0,\n};\n\n/** The small pill (e.g. \"live\") in the flyout header, tuned for the dark panel. */\nexport const payloadFlyoutBadgeSx: SxProps<Theme> = {\n display: \"inline-flex\",\n alignItems: \"center\",\n paddingInline: 0.75,\n paddingBlock: 0.25,\n borderRadius: `${shape.sm}px`,\n backgroundColor: colors.neutral[800],\n color: colors.neutral[300],\n fontSize: fontSizes.xs,\n fontWeight: fontWeights.semibold,\n letterSpacing: \"0.08em\",\n textTransform: \"uppercase\",\n lineHeight: 1.4,\n};\n\n/** The scrollable JSON body: fills the remaining flyout height. */\nexport const payloadFlyoutBodySx: SxProps<Theme> = {\n margin: 0,\n padding: 1.75,\n flex: 1,\n minHeight: 0,\n overflow: \"auto\",\n fontFamily:\n \"ui-monospace, SFMono-Regular, Menlo, Consolas, 'Liberation Mono', monospace\",\n fontSize: fontSizes.xs,\n lineHeight: 1.6,\n color: colors.neutral[100],\n whiteSpace: \"pre\",\n};\n\nexport const payloadFlyoutFooterSx: SxProps<Theme> = {\n padding: 1.5,\n borderTop: `1px solid ${colors.neutral[800]}`,\n backgroundColor: colors.neutral[900],\n};\n\n/** The full-width \"Copy JSON\" action at the foot of the flyout. */\nexport const payloadFlyoutCopyButtonSx: SxProps<Theme> = {\n display: \"inline-flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n gap: 1,\n width: \"100%\",\n margin: 0,\n paddingBlock: 1.25,\n paddingInline: 1.5,\n border: `1px solid ${colors.neutral[700]}`,\n borderRadius: `${shape.lg}px`,\n backgroundColor: colors.neutral[800],\n color: palette.text.contrast,\n cursor: \"pointer\",\n fontFamily: \"inherit\",\n fontSize: fontSizes.sm,\n fontWeight: fontWeights.semibold,\n transition: transition([\"background-color\"]),\n ...reducedMotion,\n \"&:hover\": { backgroundColor: colors.neutral[700] },\n \"& svg\": { display: \"block\" },\n ...focusVisibleStyles,\n};\n\n/** The kinds of token the JSON highlighter distinguishes. */\nexport type JsonTokenType =\n | \"key\"\n | \"string\"\n | \"number\"\n | \"boolean\"\n | \"null\"\n | \"punctuation\";\n\n/**\n * Colours for the syntax-highlighted payload, tuned for the dark\n * (`neutral[950]`) panel. Every shade clears WCAG AA (4.5:1) against that\n * background, so highlighting never trades contrast for colour.\n */\nexport const payloadTokenColors: Record<JsonTokenType, string> = {\n key: colors.neutral[100],\n string: colors.teal[300],\n number: colors.orange[300],\n boolean: colors.blue[300],\n null: colors.purple[300],\n punctuation: colors.neutral[400],\n};\n\n/* ----------------------------------------------------------------------------\n * Footer actions\n * ------------------------------------------------------------------------- */\n\n/**\n * The action row. Negative horizontal / bottom margins cancel the body padding\n * (`devPanelBodySx`, `padding: 2.5`) so — when placed as the last child — the\n * footer sits flush with the panel edges under a full-width divider.\n */\nexport const devPanelFooterSx: SxProps<Theme> = {\n display: \"flex\",\n flexDirection: \"row\",\n flexWrap: \"wrap\",\n alignItems: \"center\",\n gap: 1.25,\n marginInline: -2.5,\n marginBottom: -2.5,\n marginTop: 0.5,\n paddingInline: 2.5,\n paddingBlock: 2,\n borderTop: `1px solid ${palette.border.subtle}`,\n backgroundColor: colors.beige[100],\n};\n\n/** A visually-hidden live region for copy confirmations. */\nexport const visuallyHiddenSx: SxProps<Theme> = {\n position: \"absolute\",\n width: \"1px\",\n height: \"1px\",\n padding: 0,\n margin: \"-1px\",\n overflow: \"hidden\",\n clip: \"rect(0 0 0 0)\",\n whiteSpace: \"nowrap\",\n border: 0,\n};\n","import { createTranslation } from \"../../i18n\";\n\n/**\n * Translated accessible names and status words used across the `DevPanel`\n * sub-components (copy buttons, the minimise control, and the per-step status\n * announced to assistive tech). Every string is overridable per-instance via a\n * matching prop, so consumers can localise or reword without forking.\n */\nexport const useDevPanelLabels = createTranslation({\n copy: { no: \"Kopier\", se: \"Kopiera\", fi: \"Kopioi\", es: \"Copiar\" },\n copied: { no: \"Kopiert\", se: \"Kopierad\", fi: \"Kopioitu\", es: \"Copiado\" },\n copyJson: {\n no: \"Kopier JSON\",\n se: \"Kopiera JSON\",\n fi: \"Kopioi JSON\",\n es: \"Copiar JSON\",\n },\n close: { no: \"Lukk\", se: \"Stäng\", fi: \"Sulje\", es: \"Cerrar\" },\n minimise: {\n no: \"Minimer\",\n se: \"Minimera\",\n fi: \"Pienennä\",\n es: \"Minimizar\",\n },\n expand: { no: \"Utvid\", se: \"Expandera\", fi: \"Laajenna\", es: \"Expandir\" },\n step: { no: \"Steg\", se: \"Steg\", fi: \"Vaihe\", es: \"Paso\" },\n statusCompleted: {\n no: \"fullført\",\n se: \"slutförd\",\n fi: \"valmis\",\n es: \"completado\",\n },\n statusCurrent: {\n no: \"gjeldende\",\n se: \"aktuell\",\n fi: \"nykyinen\",\n es: \"actual\",\n },\n statusUpcoming: {\n no: \"ikke startet\",\n se: \"inte påbörjad\",\n fi: \"aloittamatta\",\n es: \"no iniciado\",\n },\n needsAttention: {\n no: \"krever oppmerksomhet\",\n se: \"kräver uppmärksamhet\",\n fi: \"vaatii huomiota\",\n es: \"requiere atención\",\n },\n});\n","\"use client\";\n\nimport { Box, type SxProps, type Theme } from \"@mui/material\";\nimport { Minus, Plus } from \"lucide-react\";\nimport {\n createContext,\n useContext,\n useId,\n useState,\n type ReactNode,\n} from \"react\";\n\nimport {\n devPanelBadgeSx,\n devPanelBodySx,\n devPanelHeaderDotSx,\n devPanelHeaderSx,\n devPanelHeaderTitleSx,\n devPanelSectionHeaderRowSx,\n devPanelSectionLabelSx,\n devPanelSectionMetaSx,\n devPanelSectionSx,\n devPanelSx,\n} from \"../../theme/components/dev-panel.theme\";\nimport { IconButton } from \"../buttons\";\nimport { useDevPanelLabels } from \"./use-dev-panel-labels\";\n\n/**\n * Exposes the current section's heading `id` so an interactive group nested in a\n * `DevPanelSection` (e.g. a `radiogroup`) can wire `aria-labelledby` to a real,\n * co-located element — the id can never dangle.\n */\nconst DevPanelSectionContext = createContext<string | undefined>(undefined);\n\n/** Reads the enclosing `DevPanelSection` heading id, if any. */\nexport function useDevPanelSectionLabelId() {\n return useContext(DevPanelSectionContext);\n}\n\nexport type DevPanelProps = {\n /** Panel title shown in the header. Defaults to `\"Dev controls\"`. */\n title?: ReactNode;\n /** Optional pill beside the title, e.g. `\"MOCK\"` or `\"live\"`. */\n badge?: ReactNode;\n /** Show the small status dot before the title. Defaults to `true`. */\n showStatusDot?: boolean;\n /** Render the minimise control. Defaults to `true`. */\n minimisable?: boolean;\n /** Controlled minimised state. Omit for uncontrolled. */\n minimised?: boolean;\n /** Initial minimised state when uncontrolled. Defaults to `false`. */\n defaultMinimised?: boolean;\n /** Called whenever the minimised state changes. */\n onMinimisedChange?: (minimised: boolean) => void;\n /** Accessible name for the minimise button. Defaults to a translated label. */\n minimiseLabel?: string;\n /** Accessible name for the restore button. Defaults to a translated label. */\n expandLabel?: string;\n /** Section content: compose the `DevPanel*` sub-components here. */\n children?: ReactNode;\n sx?: SxProps<Theme>;\n};\n\n/**\n * The root of the reusable dev panel: a self-contained, content-only card that\n * form apps compose from the `DevPanel*` sub-components. It owns the chrome\n * (title, optional badge, minimise control) and layout; every section is fully\n * controlled by the consumer via `value` + `onChange`/callback props.\n *\n * It renders only the panel — placement (fixed corner, drawer, …) is left to the\n * consuming app.\n *\n * ```tsx\n * <DevPanel badge=\"MOCK\">\n * <DevPanelCountry value={country} onChange={setCountry} options={countries} />\n * <DevPanelStatus value={status} onChange={setStatus} options={statuses} />\n * <DevPanelPayload value={payload} />\n * <DevPanelFooter onReseed={reseed} onCopyUrl={() => {}} url={url} />\n * </DevPanel>\n * ```\n */\nexport function DevPanel({\n title = \"Dev controls\",\n badge,\n showStatusDot = true,\n minimisable = true,\n minimised,\n defaultMinimised = false,\n onMinimisedChange,\n minimiseLabel,\n expandLabel,\n children,\n sx,\n}: DevPanelProps) {\n const t = useDevPanelLabels();\n const isControlled = minimised !== undefined;\n const [internalMinimised, setInternalMinimised] = useState(defaultMinimised);\n const isMinimised = isControlled ? minimised : internalMinimised;\n\n const toggleMinimised = () => {\n const next = !isMinimised;\n if (!isControlled) setInternalMinimised(next);\n onMinimisedChange?.(next);\n };\n\n const bodyId = useId();\n\n return (\n <Box\n data-dev-panel-root=\"\"\n sx={[devPanelSx, ...(Array.isArray(sx) ? sx : [sx])]}\n >\n <Box component=\"header\" sx={devPanelHeaderSx}>\n <Box component=\"span\" sx={devPanelHeaderTitleSx}>\n {showStatusDot && (\n <Box component=\"span\" sx={devPanelHeaderDotSx} aria-hidden />\n )}\n <span>{title}</span>\n {badge != null && (\n <Box component=\"span\" sx={devPanelBadgeSx}>\n {badge}\n </Box>\n )}\n </Box>\n {minimisable && (\n <IconButton\n aria-label={\n isMinimised\n ? (expandLabel ?? t.expand)\n : (minimiseLabel ?? t.minimise)\n }\n aria-expanded={!isMinimised}\n aria-controls={bodyId}\n onClick={toggleMinimised}\n variant=\"outline\"\n color=\"neutral\"\n size=\"sm\"\n >\n {isMinimised ? (\n <Plus size={18} aria-hidden />\n ) : (\n <Minus size={18} aria-hidden />\n )}\n </IconButton>\n )}\n </Box>\n {!isMinimised && (\n <Box id={bodyId} sx={devPanelBodySx}>\n {children}\n </Box>\n )}\n </Box>\n );\n}\n\nexport type DevPanelSectionProps = {\n /** The uppercase section heading (e.g. `\"Country\"`). */\n label: ReactNode;\n /** Optional trailing meta shown on the heading row (e.g. a `6 / 10` count). */\n meta?: ReactNode;\n children?: ReactNode;\n sx?: SxProps<Theme>;\n};\n\n/**\n * A labelled section wrapper. Renders the uppercase heading and exposes its\n * generated id through context so a nested interactive group can reference it\n * via `aria-labelledby`. Used internally by every `DevPanel*` section; exported\n * so consumers can build bespoke sections with the same look and wiring.\n */\nexport function DevPanelSection({\n label,\n meta,\n children,\n sx,\n}: DevPanelSectionProps) {\n const labelId = useId();\n\n return (\n <Box\n component=\"section\"\n aria-labelledby={labelId}\n sx={[devPanelSectionSx, ...(Array.isArray(sx) ? sx : [sx])]}\n >\n <Box sx={devPanelSectionHeaderRowSx}>\n <Box component=\"span\" id={labelId} sx={devPanelSectionLabelSx}>\n {label}\n </Box>\n {meta != null && (\n <Box component=\"span\" sx={devPanelSectionMetaSx}>\n {meta}\n </Box>\n )}\n </Box>\n <DevPanelSectionContext.Provider value={labelId}>\n {children}\n </DevPanelSectionContext.Provider>\n </Box>\n );\n}\n","\"use client\";\n\nimport {\n useCallback,\n useRef,\n type KeyboardEvent,\n type Ref,\n} from \"react\";\n\ntype RovingRadioItemProps = {\n ref: Ref<HTMLElement>;\n role: \"radio\";\n \"aria-checked\": boolean;\n \"aria-disabled\": true | undefined;\n tabIndex: 0 | -1;\n onClick: () => void;\n onKeyDown: (event: KeyboardEvent<HTMLElement>) => void;\n};\n\ntype UseRovingRadioOptions<T> = {\n /** All selectable values, in DOM order. */\n values: readonly T[];\n /** The currently selected value (or `undefined` when nothing is selected). */\n selected: T | undefined;\n /** Called with the value to select on click / keyboard activation. */\n onSelect: (value: T) => void;\n /** Optional per-value disabled predicate; disabled items are skipped. */\n isDisabled?: (value: T, index: number) => boolean;\n};\n\n/**\n * Wires the WAI-ARIA radiogroup keyboard pattern for a set of custom option\n * elements: a single roving `tabIndex`, arrow / Home / End navigation that moves\n * focus *and* selection (activation follows focus), and Space / Enter to\n * (re)select the focused item. Disabled items are skipped.\n *\n * The consuming component owns the markup and styling; it just spreads\n * `getItemProps(index)` onto each option and renders the group with\n * `role=\"radiogroup\"`.\n */\nexport function useRovingRadio<T>({\n values,\n selected,\n onSelect,\n isDisabled,\n}: UseRovingRadioOptions<T>) {\n const refs = useRef<(HTMLElement | null)[]>([]);\n\n const disabledAt = useCallback(\n (index: number) => isDisabled?.(values[index], index) ?? false,\n [isDisabled, values],\n );\n\n const selectedIndex = values.findIndex((value) => value === selected);\n const firstEnabledIndex = values.findIndex((_, index) => !disabledAt(index));\n // Exactly one item is tabbable: the selected one, or the first enabled option\n // when there is no selection yet.\n const tabbableIndex =\n selectedIndex >= 0 && !disabledAt(selectedIndex)\n ? selectedIndex\n : firstEnabledIndex;\n\n const focusAndSelect = useCallback(\n (index: number) => {\n refs.current[index]?.focus();\n onSelect(values[index]);\n },\n [onSelect, values],\n );\n\n const nextEnabled = useCallback(\n (from: number, direction: 1 | -1) => {\n const count = values.length;\n for (let step = 1; step <= count; step += 1) {\n const index = (from + direction * step + count * step) % count;\n if (!disabledAt(index)) return index;\n }\n return from;\n },\n [disabledAt, values.length],\n );\n\n const getItemProps = useCallback(\n (index: number): RovingRadioItemProps => {\n const value = values[index];\n const disabled = disabledAt(index);\n\n return {\n ref: (element: HTMLElement | null) => {\n refs.current[index] = element;\n },\n role: \"radio\",\n \"aria-checked\": value === selected,\n \"aria-disabled\": disabled || undefined,\n tabIndex: index === tabbableIndex ? 0 : -1,\n onClick: () => {\n if (!disabled) onSelect(value);\n },\n onKeyDown: (event: KeyboardEvent<HTMLElement>) => {\n switch (event.key) {\n case \"ArrowRight\":\n case \"ArrowDown\":\n event.preventDefault();\n focusAndSelect(nextEnabled(index, 1));\n break;\n case \"ArrowLeft\":\n case \"ArrowUp\":\n event.preventDefault();\n focusAndSelect(nextEnabled(index, -1));\n break;\n case \"Home\":\n event.preventDefault();\n focusAndSelect(nextEnabled(-1, 1));\n break;\n case \"End\":\n event.preventDefault();\n focusAndSelect(nextEnabled(0, -1));\n break;\n case \" \":\n case \"Enter\":\n event.preventDefault();\n if (!disabled) onSelect(value);\n break;\n default:\n break;\n }\n },\n };\n },\n [\n disabledAt,\n focusAndSelect,\n nextEnabled,\n onSelect,\n selected,\n tabbableIndex,\n values,\n ],\n );\n\n return { getItemProps };\n}\n","\"use client\";\n\nimport { Box } from \"@mui/material\";\nimport type { ReactNode } from \"react\";\n\nimport {\n segmentedChipDotSx,\n segmentedChipGroupSx,\n segmentedChipSx,\n segmentedGroupSx,\n segmentedOptionSx,\n} from \"../../theme/components/dev-panel.theme\";\nimport { useDevPanelSectionLabelId } from \"./dev-panel\";\nimport { useRovingRadio } from \"./use-roving-radio\";\n\n/** A single option in a segmented single-select. */\nexport type SegmentedOption<T extends string> = {\n /** The value reported to `onChange` when this option is selected. */\n value: T;\n /** Visible label. */\n label: ReactNode;\n /** Optional leading icon (mark decorative icons `aria-hidden`). */\n icon?: ReactNode;\n disabled?: boolean;\n};\n\n/**\n * Requires an accessible name for the `radiogroup`. When rendered inside a\n * `DevPanelSection` the group is labelled by the section heading automatically,\n * so a name is only required when used standalone.\n */\ntype SegmentedAccessibleName =\n | { \"aria-label\"?: string; \"aria-labelledby\"?: string };\n\nexport type SegmentedRadioGroupProps<T extends string> = {\n /** The selected value (fully controlled). */\n value: T;\n /** Called with the newly selected value. */\n onChange: (value: T) => void;\n options: SegmentedOption<T>[];\n /**\n * `\"pill\"` (default) — options fill the beige track, selected flips to a white\n * pill. `\"chip\"` — options hug their content and carry a small leading dot.\n */\n variant?: \"pill\" | \"chip\";\n} & SegmentedAccessibleName;\n\n/**\n * An accessible single-select segmented control built on the roving-radiogroup\n * pattern. Internal to `DevPanel`; Country / Variant / Step state compose it.\n */\nexport function SegmentedRadioGroup<T extends string>({\n value,\n onChange,\n options,\n variant = \"pill\",\n \"aria-label\": ariaLabel,\n \"aria-labelledby\": ariaLabelledby,\n}: SegmentedRadioGroupProps<T>) {\n const sectionLabelId = useDevPanelSectionLabelId();\n const labelledBy = ariaLabelledby ?? (ariaLabel ? undefined : sectionLabelId);\n\n const { getItemProps } = useRovingRadio<T>({\n values: options.map((option) => option.value),\n selected: value,\n onSelect: onChange,\n isDisabled: (_, index) => options[index]?.disabled ?? false,\n });\n\n const isChip = variant === \"chip\";\n\n return (\n <Box\n role=\"radiogroup\"\n aria-label={ariaLabel}\n aria-labelledby={labelledBy}\n sx={isChip ? segmentedChipGroupSx : segmentedGroupSx}\n >\n {options.map((option, index) => {\n const selected = option.value === value;\n const { onKeyDown, ...itemProps } = getItemProps(index);\n return (\n <Box\n key={option.value}\n component=\"button\"\n type=\"button\"\n data-disabled={option.disabled ? \"\" : undefined}\n onKeyDown={onKeyDown}\n {...itemProps}\n sx={\n isChip ? segmentedChipSx(selected) : segmentedOptionSx(selected)\n }\n >\n {isChip ? (\n <Box component=\"span\" sx={segmentedChipDotSx(selected)} aria-hidden />\n ) : (\n option.icon\n )}\n <span>{option.label}</span>\n </Box>\n );\n })}\n </Box>\n );\n}\n","import { Box } from \"@mui/material\";\nimport type { ReactNode } from \"react\";\n\nimport { colors } from \"../../theme/tokens\";\nimport { DevPanelSection } from \"./dev-panel\";\nimport {\n SegmentedRadioGroup,\n type SegmentedOption,\n} from \"./segmented-control\";\n\n/** A selectable country. Provide between 2 and 4. */\nexport type DevPanelCountryOption<T extends string> = {\n /** The value reported to `onChange` (e.g. an ISO code). */\n value: T;\n /** Country name shown in the pill. */\n label: ReactNode;\n /** Optional short code shown, muted, before the name (e.g. `\"SE\"`). */\n code?: ReactNode;\n disabled?: boolean;\n};\n\nexport type DevPanelCountryProps<T extends string> = {\n /** The selected country (fully controlled). */\n value: T;\n /** Called with the newly selected country. */\n onChange: (value: T) => void;\n /** 2-4 country options. */\n options: DevPanelCountryOption<T>[];\n /** Section heading. Defaults to `\"Country\"`. */\n label?: ReactNode;\n};\n\n/**\n * Segmented country selector. Renders each option as a pill with an optional\n * muted code before the name. Single-select and fully controlled.\n */\nexport function DevPanelCountry<T extends string>({\n value,\n onChange,\n options,\n label = \"Country\",\n}: DevPanelCountryProps<T>) {\n const segmentedOptions: SegmentedOption<T>[] = options.map((option) => ({\n value: option.value,\n disabled: option.disabled,\n label: option.label,\n icon:\n option.code != null ? (\n <Box\n component=\"span\"\n sx={{\n color: colors.neutral[600],\n fontWeight: 600,\n fontSize: \"0.75rem\",\n }}\n >\n {option.code}\n </Box>\n ) : undefined,\n }));\n\n return (\n <DevPanelSection label={label}>\n <SegmentedRadioGroup\n value={value}\n onChange={onChange}\n options={segmentedOptions}\n />\n </DevPanelSection>\n );\n}\n","import type { ReactNode } from \"react\";\n\nimport { DevPanelSection } from \"./dev-panel\";\nimport {\n SegmentedRadioGroup,\n type SegmentedOption,\n} from \"./segmented-control\";\n\n/** A selectable flow variant. */\nexport type DevPanelVariantOption<T extends string> = {\n value: T;\n label: ReactNode;\n disabled?: boolean;\n};\n\nexport type DevPanelVariantProps<T extends string> = {\n /** The selected variant (fully controlled). */\n value: T;\n /** Called with the newly selected variant. */\n onChange: (value: T) => void;\n options: DevPanelVariantOption<T>[];\n /** Section heading. Defaults to `\"Variant\"`. */\n label?: ReactNode;\n};\n\n/**\n * Segmented flow-variant selector (e.g. cash loan / refinance / top-up).\n * Single-select and fully controlled.\n */\nexport function DevPanelVariant<T extends string>({\n value,\n onChange,\n options,\n label = \"Variant\",\n}: DevPanelVariantProps<T>) {\n const segmentedOptions: SegmentedOption<T>[] = options.map((option) => ({\n value: option.value,\n label: option.label,\n disabled: option.disabled,\n }));\n\n return (\n <DevPanelSection label={label}>\n <SegmentedRadioGroup\n value={value}\n onChange={onChange}\n options={segmentedOptions}\n />\n </DevPanelSection>\n );\n}\n","import { Box } from \"@mui/material\";\nimport type { ReactNode } from \"react\";\n\nimport { colors } from \"../../theme/tokens\";\nimport { Text } from \"../typography\";\nimport { DevPanelSection } from \"./dev-panel\";\nimport {\n SegmentedRadioGroup,\n type SegmentedOption,\n} from \"./segmented-control\";\n\n/** A selectable variation of the current step. */\nexport type DevPanelStepStateOption<T extends string> = {\n value: T;\n label: ReactNode;\n disabled?: boolean;\n};\n\nexport type DevPanelStepStateProps<T extends string> = {\n /** The selected step-state variation (fully controlled). */\n value: T;\n /** Called with the newly selected variation. */\n onChange: (value: T) => void;\n options: DevPanelStepStateOption<T>[];\n /** Section heading. Defaults to `\"Step state\"`. */\n label?: ReactNode;\n /**\n * Name of the step the variations belong to (e.g. `\"Skulder\"`). When set, a\n * `\"{variationsLabel} {stepLabel}\"` line is shown above the chips.\n */\n stepLabel?: ReactNode;\n /** Prefix for the step-label line. Defaults to `\"Variations for\"`. */\n variationsLabel?: ReactNode;\n};\n\n/**\n * Segmented chips for the different states/variations of the current step (e.g.\n * required debts / voluntary / no debts). Single-select and fully controlled.\n */\nexport function DevPanelStepState<T extends string>({\n value,\n onChange,\n options,\n label = \"Step state\",\n stepLabel,\n variationsLabel = \"Variations for\",\n}: DevPanelStepStateProps<T>) {\n const segmentedOptions: SegmentedOption<T>[] = options.map((option) => ({\n value: option.value,\n label: option.label,\n disabled: option.disabled,\n }));\n\n return (\n <DevPanelSection label={label}>\n {stepLabel != null && (\n <Text fontSize=\"sm\" color={colors.neutral[600]} sx={{ mb: 0.5 }}>\n {variationsLabel}{\" \"}\n <Box\n component=\"span\"\n sx={{ color: \"text.base\", fontWeight: 600 }}\n >\n {stepLabel}\n </Box>\n </Text>\n )}\n <SegmentedRadioGroup\n value={value}\n onChange={onChange}\n options={segmentedOptions}\n variant=\"chip\"\n />\n </DevPanelSection>\n );\n}\n","\"use client\";\n\nimport { Box } from \"@mui/material\";\nimport { Check } from \"lucide-react\";\nimport type { ReactNode } from \"react\";\n\nimport {\n stepButtonSx,\n stepCircleSx,\n stepFlagDotSx,\n stepGridSx,\n stepLabelSx,\n type StepCircleState,\n} from \"../../theme/components/dev-panel.theme\";\nimport { useDevPanelSectionLabelId, DevPanelSection } from \"./dev-panel\";\nimport { useDevPanelLabels } from \"./use-dev-panel-labels\";\n\n/** A single step in the jump-to-step grid. */\nexport type DevPanelStep = {\n /** Short label shown beneath the circle (e.g. `\"Skulder\"`). */\n label: ReactNode;\n /**\n * Explicit visual state. When omitted it is derived from `currentStep`\n * (before → `complete`, at → `current`, after → `upcoming`).\n */\n status?: StepCircleState;\n /** Marks the step with a warning dot (e.g. it needs attention). */\n flagged?: boolean;\n disabled?: boolean;\n};\n\nexport type DevPanelStepsProps = {\n /** The ordered steps. */\n steps: DevPanelStep[];\n /**\n * The active step (1-based). Drives the count and, for any step without an\n * explicit `status`, the derived complete/current/upcoming state.\n */\n currentStep?: number;\n /** Called when a step is chosen, with its 1-based number and the step. */\n onStepSelect?: (step: number, item: DevPanelStep) => void;\n /** Section heading. Defaults to `\"Jump to step\"`. */\n label?: ReactNode;\n /** Show the `currentStep / total` count in the heading. Defaults to `true`. */\n showCount?: boolean;\n /** Number of step circles per row. Defaults to `4`. */\n columns?: number;\n};\n\nconst statusWord = (\n state: StepCircleState,\n t: ReturnType<typeof useDevPanelLabels>,\n) => {\n switch (state) {\n case \"complete\":\n return t.statusCompleted;\n case \"current\":\n return t.statusCurrent;\n default:\n return t.statusUpcoming;\n }\n};\n\n/**\n * A grid of numbered step circles for jumping between form steps. Completed\n * steps show a check, the current step is filled, and a warning dot flags steps\n * that need attention. Fully controlled: the consumer supplies the steps and the\n * active step, and handles selection.\n */\nexport function DevPanelSteps({\n steps,\n currentStep,\n onStepSelect,\n label = \"Jump to step\",\n showCount = true,\n columns = 4,\n}: DevPanelStepsProps) {\n const t = useDevPanelLabels();\n const total = steps.length;\n const meta =\n showCount && currentStep != null ? `${currentStep} / ${total}` : undefined;\n\n return (\n <DevPanelSection label={label} meta={meta}>\n <StepGrid\n steps={steps}\n currentStep={currentStep}\n onStepSelect={onStepSelect}\n columns={columns}\n t={t}\n />\n </DevPanelSection>\n );\n}\n\nfunction StepGrid({\n steps,\n currentStep,\n onStepSelect,\n columns,\n t,\n}: {\n steps: DevPanelStep[];\n currentStep?: number;\n onStepSelect?: (step: number, item: DevPanelStep) => void;\n columns: number;\n t: ReturnType<typeof useDevPanelLabels>;\n}) {\n const groupLabelId = useDevPanelSectionLabelId();\n\n return (\n <Box role=\"group\" aria-labelledby={groupLabelId} sx={stepGridSx(columns)}>\n {steps.map((item, index) => {\n const stepNumber = index + 1;\n const state: StepCircleState =\n item.status ??\n (currentStep == null\n ? \"upcoming\"\n : stepNumber < currentStep\n ? \"complete\"\n : stepNumber === currentStep\n ? \"current\"\n : \"upcoming\");\n const isCurrent = state === \"current\";\n\n const labelText = typeof item.label === \"string\" ? item.label : \"\";\n const accessibleName = [\n `${t.step} ${stepNumber}`,\n labelText ? `: ${labelText}` : \"\",\n `, ${statusWord(state, t)}`,\n item.flagged ? `, ${t.needsAttention}` : \"\",\n ].join(\"\");\n\n return (\n <Box\n key={stepNumber}\n component=\"button\"\n type=\"button\"\n aria-label={accessibleName}\n aria-current={isCurrent ? \"step\" : undefined}\n data-disabled={item.disabled ? \"\" : undefined}\n disabled={item.disabled}\n onClick={() => onStepSelect?.(stepNumber, item)}\n sx={stepButtonSx}\n >\n <Box component=\"span\" sx={stepCircleSx(state)}>\n {state === \"complete\" ? (\n <Check size={18} aria-hidden />\n ) : (\n stepNumber\n )}\n {item.flagged && (\n <Box component=\"span\" sx={stepFlagDotSx} aria-hidden />\n )}\n </Box>\n <Box component=\"span\" sx={stepLabelSx(isCurrent)}>\n {item.label}\n </Box>\n </Box>\n );\n })}\n </Box>\n );\n}\n","\"use client\";\n\nimport { Box } from \"@mui/material\";\nimport type { ReactNode } from \"react\";\n\nimport {\n statusCardSx,\n statusDotSx,\n statusGridSx,\n type DevPanelStatusColor,\n} from \"../../theme/components/dev-panel.theme\";\nimport { useDevPanelSectionLabelId, DevPanelSection } from \"./dev-panel\";\nimport { useRovingRadio } from \"./use-roving-radio\";\n\nexport type { DevPanelStatusColor };\n\n/** A selectable application status. */\nexport type DevPanelStatusOption<T extends string> = {\n value: T;\n label: ReactNode;\n /**\n * Colour of the leading dot / selected border. Defaults to `\"neutral\"`. The\n * dot is decorative — status is always conveyed by the label text too, so it\n * never relies on colour alone.\n */\n color?: DevPanelStatusColor;\n disabled?: boolean;\n};\n\nexport type DevPanelStatusProps<T extends string> = {\n /** The selected status (fully controlled). */\n value: T;\n /** Called with the newly selected status. */\n onChange: (value: T) => void;\n options: DevPanelStatusOption<T>[];\n /** Section heading. Defaults to `\"Application status\"`. */\n label?: ReactNode;\n};\n\n/**\n * A radio grid for the application status. Each card carries a decorative\n * coloured dot mapped to a status token; the status is always spelled out in the\n * label so it is never signalled by colour alone. Single-select and fully\n * controlled.\n */\nexport function DevPanelStatus<T extends string>({\n value,\n onChange,\n options,\n label = \"Application status\",\n}: DevPanelStatusProps<T>) {\n return (\n <DevPanelSection label={label}>\n <StatusGrid value={value} onChange={onChange} options={options} />\n </DevPanelSection>\n );\n}\n\nfunction StatusGrid<T extends string>({\n value,\n onChange,\n options,\n}: {\n value: T;\n onChange: (value: T) => void;\n options: DevPanelStatusOption<T>[];\n}) {\n const groupLabelId = useDevPanelSectionLabelId();\n const { getItemProps } = useRovingRadio<T>({\n values: options.map((option) => option.value),\n selected: value,\n onSelect: onChange,\n isDisabled: (_, index) => options[index]?.disabled ?? false,\n });\n\n return (\n <Box role=\"radiogroup\" aria-labelledby={groupLabelId} sx={statusGridSx}>\n {options.map((option, index) => {\n const selected = option.value === value;\n const color = option.color ?? \"neutral\";\n const { onKeyDown, ...itemProps } = getItemProps(index);\n return (\n <Box\n key={option.value}\n component=\"button\"\n type=\"button\"\n data-disabled={option.disabled ? \"\" : undefined}\n onKeyDown={onKeyDown}\n {...itemProps}\n sx={statusCardSx(color, selected)}\n >\n <Box component=\"span\" sx={statusDotSx(color)} aria-hidden />\n <span>{option.label}</span>\n </Box>\n );\n })}\n </Box>\n );\n}\n","\"use client\";\n\nimport { useCallback, useEffect, useRef, useState } from \"react\";\n\n/**\n * Writes text to the clipboard and tracks a short-lived `copied` flag so the\n * caller can announce success (via a `role=\"status\"` live region) and flip an\n * icon. The flag auto-resets after ~2s; the pending timer is cleared on unmount.\n */\nexport function useCopy() {\n const [copied, setCopied] = useState(false);\n const timeoutRef = useRef<ReturnType<typeof setTimeout> | undefined>(\n undefined,\n );\n\n const copy = useCallback(async (text: string) => {\n try {\n await navigator.clipboard?.writeText(text);\n } catch {\n // Clipboard can reject (permissions, insecure context). Still surface the\n // confirmation so the interaction feels responsive; the dev can retry.\n }\n setCopied(true);\n clearTimeout(timeoutRef.current);\n timeoutRef.current = setTimeout(() => setCopied(false), 2000);\n }, []);\n\n useEffect(() => () => clearTimeout(timeoutRef.current), []);\n\n return { copied, copy };\n}\n","\"use client\";\n\nimport { Box } from \"@mui/material\";\nimport { Check, Copy } from \"lucide-react\";\nimport { Fragment, type ReactNode } from \"react\";\n\nimport {\n devPanelFlowLabelSx,\n devPanelFlowSx,\n devPanelFlowTextSx,\n visuallyHiddenSx,\n} from \"../../theme/components/dev-panel.theme\";\nimport { IconButton } from \"../buttons\";\nimport { useCopy } from \"./use-copy\";\nimport { useDevPanelLabels } from \"./use-dev-panel-labels\";\n\nexport type DevPanelFlowProps = {\n /** Flow identifier (e.g. a short hash). */\n flowId?: ReactNode;\n /** Process name (e.g. `\"loan-se\"`). */\n process?: ReactNode;\n /** Variant name (e.g. `\"refinance\"`). */\n variant?: ReactNode;\n /** Leading label. Defaults to `\"Flow\"`. */\n label?: ReactNode;\n /** Show the copy button. Defaults to `true`. */\n showCopy?: boolean;\n /**\n * String written to the clipboard. Defaults to the string parts joined by\n * `\" · \"`.\n */\n copyValue?: string;\n /** Accessible name for the copy button. Defaults to a translated label. */\n copyLabel?: string;\n /** Called after a successful copy. */\n onCopy?: () => void;\n};\n\nconst asCopyString = (part: ReactNode) =>\n typeof part === \"string\" || typeof part === \"number\" ? String(part) : null;\n\n/**\n * The flow header row: an uppercase label followed by the `id · process ·\n * variant` breadcrumb and a copy button. Copy success is announced via a\n * `role=\"status\"` live region.\n */\nexport function DevPanelFlow({\n flowId,\n process,\n variant,\n label = \"Flow\",\n showCopy = true,\n copyValue,\n copyLabel,\n onCopy,\n}: DevPanelFlowProps) {\n const t = useDevPanelLabels();\n const { copied, copy } = useCopy();\n\n const parts = [flowId, process, variant].filter(\n (part): part is ReactNode => part != null,\n );\n const derivedCopy = parts\n .map(asCopyString)\n .filter((part): part is string => part != null)\n .join(\" · \");\n const textToCopy = copyValue ?? derivedCopy;\n\n const handleCopy = async () => {\n await copy(textToCopy);\n onCopy?.();\n };\n\n return (\n <Box sx={devPanelFlowSx}>\n <Box sx={devPanelFlowTextSx}>\n <Box component=\"span\" sx={devPanelFlowLabelSx}>\n {label}\n </Box>\n <span>\n {parts.map((part, index) => (\n <Fragment key={index}>\n {index > 0 && (\n <Box\n component=\"span\"\n aria-hidden\n sx={{ color: \"text.muted\", mx: 0.5 }}\n >\n ·\n </Box>\n )}\n {part}\n </Fragment>\n ))}\n </span>\n </Box>\n {showCopy && (\n <IconButton\n aria-label={copyLabel ?? t.copy}\n onClick={handleCopy}\n variant=\"outline\"\n color=\"neutral\"\n size=\"sm\"\n >\n {copied ? (\n <Check size={16} aria-hidden />\n ) : (\n <Copy size={16} aria-hidden />\n )}\n </IconButton>\n )}\n <Box component=\"span\" role=\"status\" aria-live=\"polite\" sx={visuallyHiddenSx}>\n {copied ? t.copied : \"\"}\n </Box>\n </Box>\n );\n}\n","\"use client\";\n\nimport { useMemo } from \"react\";\n\nimport {\n payloadTokenColors,\n type JsonTokenType,\n} from \"../../theme/components/dev-panel.theme\";\n\ntype Token = { type: JsonTokenType; value: string };\n\n// Matches the value-bearing tokens (strings, numbers, and the JSON keywords).\n// Everything between matches (braces, brackets, commas, colons, whitespace) is\n// treated as punctuation.\nconst TOKEN =\n /\"(?:\\\\.|[^\"\\\\])*\"|-?\\d+(?:\\.\\d+)?(?:[eE][+-]?\\d+)?|\\b(?:true|false|null)\\b/g;\n\nconst isSpace = (char: string) =>\n char === \" \" || char === \"\\t\" || char === \"\\n\" || char === \"\\r\";\n\nfunction classify(raw: string, code: string, end: number): JsonTokenType {\n if (raw[0] === '\"') {\n // A string is a key when the next non-space character is a colon.\n let i = end;\n while (i < code.length && isSpace(code[i])) i += 1;\n return code[i] === \":\" ? \"key\" : \"string\";\n }\n if (raw === \"true\" || raw === \"false\") return \"boolean\";\n if (raw === \"null\") return \"null\";\n return \"number\";\n}\n\nfunction tokenize(code: string): Token[] {\n const tokens: Token[] = [];\n let lastIndex = 0;\n\n for (const match of code.matchAll(TOKEN)) {\n const index = match.index ?? 0;\n if (index > lastIndex) {\n tokens.push({ type: \"punctuation\", value: code.slice(lastIndex, index) });\n }\n const raw = match[0];\n tokens.push({ type: classify(raw, code, index + raw.length), value: raw });\n lastIndex = index + raw.length;\n }\n\n if (lastIndex < code.length) {\n tokens.push({ type: \"punctuation\", value: code.slice(lastIndex) });\n }\n\n return tokens;\n}\n\n/**\n * Returns `true` when `value` should be syntax-highlighted as JSON: any non-null\n * non-string value (objects, arrays, numbers, booleans), or a string that parses\n * cleanly as JSON. Plain prose strings return `false` so they render verbatim.\n */\nexport function looksLikeJson(value: unknown): boolean {\n if (typeof value !== \"string\") return value != null;\n const trimmed = value.trim();\n if (!trimmed) return false;\n try {\n JSON.parse(trimmed);\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * Renders a serialised JSON string as coloured spans. Output is built from React\n * nodes (never `dangerouslySetInnerHTML`), so a string value such as `\"<img>\"`\n * is shown as text and can never inject markup. Colours come from the theme's\n * `payloadTokenColors` and are applied inline to keep the many spans cheap.\n */\nexport function JsonHighlight({ code }: { code: string }) {\n const tokens = useMemo(() => tokenize(code), [code]);\n\n return (\n <>\n {tokens.map((token, index) => (\n <span key={index} style={{ color: payloadTokenColors[token.type] }}>\n {token.value}\n </span>\n ))}\n </>\n );\n}\n","\"use client\";\n\nimport { Box, Portal } from \"@mui/material\";\nimport { Braces, Check, ChevronRight, Copy, X } from \"lucide-react\";\nimport {\n useCallback,\n useEffect,\n useId,\n useLayoutEffect,\n useRef,\n useState,\n type CSSProperties,\n type ReactNode,\n} from \"react\";\n\nimport {\n payloadChevronSx,\n payloadFlyoutBadgeSx,\n payloadFlyoutBodySx,\n payloadFlyoutCopyButtonSx,\n payloadFlyoutFooterSx,\n payloadFlyoutHeaderSx,\n payloadFlyoutSx,\n payloadFlyoutTitleSx,\n payloadPanelHeaderSx,\n payloadPanelSx,\n payloadPreSx,\n payloadSideChevronSx,\n payloadToggleLabelSx,\n payloadToggleSx,\n visuallyHiddenSx,\n} from \"../../theme/components/dev-panel.theme\";\nimport { IconButton } from \"../buttons\";\nimport { JsonHighlight, looksLikeJson } from \"./json-highlight\";\nimport { useCopy } from \"./use-copy\";\nimport { useDevPanelLabels } from \"./use-dev-panel-labels\";\n\n/** Re-points the button's colour properties for the dark payload panel. */\nconst onDarkButtonStyle = {\n \"--button-fg\": \"var(--lea-palette-text-contrast)\",\n \"--button-border\": \"var(--lea-palette-border-contrast)\",\n \"--button-tint\": \"var(--lea-color-neutral-800)\",\n} as CSSProperties;\n\nexport type DevPanelPayloadProps = {\n /**\n * The payload to preview. Objects are pretty-printed as JSON; strings are\n * shown verbatim.\n */\n value: unknown;\n /** Label on the toggle. Defaults to `\"Payload preview\"`. */\n label?: ReactNode;\n /** Heading of the expanded dark panel. Defaults to `label`. */\n title?: ReactNode;\n /**\n * Where the payload opens. `\"inline\"` (default) expands a dark panel below the\n * toggle; `\"side\"` opens a floating panel beside the `DevPanel` as a dialog\n * (dismissed with Escape or a click outside).\n */\n placement?: \"inline\" | \"side\";\n /** Optional pill in the side flyout header, e.g. `\"live\"`. Ignored inline. */\n badge?: ReactNode;\n /** Controlled open state. Omit for uncontrolled. */\n open?: boolean;\n /** Initial open state when uncontrolled. Defaults to `false`. */\n defaultOpen?: boolean;\n /** Called whenever the open state changes. */\n onOpenChange?: (open: boolean) => void;\n /** Accessible name for the copy button. Defaults to a translated label. */\n copyLabel?: string;\n /** Visible label for the side flyout's copy action. Defaults to a translated label. */\n copyJsonLabel?: string;\n /** Accessible name for the side flyout's close button. Defaults to a translated label. */\n closeLabel?: string;\n /**\n * Syntax-highlight JSON payloads. Defaults to `true`. Non-JSON strings always\n * render verbatim. Set `false` for the plain single-colour view.\n */\n highlight?: boolean;\n};\n\nconst serialise = (value: unknown): string => {\n if (typeof value === \"string\") return value;\n try {\n return JSON.stringify(value, null, 2);\n } catch {\n return String(value);\n }\n};\n\n// Avoid the useLayoutEffect SSR warning while still positioning before paint on\n// the client (the flyout only opens in response to a client interaction).\nconst useIsomorphicLayoutEffect =\n typeof window !== \"undefined\" ? useLayoutEffect : useEffect;\n\ntype FlyoutRect = { top: number; left: number; width: number; height: number };\n\nconst GAP = 12;\nconst MAX_WIDTH = 420;\nconst MIN_WIDTH = 280;\n\n/**\n * A payload preview. The toggle is a disclosure (`aria-expanded`/`aria-controls`)\n * that reveals the pretty-printed JSON with a copy control; copy success is\n * announced via a `role=\"status\"` live region. With `placement=\"inline\"`\n * (default) it expands a dark panel below the toggle; with `placement=\"side\"` it\n * opens a floating dialog beside the panel (Escape / click-outside to close,\n * focus moves in and returns to the toggle on close). Uncontrolled by default;\n * drive it with `open`/`onOpenChange` when needed.\n */\nexport function DevPanelPayload({\n value,\n label = \"Payload preview\",\n title,\n placement = \"inline\",\n badge,\n open,\n defaultOpen = false,\n onOpenChange,\n copyLabel,\n copyJsonLabel,\n closeLabel,\n highlight = true,\n}: DevPanelPayloadProps) {\n const t = useDevPanelLabels();\n const { copied, copy } = useCopy();\n const isControlled = open !== undefined;\n const [internalOpen, setInternalOpen] = useState(defaultOpen);\n const isOpen = isControlled ? open : internalOpen;\n const panelId = useId();\n const titleId = useId();\n const isSide = placement === \"side\";\n\n const toggleRef = useRef<HTMLButtonElement>(null);\n const flyoutRef = useRef<HTMLDivElement>(null);\n const [rect, setRect] = useState<FlyoutRect | null>(null);\n\n const setOpen = useCallback(\n (next: boolean) => {\n if (!isControlled) setInternalOpen(next);\n onOpenChange?.(next);\n },\n [isControlled, onOpenChange],\n );\n\n const text = serialise(value);\n const body =\n highlight && looksLikeJson(value) ? <JsonHighlight code={text} /> : text;\n\n const position = useCallback(() => {\n const anchor =\n (toggleRef.current?.closest(\n \"[data-dev-panel-root]\",\n ) as HTMLElement | null) ?? toggleRef.current;\n if (!anchor) return;\n const r = anchor.getBoundingClientRect();\n const width = Math.min(MAX_WIDTH, Math.max(MIN_WIDTH, r.width));\n // Prefer the left of the panel; flip to the right when there isn't room.\n let left = r.left - width - GAP;\n if (left < GAP) {\n left = Math.min(r.right + GAP, window.innerWidth - width - GAP);\n }\n const height = Math.min(r.height, window.innerHeight - GAP * 2);\n const top = Math.min(\n Math.max(GAP, r.top),\n window.innerHeight - GAP - height,\n );\n setRect({ top, left, width, height });\n }, []);\n\n useIsomorphicLayoutEffect(() => {\n if (!isSide || !isOpen) return;\n position();\n const onChange = () => position();\n window.addEventListener(\"resize\", onChange);\n window.addEventListener(\"scroll\", onChange, true);\n return () => {\n window.removeEventListener(\"resize\", onChange);\n window.removeEventListener(\"scroll\", onChange, true);\n };\n }, [isSide, isOpen, position]);\n\n useEffect(() => {\n if (!isSide || !isOpen) return;\n const flyout = flyoutRef.current;\n const toggle = toggleRef.current;\n\n const focusable = () =>\n Array.from(\n flyout?.querySelectorAll<HTMLElement>(\n 'button, [href], input, textarea, select, [tabindex]:not([tabindex=\"-1\"])',\n ) ?? [],\n ).filter((el) => !el.hasAttribute(\"disabled\"));\n\n (focusable()[0] ?? flyout)?.focus();\n\n const onKeyDown = (event: KeyboardEvent) => {\n if (event.key === \"Escape\") {\n event.stopPropagation();\n setOpen(false);\n return;\n }\n if (event.key !== \"Tab\") return;\n const items = focusable();\n if (items.length === 0) {\n event.preventDefault();\n flyout?.focus();\n return;\n }\n const first = items[0];\n const last = items[items.length - 1];\n const active = document.activeElement;\n if (event.shiftKey && (active === first || active === flyout)) {\n event.preventDefault();\n last.focus();\n } else if (!event.shiftKey && active === last) {\n event.preventDefault();\n first.focus();\n }\n };\n\n const onPointerDown = (event: PointerEvent) => {\n const target = event.target as Node;\n if (flyout?.contains(target) || toggle?.contains(target)) return;\n setOpen(false);\n };\n\n document.addEventListener(\"keydown\", onKeyDown, true);\n document.addEventListener(\"pointerdown\", onPointerDown, true);\n return () => {\n document.removeEventListener(\"keydown\", onKeyDown, true);\n document.removeEventListener(\"pointerdown\", onPointerDown, true);\n toggle?.focus();\n };\n }, [isSide, isOpen, setOpen]);\n\n const copyButton = (\n <IconButton\n aria-label={copyLabel ?? t.copy}\n onClick={() => copy(text)}\n variant=\"outline\"\n color=\"neutral\"\n size=\"sm\"\n style={onDarkButtonStyle}\n >\n {copied ? <Check size={16} aria-hidden /> : <Copy size={16} aria-hidden />}\n </IconButton>\n );\n\n return (\n <Box>\n <Box\n ref={toggleRef}\n component=\"button\"\n type=\"button\"\n aria-expanded={isOpen}\n aria-controls={panelId}\n onClick={() => setOpen(!isOpen)}\n sx={payloadToggleSx}\n >\n <Box component=\"span\" sx={payloadToggleLabelSx}>\n <Braces size={16} aria-hidden />\n {label}\n </Box>\n <Box\n component=\"span\"\n sx={isSide ? payloadSideChevronSx : payloadChevronSx(isOpen)}\n >\n <ChevronRight size={16} aria-hidden />\n </Box>\n </Box>\n\n {!isSide && isOpen && (\n <Box id={panelId} sx={payloadPanelSx}>\n <Box sx={payloadPanelHeaderSx}>\n <span>{title ?? label}</span>\n {copyButton}\n </Box>\n <Box component=\"pre\" tabIndex={0} sx={payloadPreSx}>\n {body}\n </Box>\n </Box>\n )}\n\n {isSide && isOpen && (\n <Portal>\n <Box\n ref={flyoutRef}\n id={panelId}\n role=\"dialog\"\n aria-labelledby={titleId}\n tabIndex={-1}\n sx={payloadFlyoutSx}\n style={\n rect\n ? {\n top: rect.top,\n left: rect.left,\n width: rect.width,\n height: rect.height,\n }\n : { visibility: \"hidden\" }\n }\n >\n <Box sx={payloadFlyoutHeaderSx}>\n <Box component=\"span\" sx={payloadFlyoutTitleSx}>\n <span id={titleId}>{title ?? label}</span>\n {badge != null && (\n <Box component=\"span\" sx={payloadFlyoutBadgeSx}>\n {badge}\n </Box>\n )}\n </Box>\n <IconButton\n aria-label={closeLabel ?? t.close}\n onClick={() => setOpen(false)}\n variant=\"outline\"\n color=\"neutral\"\n size=\"sm\"\n style={onDarkButtonStyle}\n >\n <X size={16} aria-hidden />\n </IconButton>\n </Box>\n <Box component=\"pre\" tabIndex={0} sx={payloadFlyoutBodySx}>\n {body}\n </Box>\n <Box sx={payloadFlyoutFooterSx}>\n <Box\n component=\"button\"\n type=\"button\"\n onClick={() => copy(text)}\n sx={payloadFlyoutCopyButtonSx}\n >\n {copied ? (\n <Check size={16} aria-hidden />\n ) : (\n <Copy size={16} aria-hidden />\n )}\n {copied ? t.copied : (copyJsonLabel ?? t.copyJson)}\n </Box>\n </Box>\n </Box>\n </Portal>\n )}\n\n <Box\n component=\"span\"\n role=\"status\"\n aria-live=\"polite\"\n sx={visuallyHiddenSx}\n >\n {copied ? t.copied : \"\"}\n </Box>\n </Box>\n );\n}\n","\"use client\";\n\nimport { Box } from \"@mui/material\";\nimport { ChevronRight, RotateCcw, Upload } from \"lucide-react\";\nimport type { ReactNode } from \"react\";\n\nimport { devPanelFooterSx } from \"../../theme/components/dev-panel.theme\";\nimport { Button } from \"../buttons\";\nimport { useCopy } from \"./use-copy\";\n\nexport type DevPanelFooterProps = {\n /** Called when \"Reseed\" is pressed. Omit to hide the button. */\n onReseed?: () => void;\n /** Label for the reseed button. Defaults to `\"Reseed\"`. */\n reseedLabel?: ReactNode;\n /** Called when \"Copy URL\" is pressed. Omit to hide the button. */\n onCopyUrl?: () => void;\n /** When set, this URL is written to the clipboard before `onCopyUrl` fires. */\n url?: string;\n /** Label for the copy-URL button. Defaults to `\"Copy URL\"`. */\n copyUrlLabel?: ReactNode;\n /** Called when \"Console\" is pressed. Omit to hide the button. */\n onConsole?: () => void;\n /** Label for the console button. Defaults to `\"Console\"`. */\n consoleLabel?: ReactNode;\n /** Extra actions appended after the built-in buttons. */\n children?: ReactNode;\n};\n\n/**\n * The footer action row. Renders a button only for each callback provided, so\n * apps opt into just the actions they support. `Copy URL` writes `url` to the\n * clipboard (when given) before invoking `onCopyUrl`. Extra `children` are\n * appended after the built-ins.\n */\nexport function DevPanelFooter({\n onReseed,\n reseedLabel = \"Reseed\",\n onCopyUrl,\n url,\n copyUrlLabel = \"Copy URL\",\n onConsole,\n consoleLabel = \"Console\",\n children,\n}: DevPanelFooterProps) {\n const { copy } = useCopy();\n\n const handleCopyUrl = async () => {\n if (url != null) await copy(url);\n onCopyUrl?.();\n };\n\n return (\n <Box sx={devPanelFooterSx}>\n {onReseed && (\n <Button\n variant=\"outline\"\n color=\"neutral\"\n size=\"sm\"\n startIcon={<RotateCcw aria-hidden />}\n onClick={onReseed}\n >\n {reseedLabel}\n </Button>\n )}\n {onCopyUrl && (\n <Button\n variant=\"outline\"\n color=\"neutral\"\n size=\"sm\"\n startIcon={<Upload aria-hidden />}\n onClick={handleCopyUrl}\n >\n {copyUrlLabel}\n </Button>\n )}\n {onConsole && (\n <Button\n variant=\"solid\"\n size=\"sm\"\n endIcon={<ChevronRight aria-hidden />}\n onClick={onConsole}\n style={{ marginInlineStart: \"auto\" }}\n >\n {consoleLabel}\n </Button>\n )}\n {children}\n </Box>\n );\n}\n","/*\n * Shared by Alert and GlobalAlert. Design tokens come from src/theme/tokens.css,\n * so these render styled without a provider.\n *\n * Each colour sets two local properties that the variants read, which keeps\n * the variant x colour matrix to one rule per cell.\n */\n\n.Alert {\n --alert-base: var(--lea-palette-status-success-base);\n --alert-subtle: var(--lea-palette-status-success-subtle);\n\n /* The height of one line of text, so the icon centres on the first line. */\n --alert-line: calc(var(--lea-font-size-md) * 1.5);\n --alert-message-padding: calc(var(--lea-spacing) * 0.7);\n\n box-sizing: border-box;\n padding: var(--lea-spacing) calc(var(--lea-spacing) * 2);\n border-radius: var(--lea-radius-xl);\n color: var(--lea-palette-text-base);\n font-size: var(--lea-font-size-md);\n font-weight: var(--lea-font-weight-regular);\n line-height: 1.5;\n}\n\n.Layout {\n display: flex;\n align-items: flex-start;\n gap: calc(var(--lea-spacing) * 1.5);\n}\n\n.Icon {\n box-sizing: content-box;\n display: flex;\n height: var(--alert-line);\n flex-shrink: 0;\n align-items: center;\n padding-block: var(--alert-message-padding);\n color: var(--alert-base);\n font-size: var(--lea-font-size-lg);\n}\n\n.Message {\n display: flex;\n min-width: 0;\n flex: 1;\n flex-direction: column;\n padding-block: var(--alert-message-padding);\n overflow-wrap: anywhere;\n}\n\n.Title {\n font-weight: var(--lea-font-weight-medium);\n}\n\n.Action {\n display: flex;\n flex-shrink: 0;\n align-items: center;\n margin-inline-start: auto;\n}\n\n/* Colours */\n\n.Alert[data-color=\"info\"] {\n --alert-base: var(--lea-palette-status-info-base);\n --alert-subtle: var(--lea-palette-status-info-subtle);\n}\n\n.Alert[data-color=\"warning\"] {\n --alert-base: var(--lea-palette-status-warning-base);\n --alert-subtle: var(--lea-palette-status-warning-subtle);\n}\n\n.Alert[data-color=\"error\"] {\n --alert-base: var(--lea-palette-status-error-base);\n --alert-subtle: var(--lea-palette-status-error-subtle);\n}\n\n.Alert[data-color=\"purple\"] {\n --alert-base: var(--lea-palette-purple-base);\n --alert-subtle: var(--lea-palette-purple-subtle);\n}\n\n.Alert[data-color=\"grey\"] {\n --alert-base: var(--lea-color-neutral-700);\n --alert-subtle: var(--lea-color-neutral-100);\n}\n\n/* Variants */\n\n.Alert[data-variant=\"standard\"] {\n background-color: var(--alert-subtle);\n}\n\n.Alert[data-variant=\"filled\"] {\n background-color: var(--alert-base);\n color: var(--lea-palette-text-contrast);\n}\n\n.Alert[data-variant=\"filled\"] .Icon,\n.Alert[data-variant=\"filled\"] .Close {\n color: var(--lea-palette-text-contrast);\n}\n\n.Alert[data-variant=\"outlined\"] {\n border: 1px solid var(--alert-base);\n background-color: transparent;\n}\n\n/* Sizes */\n\n.Alert[data-size=\"sm\"] {\n --alert-line: calc(var(--lea-font-size-sm) * 1.5);\n\n padding: calc(var(--lea-spacing) * 0.5) calc(var(--lea-spacing) * 1.5);\n font-size: var(--lea-font-size-sm);\n}\n\n.Alert[data-size=\"sm\"] .Layout,\n.Alert[data-size=\"sm\"].Layout {\n gap: var(--lea-spacing);\n}\n\n.Alert[data-size=\"sm\"] .Action {\n margin-block: calc(var(--lea-spacing) * -0.25);\n}\n\n/*\n * GlobalAlert: edge to edge, with the side padding coming from the inner\n * Container so the content lines up with the page.\n */\n\n.Alert[data-global] {\n width: 100%;\n padding-inline: 0;\n border-radius: 0;\n}\n\n.Alert[data-global][data-variant=\"outlined\"] {\n border-inline: 0;\n}\n\n.Layout[data-fluid] {\n max-width: none;\n}\n","\"use client\";\n\nimport { CircleAlert, CircleCheck, Info, TriangleAlert } from \"lucide-react\";\nimport type {\n ComponentPropsWithRef,\n ReactNode,\n SyntheticEvent,\n} from \"react\";\n\nimport { CloseButton } from \"../buttons/close-button\";\nimport styles from \"./alert.module.css\";\n\nexport type AlertSeverity = \"success\" | \"info\" | \"warning\" | \"error\";\nexport type AlertColor = AlertSeverity | \"purple\" | \"grey\";\nexport type AlertVariant = \"standard\" | \"filled\" | \"outlined\";\nexport type AlertSize = \"sm\" | \"lg\";\n\nexport type AlertProps = Omit<ComponentPropsWithRef<\"div\">, \"color\"> & {\n /**\n * Semantic meaning — picks the icon and how screen readers announce it.\n * @default \"success\", or \"info\" with a brand `color`\n */\n severity?: AlertSeverity;\n /**\n * Colour scheme. Defaults to the colour of `severity`. `\"purple\"` and\n * `\"grey\"` carry no status meaning.\n */\n color?: AlertColor;\n /**\n * `\"standard\"` is a tinted fill, `\"filled\"` a solid one, `\"outlined\"` a\n * border only.\n * @default \"standard\"\n */\n variant?: AlertVariant;\n /**\n * `\"sm\"` for tighter padding and smaller text.\n * @default \"lg\"\n */\n size?: AlertSize;\n /** Replaces the severity icon. Pass `false` to hide it. */\n icon?: ReactNode | false;\n /** Content for the end of the alert, e.g. a button. Replaces the close button. */\n action?: ReactNode;\n /** Renders a close button that calls this when pressed. */\n onClose?: (event: SyntheticEvent) => void;\n /** Accessible name of the close button. Defaults to a translated \"Close\". */\n closeLabel?: string;\n};\n\nconst brandColours: AlertColor[] = [\"purple\", \"grey\"];\n\nconst alertIcons: Record<AlertSeverity, ReactNode> = {\n success: <CircleCheck size=\"1em\" aria-hidden />,\n info: <Info size=\"1em\" aria-hidden />,\n warning: <TriangleAlert size=\"1em\" aria-hidden />,\n error: <CircleAlert size=\"1em\" aria-hidden />,\n};\n\n/**\n * Resolves the props shared by `Alert` and `GlobalAlert` into the root's\n * attributes and its inner markup. Internal — not exported from the package.\n */\nexport function resolveAlert({\n severity,\n color,\n variant = \"standard\",\n size = \"lg\",\n icon,\n action,\n onClose,\n closeLabel,\n role,\n children,\n ...rest\n}: AlertProps) {\n const resolvedSeverity: AlertSeverity =\n severity ?? (color && brandColours.includes(color) ? \"info\" : \"success\");\n\n const rootProps = {\n ...rest,\n role:\n role ??\n (resolvedSeverity === \"error\" || resolvedSeverity === \"warning\"\n ? \"alert\"\n : \"status\"),\n \"data-color\": color ?? resolvedSeverity,\n \"data-variant\": variant,\n \"data-size\": size,\n };\n\n const resolvedIcon = icon === undefined ? alertIcons[resolvedSeverity] : icon;\n const resolvedAction =\n action ??\n (onClose && (\n <CloseButton\n size=\"sm\"\n label={closeLabel}\n onClick={onClose}\n className={styles.Close}\n />\n ));\n\n const content = (\n <>\n {resolvedIcon !== false && resolvedIcon != null && (\n <div className={styles.Icon}>{resolvedIcon}</div>\n )}\n <div className={styles.Message}>{children}</div>\n {resolvedAction && <div className={styles.Action}>{resolvedAction}</div>}\n </>\n );\n\n return { rootProps, content };\n}\n","\"use client\";\n\nimport type { ComponentPropsWithRef } from \"react\";\n\nimport { type AlertProps, resolveAlert } from \"./alert-parts\";\nimport styles from \"./alert.module.css\";\n\nexport type {\n AlertColor,\n AlertProps,\n AlertSeverity,\n AlertSize,\n AlertVariant,\n} from \"./alert-parts\";\n\n/**\n * A message with Lea Bank's status colours. The ARIA `role` is derived from\n * `severity`: `error` / `warning` announce assertively (`role=\"alert\"`) while\n * `info` / `success` announce politely (`role=\"status\"`). Pass an explicit\n * `role` to override.\n *\n * With `onClose`, a close button is rendered with a translated accessible\n * name — override it per-instance with `closeLabel`.\n *\n * ```tsx\n * <Alert color=\"purple\" size=\"sm\">\n * Lånet forutsetter at du løser skulder for totalt 80 000 kr.\n * </Alert>\n * ```\n */\nexport function Alert({ className, ...props }: AlertProps) {\n const { rootProps, content } = resolveAlert(props);\n\n return (\n <div\n {...rootProps}\n className={[styles.Alert, styles.Layout, className]\n .filter(Boolean)\n .join(\" \")}\n >\n {content}\n </div>\n );\n}\n\nexport type AlertTitleProps = ComponentPropsWithRef<\"div\">;\n\n/** A heading above the alert's message. */\nexport function AlertTitle({ className, ...rest }: AlertTitleProps) {\n return (\n <div\n {...rest}\n className={[styles.Title, className].filter(Boolean).join(\" \")}\n />\n );\n}\n","/*\n * Design tokens come from src/theme/tokens.css, generated from src/theme/tokens\n * by `pnpm tokens:css`. It is a plain stylesheet rather than runtime-injected\n * CSS variables, so this component renders correctly without a provider.\n * `--lea-spacing` is the 0.5rem base unit, multiplied to match `spacing(n)`.\n */\n\n.Backdrop {\n position: fixed;\n z-index: 1300;\n background-color: rgba(15, 16, 16, 0.5);\n inset: 0;\n opacity: 1;\n transition: opacity var(--lea-duration-normal) var(--lea-easing-standard);\n}\n\n.Backdrop[data-starting-style],\n.Backdrop[data-ending-style] {\n opacity: 0;\n}\n\n.Viewport {\n position: fixed;\n z-index: 1300;\n display: flex;\n align-items: center;\n justify-content: center;\n padding: calc(var(--lea-spacing) * 2);\n inset: 0;\n /*\n * The viewport covers the window so the popup can be centred, but only the\n * popup should swallow clicks — presses that land here are outside presses\n * and must dismiss the dialog.\n */\n pointer-events: none;\n}\n\n.Popup {\n display: flex;\n overflow: hidden;\n width: 100%;\n max-height: 100%;\n flex-direction: column;\n border-radius: var(--lea-radius-4xl);\n background-color: var(--lea-palette-bg-base);\n box-shadow: var(--lea-shadow-xl);\n color: var(--lea-palette-text-base);\n opacity: 1;\n pointer-events: auto;\n transform: scale(1);\n transition:\n opacity var(--lea-duration-normal) var(--lea-easing-standard),\n transform var(--lea-duration-normal) var(--lea-easing-standard);\n}\n\n.Popup[data-starting-style],\n.Popup[data-ending-style] {\n opacity: 0;\n transform: scale(0.95);\n}\n\n.Popup[data-size=\"xs\"] {\n max-width: 27.75rem;\n}\n\n.Popup[data-size=\"sm\"] {\n max-width: 37.5rem;\n}\n\n.Popup[data-size=\"md\"] {\n max-width: 56.25rem;\n}\n\n.Popup[data-size=\"lg\"] {\n max-width: 75rem;\n}\n\n.Header {\n display: flex;\n flex-shrink: 0;\n align-items: flex-start;\n justify-content: space-between;\n gap: var(--lea-spacing);\n padding: calc(var(--lea-spacing) * 3) calc(var(--lea-spacing) * 3)\n calc(var(--lea-spacing) * 2);\n}\n\n.Title {\n margin: 0;\n color: var(--lea-palette-text-base);\n font-size: var(--lea-font-size-lg);\n font-weight: var(--lea-font-weight-semibold);\n line-height: 1.4;\n}\n\n.Description {\n margin: 0 0 calc(var(--lea-spacing) * 2);\n color: var(--lea-palette-text-subtle);\n}\n\n/*\n * Set when the description is the last thing in the body. A `:last-child`\n * selector would not do: body content is often a bare string, and text nodes\n * don't count as children.\n */\n.Description[data-last] {\n margin-bottom: 0;\n}\n\n.Content {\n overflow-y: auto;\n flex: 1;\n padding: 0 calc(var(--lea-spacing) * 3) calc(var(--lea-spacing) * 3);\n color: var(--lea-palette-text-base);\n}\n\n/* The footer's top padding takes over the gap, mirroring the header. */\n.Content:has(+ .Footer) {\n padding-bottom: 0;\n}\n\n.Footer {\n display: flex;\n flex-shrink: 0;\n flex-wrap: wrap;\n align-items: center;\n justify-content: flex-end;\n gap: var(--lea-spacing);\n padding: calc(var(--lea-spacing) * 2) calc(var(--lea-spacing) * 3)\n calc(var(--lea-spacing) * 2);\n background-color: var(--lea-palette-bg-base);\n}\n\n.CloseButton {\n display: inline-flex;\n width: 2.5rem;\n height: 2.5rem;\n flex-shrink: 0;\n align-items: center;\n justify-content: center;\n padding: 0;\n border: 2px solid var(--lea-palette-border-base);\n border-radius: var(--lea-radius-full);\n margin-inline-end: calc(var(--lea-spacing) * -0.5);\n background-color: transparent;\n color: var(--lea-palette-text-base);\n cursor: pointer;\n transition:\n border-color var(--lea-duration-emphasis) var(--lea-easing-spring),\n background-color var(--lea-duration-emphasis) var(--lea-easing-spring),\n color var(--lea-duration-emphasis) var(--lea-easing-spring);\n}\n\n@media (hover: hover) {\n .CloseButton:hover {\n border-color: var(--lea-palette-purple-base);\n background-color: var(--lea-palette-purple-base);\n color: var(--lea-palette-purple-contrast);\n }\n}\n\n.CloseButton:focus-visible {\n outline: 2px solid var(--lea-palette-text-base);\n outline-offset: 0.125rem;\n}\n\n/*\n * Fills the screen rather than floating as a card. `100dvh` follows the mobile\n * browser chrome as it collapses, and the safe-area inset keeps the content\n * clear of the home indicator.\n */\n@media (max-width: 599.95px) {\n .Viewport:has(.Popup[data-full-screen-on-mobile]) {\n padding: 0;\n }\n\n .Popup[data-full-screen-on-mobile] {\n width: 100vw;\n max-width: none;\n height: 100dvh;\n max-height: none;\n border-radius: 0;\n }\n\n .Popup[data-full-screen-on-mobile] .Content {\n padding-bottom: calc(\n var(--lea-spacing) * 3 + env(safe-area-inset-bottom)\n );\n }\n\n .Popup[data-full-screen-on-mobile] .Content:has(+ .Footer) {\n padding-bottom: 0;\n }\n\n .Popup[data-full-screen-on-mobile] .Footer {\n padding-bottom: calc(\n var(--lea-spacing) * 3 + env(safe-area-inset-bottom)\n );\n }\n}\n\n@media (prefers-reduced-motion: reduce) {\n .Backdrop,\n .Popup,\n .CloseButton {\n transition-duration: 0.01ms;\n }\n}\n","\"use client\";\n\nimport { Dialog as BaseDialog } from \"@base-ui/react/dialog\";\nimport { X } from \"lucide-react\";\nimport type { ComponentPropsWithRef } from \"react\";\n\nimport { mergeClassName } from \"../../utils/merge-class-name\";\nimport styles from \"./dialog.module.css\";\nimport { useCloseLabel } from \"./use-close-label\";\n\n/**\n * Maximum width of the popup. The names match the breakpoint scale the library\n * used before, so `size=\"xs\"` is still the compact confirm dialog.\n */\nexport type Size = \"xs\" | \"sm\" | \"md\" | \"lg\";\n\n/**\n * Groups all parts of the dialog and owns the open state. Renders no element\n * of its own. Control it with `open` + `onOpenChange`, or leave both off and\n * let a `Dialog.Trigger` drive it.\n */\nexport const Root = BaseDialog.Root;\nexport type RootProps<Payload = unknown> = BaseDialog.Root.Props<Payload>;\n\n/**\n * Opens the dialog. Renders a bare `<button>`, so pass a styled control\n * through `render` — `<Dialog.Trigger render={<Button />}>Open</Dialog.Trigger>`.\n */\nexport const Trigger = BaseDialog.Trigger;\nexport type TriggerProps<Payload = unknown> = BaseDialog.Trigger.Props<Payload>;\n\n/** Moves the backdrop and popup to the end of `<body>`. */\nexport const Portal = BaseDialog.Portal;\nexport type PortalProps = BaseDialog.Portal.Props;\n\nexport type BackdropProps = BaseDialog.Backdrop.Props;\n\n/** The dimmed overlay behind the popup. */\nexport function Backdrop({ className, ...rest }: BackdropProps) {\n return (\n <BaseDialog.Backdrop\n {...rest}\n className={mergeClassName(styles.Backdrop, className)}\n />\n );\n}\n\nexport type ViewportProps = BaseDialog.Viewport.Props;\n\n/** Centres the popup in the window and keeps a gutter at the screen edges. */\nexport function Viewport({ className, ...rest }: ViewportProps) {\n return (\n <BaseDialog.Viewport\n {...rest}\n className={mergeClassName(styles.Viewport, className)}\n />\n );\n}\n\nexport type PopupProps = BaseDialog.Popup.Props & {\n /**\n * Maximum width of the surface.\n * @default \"sm\"\n */\n size?: Size;\n /**\n * Fills the screen on narrow viewports (below 600px) instead of floating as\n * a card. Use it for flows that need the whole screen, such as a multi-step\n * form or a long consent list.\n */\n fullScreenOnMobile?: boolean;\n};\n\n/**\n * The dialog surface. Lays its children out in a column so a `Dialog.Content`\n * can scroll while the header stays put.\n */\nexport function Popup({\n size = \"sm\",\n fullScreenOnMobile,\n className,\n ...rest\n}: PopupProps) {\n return (\n <BaseDialog.Popup\n {...rest}\n data-size={size}\n data-full-screen-on-mobile={fullScreenOnMobile || undefined}\n className={mergeClassName(styles.Popup, className)}\n />\n );\n}\n\nexport type HeaderProps = ComponentPropsWithRef<\"div\">;\n\n/**\n * The title row. Anything after the `Dialog.Title` sits on the same line,\n * which is where `Dialog.CloseButton` belongs. Stays fixed while\n * `Dialog.Content` scrolls.\n */\nexport function Header({ className, ...rest }: HeaderProps) {\n return (\n <div\n {...rest}\n className={[styles.Header, className].filter(Boolean).join(\" \")}\n />\n );\n}\n\nexport type TitleProps = BaseDialog.Title.Props;\n\n/**\n * The heading. Base UI links it to the popup as the accessible name, so no id\n * wiring is needed.\n */\nexport function Title({ className, ...rest }: TitleProps) {\n return (\n <BaseDialog.Title\n {...rest}\n className={mergeClassName(styles.Title, className)}\n />\n );\n}\n\nexport type DescriptionProps = BaseDialog.Description.Props;\n\n/** Supporting text, linked to the popup as its accessible description. */\nexport function Description({ className, ...rest }: DescriptionProps) {\n return (\n <BaseDialog.Description\n {...rest}\n className={mergeClassName(styles.Description, className)}\n />\n );\n}\n\nexport type ContentProps = ComponentPropsWithRef<\"div\">;\n\n/** The body. Scrolls on its own once the popup runs out of height. */\nexport function Content({ className, ...rest }: ContentProps) {\n return (\n <div\n {...rest}\n className={[styles.Content, className].filter(Boolean).join(\" \")}\n />\n );\n}\n\nexport type FooterProps = ComponentPropsWithRef<\"div\">;\n\n/**\n * The action row, placed after `Dialog.Content`. Stays pinned to the bottom of\n * the popup while `Dialog.Content` scrolls, and lines its children up at the\n * end.\n */\nexport function Footer({ className, ...rest }: FooterProps) {\n return (\n <div\n {...rest}\n className={[styles.Footer, className].filter(Boolean).join(\" \")}\n />\n );\n}\n\n/**\n * Closes the dialog. Renders a bare `<button>` for text actions — use\n * `render` for a styled one: `<Dialog.Close render={<Button />}>Cancel</Dialog.Close>`.\n * For the X in the header corner, use `Dialog.CloseButton`.\n */\nexport const Close = BaseDialog.Close;\nexport type CloseProps = BaseDialog.Close.Props;\n\nexport type CloseButtonProps = Omit<\n BaseDialog.Close.Props,\n \"children\" | \"aria-label\"\n> & {\n /** Accessible name. Defaults to a translated \"Close\". */\n label?: string;\n};\n\n/**\n * The round X in the header corner. It renders its own icon and always has an\n * accessible name, so it cannot be built without one.\n */\nexport function CloseButton({ label, className, ...rest }: CloseButtonProps) {\n const t = useCloseLabel();\n\n return (\n <BaseDialog.Close\n {...rest}\n aria-label={label ?? t.close}\n className={mergeClassName(styles.CloseButton, className)}\n >\n <X size={20} aria-hidden />\n </BaseDialog.Close>\n );\n}\n","/*\n * Design tokens come from src/theme/tokens.css, generated from src/theme/tokens\n * by `pnpm tokens:css`. It is a plain stylesheet rather than runtime-injected\n * CSS variables, so this component renders correctly without a provider.\n * `--lea-spacing` is the 0.5rem base unit, multiplied to match `spacing(n)`.\n *\n * Positioning keys off `data-swipe-direction`, which Base UI sets on the popup\n * from the root's `swipeDirection` — the same value `Drawer.Root` derives from\n * `side`, so the panel can never sit on one edge and swipe towards another.\n */\n\n.Backdrop {\n position: fixed;\n z-index: 1300;\n background-color: rgba(15, 16, 16, 0.5);\n inset: 0;\n /* Fades in step with the swipe, so the panel feels attached to the finger. */\n opacity: calc(1 - var(--drawer-swipe-progress, 0));\n transition: opacity var(--lea-duration-normal) var(--lea-easing-standard);\n}\n\n.Backdrop[data-starting-style],\n.Backdrop[data-ending-style] {\n opacity: 0;\n}\n\n.Viewport {\n position: fixed;\n z-index: 1300;\n inset: 0;\n /* Only the panel should swallow clicks; presses elsewhere dismiss it. */\n pointer-events: none;\n}\n\n.Popup {\n position: absolute;\n display: flex;\n flex-direction: column;\n background-color: var(--lea-palette-bg-base);\n box-shadow: var(--lea-shadow-xl);\n color: var(--lea-palette-text-base);\n pointer-events: auto;\n transition: transform var(--lea-duration-normal) var(--lea-easing-standard);\n}\n\n.Popup[data-swipe-direction=\"left\"],\n.Popup[data-swipe-direction=\"right\"] {\n top: 0;\n width: min(var(--drawer-size, 22.5rem), 100vw);\n height: 100%;\n transform: translateX(var(--drawer-swipe-movement-x, 0px));\n}\n\n.Popup[data-swipe-direction=\"left\"] {\n left: 0;\n}\n\n.Popup[data-swipe-direction=\"right\"] {\n right: 0;\n}\n\n.Popup[data-swipe-direction=\"up\"],\n.Popup[data-swipe-direction=\"down\"] {\n left: 0;\n width: 100%;\n /* Sheets size to their content; `--drawer-size` caps them lower if needed. */\n max-height: var(--drawer-size, 90dvh);\n transform: translateY(\n calc(var(--drawer-snap-point-offset, 0px) + var(--drawer-swipe-movement-y, 0px))\n );\n}\n\n/* Sheets round the edge that faces the content, the way a card would. */\n.Popup[data-swipe-direction=\"up\"] {\n top: 0;\n border-radius: 0 0 var(--drawer-radius, var(--lea-radius-4xl))\n var(--drawer-radius, var(--lea-radius-4xl));\n}\n\n.Popup[data-swipe-direction=\"down\"] {\n bottom: 0;\n border-radius: var(--drawer-radius, var(--lea-radius-4xl))\n var(--drawer-radius, var(--lea-radius-4xl)) 0 0;\n padding-bottom: env(safe-area-inset-bottom);\n}\n\n.Popup[data-starting-style][data-swipe-direction=\"left\"],\n.Popup[data-ending-style][data-swipe-direction=\"left\"] {\n transform: translateX(-100%);\n}\n\n.Popup[data-starting-style][data-swipe-direction=\"right\"],\n.Popup[data-ending-style][data-swipe-direction=\"right\"] {\n transform: translateX(100%);\n}\n\n.Popup[data-starting-style][data-swipe-direction=\"up\"],\n.Popup[data-ending-style][data-swipe-direction=\"up\"] {\n transform: translateY(-100%);\n}\n\n.Popup[data-starting-style][data-swipe-direction=\"down\"],\n.Popup[data-ending-style][data-swipe-direction=\"down\"] {\n transform: translateY(100%);\n}\n\n/* A flick should settle faster than a slow drag; a live drag must not lag. */\n.Popup[data-ending-style],\n.Backdrop[data-ending-style] {\n transition-duration: calc(\n var(--drawer-swipe-strength, 1) * var(--lea-duration-normal)\n );\n}\n\n.Popup[data-swiping],\n.Backdrop[data-swiping] {\n transition-duration: 0ms;\n}\n\n.Handle {\n width: calc(var(--lea-spacing) * 5);\n height: calc(var(--lea-spacing) * 0.5);\n flex-shrink: 0;\n border-radius: var(--lea-radius-sm);\n margin: calc(var(--lea-spacing) * 1.5) auto calc(var(--lea-spacing) * 0.5);\n background-color: var(--lea-palette-border-base);\n}\n\n/* A top sheet is dragged upwards, so its handle belongs on the bottom edge. */\n.Popup[data-swipe-direction=\"up\"] .Handle {\n margin: calc(var(--lea-spacing) * 0.5) auto calc(var(--lea-spacing) * 1.5);\n}\n\n.Header {\n display: flex;\n flex-shrink: 0;\n align-items: flex-start;\n justify-content: space-between;\n gap: var(--lea-spacing);\n padding: calc(var(--lea-spacing) * 3) calc(var(--lea-spacing) * 3)\n calc(var(--lea-spacing) * 2);\n}\n\n.Title {\n margin: 0;\n color: var(--lea-palette-text-base);\n font-size: var(--lea-font-size-lg);\n font-weight: var(--lea-font-weight-semibold);\n line-height: 1.4;\n}\n\n.Description {\n margin: 0 0 calc(var(--lea-spacing) * 2);\n color: var(--lea-palette-text-subtle);\n}\n\n/*\n * Set when the description is the last thing in the body. A `:last-child`\n * selector would not do: body content is often a bare string, and text nodes\n * don't count as children.\n */\n.Description[data-last] {\n margin-bottom: 0;\n}\n\n.Content {\n overflow-y: auto;\n flex: 1;\n padding: 0 calc(var(--lea-spacing) * 3) calc(var(--lea-spacing) * 3);\n color: var(--lea-palette-text-base);\n}\n\n.CloseButton {\n display: inline-flex;\n width: 2.5rem;\n height: 2.5rem;\n flex-shrink: 0;\n align-items: center;\n justify-content: center;\n padding: 0;\n border: 2px solid var(--lea-palette-border-base);\n border-radius: var(--lea-radius-full);\n margin-inline-end: calc(var(--lea-spacing) * -0.5);\n background-color: transparent;\n color: var(--lea-palette-text-base);\n cursor: pointer;\n transition:\n border-color var(--lea-duration-emphasis) var(--lea-easing-spring),\n background-color var(--lea-duration-emphasis) var(--lea-easing-spring),\n color var(--lea-duration-emphasis) var(--lea-easing-spring);\n}\n\n@media (hover: hover) {\n .CloseButton:hover {\n border-color: var(--lea-palette-purple-base);\n background-color: var(--lea-palette-purple-base);\n color: var(--lea-palette-purple-contrast);\n }\n}\n\n.CloseButton:focus-visible {\n outline: 2px solid var(--lea-palette-text-base);\n outline-offset: 0.125rem;\n}\n\n@media (prefers-reduced-motion: reduce) {\n .Backdrop,\n .Popup,\n .CloseButton {\n transition-duration: 0.01ms;\n }\n}\n","\"use client\";\n\nimport { Drawer as BaseDrawer } from \"@base-ui/react/drawer\";\nimport { X } from \"lucide-react\";\nimport type { ComponentPropsWithRef } from \"react\";\n\nimport { mergeClassName } from \"../../utils/merge-class-name\";\nimport styles from \"./drawer.module.css\";\nimport { useCloseLabel } from \"./use-close-label\";\n\n/** Screen edge the panel slides in from. */\nexport type Side = \"left\" | \"right\" | \"top\" | \"bottom\";\n\n/**\n * The panel is dismissed by swiping it back towards the edge it came from, so\n * the gesture direction follows from the side.\n */\nconst SWIPE_DIRECTION = {\n left: \"left\",\n right: \"right\",\n top: \"up\",\n bottom: \"down\",\n} as const;\n\nexport type RootProps<Payload = unknown> = Omit<\n BaseDrawer.Root.Props<Payload>,\n \"swipeDirection\"\n> & {\n /**\n * Screen edge the panel slides in from. Also sets the swipe-to-dismiss\n * direction, so the two can never disagree.\n * @default \"right\"\n */\n side?: Side;\n};\n\n/**\n * Groups all parts of the drawer and owns the open state. Renders no element\n * of its own. Control it with `open` + `onOpenChange`, or leave both off and\n * let a `Drawer.Trigger` drive it.\n */\nexport function Root<Payload = unknown>({\n side = \"right\",\n ...rest\n}: RootProps<Payload>) {\n return <BaseDrawer.Root {...rest} swipeDirection={SWIPE_DIRECTION[side]} />;\n}\n\n/**\n * Opens the drawer. Renders a bare `<button>`, so pass a styled control\n * through `render` — `<Drawer.Trigger render={<Button />}>Open</Drawer.Trigger>`.\n */\nexport const Trigger = BaseDrawer.Trigger;\nexport type TriggerProps<Payload = unknown> = BaseDrawer.Trigger.Props<Payload>;\n\n/** Moves the backdrop and popup to the end of `<body>`. */\nexport const Portal = BaseDrawer.Portal;\nexport type PortalProps = BaseDrawer.Portal.Props;\n\nexport type BackdropProps = BaseDrawer.Backdrop.Props;\n\n/** The dimmed overlay behind the panel. Fades out as the panel is swiped away. */\nexport function Backdrop({ className, ...rest }: BackdropProps) {\n return (\n <BaseDrawer.Backdrop\n {...rest}\n className={mergeClassName(styles.Backdrop, className)}\n />\n );\n}\n\nexport type ViewportProps = BaseDrawer.Viewport.Props;\n\n/**\n * Positioning container for the panel. Also the element Base UI offsets when\n * the on-screen keyboard appears.\n */\nexport function Viewport({ className, ...rest }: ViewportProps) {\n return (\n <BaseDrawer.Viewport\n {...rest}\n className={mergeClassName(styles.Viewport, className)}\n />\n );\n}\n\nexport type PopupProps = BaseDrawer.Popup.Props;\n\n/**\n * The panel surface, pinned to the edge given by `side` on `Drawer.Root`.\n * Side panels are `min(22.5rem, 100vw)` wide and sheets are at most 90% of the\n * screen height; override either with the `--drawer-size` custom property.\n */\nexport function Popup({ className, ...rest }: PopupProps) {\n return (\n <BaseDrawer.Popup\n {...rest}\n className={mergeClassName(styles.Popup, className)}\n />\n );\n}\n\nexport type HandleProps = ComponentPropsWithRef<\"div\">;\n\n/**\n * The grab bar at the top of a bottom sheet. Decorative — the panel is\n * swipe-dismissable anywhere, so this is a hint rather than a control.\n */\nexport function Handle({ className, ...rest }: HandleProps) {\n return (\n <div\n {...rest}\n aria-hidden\n className={[styles.Handle, className].filter(Boolean).join(\" \")}\n />\n );\n}\n\nexport type HeaderProps = ComponentPropsWithRef<\"div\">;\n\n/**\n * The title row. Anything after the `Drawer.Title` sits on the same line,\n * which is where `Drawer.CloseButton` belongs. Stays fixed while\n * `Drawer.Content` scrolls.\n */\nexport function Header({ className, ...rest }: HeaderProps) {\n return (\n <div\n {...rest}\n className={[styles.Header, className].filter(Boolean).join(\" \")}\n />\n );\n}\n\nexport type TitleProps = BaseDrawer.Title.Props;\n\n/**\n * The heading. Base UI links it to the panel as the accessible name, so no id\n * wiring is needed.\n */\nexport function Title({ className, ...rest }: TitleProps) {\n return (\n <BaseDrawer.Title\n {...rest}\n className={mergeClassName(styles.Title, className)}\n />\n );\n}\n\nexport type DescriptionProps = BaseDrawer.Description.Props;\n\n/** Supporting text, linked to the panel as its accessible description. */\nexport function Description({ className, ...rest }: DescriptionProps) {\n return (\n <BaseDrawer.Description\n {...rest}\n className={mergeClassName(styles.Description, className)}\n />\n );\n}\n\nexport type ContentProps = BaseDrawer.Content.Props;\n\n/**\n * The body. Scrolls on its own once the panel runs out of height, and lets a\n * mouse select text inside it without starting a swipe.\n */\nexport function Content({ className, ...rest }: ContentProps) {\n return (\n <BaseDrawer.Content\n {...rest}\n className={mergeClassName(styles.Content, className)}\n />\n );\n}\n\n/**\n * Closes the drawer. Renders a bare `<button>` for text actions — use\n * `render` for a styled one: `<Drawer.Close render={<Button />}>Cancel</Drawer.Close>`.\n * For the X in the header corner, use `Drawer.CloseButton`.\n */\nexport const Close = BaseDrawer.Close;\nexport type CloseProps = BaseDrawer.Close.Props;\n\nexport type CloseButtonProps = Omit<\n BaseDrawer.Close.Props,\n \"children\" | \"aria-label\"\n> & {\n /** Accessible name. Defaults to a translated \"Close\". */\n label?: string;\n};\n\n/**\n * The round X in the header corner. It renders its own icon and always has an\n * accessible name, so it cannot be built without one.\n */\nexport function CloseButton({ label, className, ...rest }: CloseButtonProps) {\n const t = useCloseLabel();\n\n return (\n <BaseDrawer.Close\n {...rest}\n aria-label={label ?? t.close}\n className={mergeClassName(styles.CloseButton, className)}\n >\n <X size={20} aria-hidden />\n </BaseDrawer.Close>\n );\n}\n",".Container {\n box-sizing: border-box;\n width: 100%;\n max-width: var(--lea-breakpoint-lg);\n padding-inline: calc(var(--lea-spacing) * 2);\n margin-inline: auto;\n}\n\n.Container[data-size=\"sm\"] {\n max-width: var(--lea-breakpoint-sm);\n}\n\n.Container[data-size=\"md\"] {\n max-width: var(--lea-breakpoint-md);\n}\n\n.Container[data-size=\"xl\"] {\n max-width: var(--lea-breakpoint-xl);\n}\n\n@media (min-width: 600px) {\n .Container {\n padding-inline: calc(var(--lea-spacing) * 3);\n }\n}\n\n@media (min-width: 900px) {\n .Container {\n padding-inline: calc(var(--lea-spacing) * 4);\n }\n}\n","\"use client\";\n\nimport { useRender } from \"@base-ui/react/use-render\";\n\nimport type { Breakpoint } from \"../../theme/tokens/breakpoints\";\nimport { mergeClassName } from \"../../utils/merge-class-name\";\nimport styles from \"./container.module.css\";\n\nexport type ContainerSize = Exclude<Breakpoint, \"xs\">;\n\nexport type ContainerProps = Omit<useRender.ComponentProps<\"div\">, \"ref\"> & {\n /**\n * Maximum width, named after the breakpoint it matches: `\"md\"` stops\n * growing at the `md` breakpoint width.\n * @default \"lg\"\n */\n size?: ContainerSize;\n};\n\n/**\n * Centres page content, caps its width and keeps it clear of the screen edge.\n * The side padding grows with the viewport: `spacing(2)` on phones,\n * `spacing(3)` from `sm` and `spacing(4)` from `md`.\n *\n * ```tsx\n * <Container render={<main />}>\n * <Text variant=\"h1\">Mine lån</Text>\n * </Container>\n * ```\n */\nexport function Container({\n size = \"lg\",\n render,\n className,\n ...rest\n}: ContainerProps) {\n return useRender({\n render,\n props: {\n ...rest,\n \"data-size\": size,\n className: mergeClassName(styles.Container, className)({}),\n },\n });\n}\n","\"use client\";\n\nimport { Container } from \"../layout/container\";\nimport { type AlertProps, resolveAlert } from \"./alert-parts\";\nimport styles from \"./alert.module.css\";\n\nexport type GlobalAlertProps = AlertProps & {\n /**\n * Lets the content span the full width instead of stopping at the `lg`\n * breakpoint. The side padding stays.\n * @default false\n */\n fluid?: boolean;\n};\n\n/**\n * An `Alert` that spans the whole page width, for messages about the whole\n * page or session. Place it directly above or below `AppHeader`. It takes the\n * same props and styling as `Alert`, without the rounded corners, and its\n * content follows the `Container` breakpoints and side padding.\n *\n * ```tsx\n * <AppHeader />\n * <GlobalAlert severity=\"warning\" onClose={dismiss}>\n * <AlertTitle>Planned maintenance</AlertTitle>\n * Online banking is unavailable tonight from 22:00 to 23:00.\n * </GlobalAlert>\n * ```\n */\nexport function GlobalAlert({\n fluid = false,\n className,\n ...props\n}: GlobalAlertProps) {\n const { rootProps, content } = resolveAlert(props);\n\n return (\n <div\n {...rootProps}\n data-global=\"\"\n className={[styles.Alert, className].filter(Boolean).join(\" \")}\n >\n <Container className={styles.Layout} data-fluid={fluid || undefined}>\n {content}\n </Container>\n </div>\n );\n}\n","\"use client\";\n\nimport type { ReactNode } from \"react\";\n\nimport * as Dialog from \"./dialog\";\n\nexport type SimpleDialogProps = Omit<Dialog.RootProps, \"children\"> & {\n /** Heading. Becomes the dialog's accessible name. */\n title: ReactNode;\n /** Optional supporting text. Becomes the accessible description. */\n description?: ReactNode;\n /** Body content rendered below the title / description. */\n children?: ReactNode;\n /** Accessible name for the close button. Defaults to a translated \"Close\". */\n closeLabel?: string;\n /**\n * Maximum width of the surface.\n * @default \"sm\"\n */\n size?: Dialog.Size;\n /** Fills the screen below 600px instead of floating as a card. */\n fullScreenOnMobile?: boolean;\n /** Hide close button. */\n hideCloseButton?: boolean;\n};\n\n/**\n * The ready-made modal: pass `title`, an optional `description` and\n * `children`, and it renders the Lea chrome — a white, large-radius surface\n * over a dark overlay, a title row with a close button, and a scrollable body.\n *\n * Reach for `Dialog` (the parts) when you need a different layout.\n *\n * ```tsx\n * <SimpleDialog\n * open={open}\n * onOpenChange={setOpen}\n * title=\"Update your details\"\n * description=\"Keep your contact information up to date.\"\n * >\n * <TextField label=\"Phone\" />\n * </SimpleDialog>\n * ```\n */\nexport function SimpleDialog({\n title,\n description,\n children,\n closeLabel,\n size,\n fullScreenOnMobile,\n hideCloseButton,\n ...rest\n}: SimpleDialogProps) {\n return (\n <Dialog.Root {...rest}>\n <Dialog.Portal>\n <Dialog.Backdrop />\n <Dialog.Viewport>\n <Dialog.Popup size={size} fullScreenOnMobile={fullScreenOnMobile}>\n <Dialog.Header>\n <Dialog.Title>{title}</Dialog.Title>\n {!hideCloseButton && <Dialog.CloseButton label={closeLabel} />}\n </Dialog.Header>\n <Dialog.Content>\n {description != null && (\n <Dialog.Description data-last={children == null || undefined}>\n {description}\n </Dialog.Description>\n )}\n {children}\n </Dialog.Content>\n </Dialog.Popup>\n </Dialog.Viewport>\n </Dialog.Portal>\n </Dialog.Root>\n );\n}\n","\"use client\";\n\nimport type { ReactNode } from \"react\";\n\nimport * as Drawer from \"./drawer\";\n\nexport type SimpleDrawerProps = Omit<Drawer.RootProps, \"children\"> & {\n /** Heading. Becomes the drawer's accessible name. */\n title: ReactNode;\n /** Optional supporting text. Becomes the accessible description. */\n description?: ReactNode;\n /** Body content rendered below the title / description. */\n children?: ReactNode;\n /** Accessible name for the close button. Defaults to a translated \"Close\". */\n closeLabel?: string;\n};\n\n/**\n * The ready-made side panel: pass `title`, an optional `description` and\n * `children`, and it renders the Lea chrome — a white surface that slides in\n * from the edge over a dark overlay, a header row with a close button, and a\n * scrollable body. Swipe-to-dismiss comes for free, towards `side`.\n *\n * Bottom and top sheets (`side=\"bottom\"` / `\"top\"`) get a grab handle and\n * round the edge that faces the content.\n *\n * Reach for `Drawer` (the parts) when you need a different layout.\n *\n * ```tsx\n * <SimpleDrawer open={open} onOpenChange={setOpen} title=\"Filters\">\n * <FilterForm />\n * </SimpleDrawer>\n * ```\n */\nexport function SimpleDrawer({\n title,\n description,\n children,\n closeLabel,\n side = \"right\",\n ...rest\n}: SimpleDrawerProps) {\n return (\n <Drawer.Root {...rest} side={side}>\n <Drawer.Portal>\n <Drawer.Backdrop />\n <Drawer.Viewport>\n <Drawer.Popup>\n {/* The handle sits on the edge the sheet is dragged towards. */}\n {side === \"bottom\" && <Drawer.Handle />}\n <Drawer.Header>\n <Drawer.Title>{title}</Drawer.Title>\n <Drawer.CloseButton label={closeLabel} />\n </Drawer.Header>\n <Drawer.Content>\n {description != null && (\n <Drawer.Description data-last={children == null || undefined}>\n {description}\n </Drawer.Description>\n )}\n {children}\n </Drawer.Content>\n {side === \"top\" && <Drawer.Handle />}\n </Drawer.Popup>\n </Drawer.Viewport>\n </Drawer.Portal>\n </Drawer.Root>\n );\n}\n","// `Country` is owned by the hooks/country module and re-exported from the\n// package root via the hooks barrel. Validators import it from there directly so\n// the validation barrel does not produce an ambiguous duplicate `Country`\n// export at the package root.\n\n/**\n * Result of a validation check. `normalized` holds the canonical form of the\n * input (e.g. digits only, or E.164 phone) when the value is valid.\n */\nexport interface ValidationResult {\n valid: boolean;\n normalized?: string;\n}\n\nexport const invalid = (): ValidationResult => ({ valid: false });\n\nexport const valid = (normalized: string): ValidationResult => ({\n valid: true,\n normalized,\n});\n","import type { Country } from \"../hooks/country/countries\";\nimport { invalid, valid, type ValidationResult } from \"./types\";\n\n/**\n * Luhn (mod-10) checksum over a string of digits.\n */\nfunction passesLuhn(digits: string): boolean {\n let sum = 0;\n let double = digits.length % 2 === 0;\n\n for (const char of digits) {\n let value = Number(char);\n if (double) {\n value *= 2;\n if (value > 9) value -= 9;\n }\n sum += value;\n double = !double;\n }\n\n return sum % 10 === 0;\n}\n\n/**\n * Swedish personnummer. Accepts 10 or 12 digit forms (with or without\n * separators) and validates the trailing Luhn check digit.\n */\nexport function isValidSwedishNationalId(value: string): boolean {\n let digits = value.replace(/\\D/g, \"\");\n\n if (digits.length === 12) {\n digits = digits.slice(2);\n }\n\n if (digits.length !== 10) {\n return false;\n }\n\n const month = Number(digits.slice(2, 4));\n const day = Number(digits.slice(4, 6));\n\n if (month < 1 || month > 12 || day < 1 || day > 31) {\n return false;\n }\n\n return passesLuhn(digits);\n}\n\nconst FINNISH_CHECK_CHARACTERS = \"0123456789ABCDEFHJKLMNPRSTUVWXY\";\n\n/**\n * Finnish henkilötunnus (HETU). Validates structure, date, century marker and\n * the mod-31 check character.\n */\nexport function isValidFinnishNationalId(value: string): boolean {\n const normalized = value.replace(/\\s/g, \"\").toUpperCase();\n\n if (!/^\\d{6}[+\\-A]\\d{3}[0-9A-Y]$/.test(normalized)) {\n return false;\n }\n\n const day = Number(normalized.slice(0, 2));\n const month = Number(normalized.slice(2, 4));\n const yearShort = Number(normalized.slice(4, 6));\n const centurySign = normalized[6];\n\n const centuryBase =\n centurySign === \"+\"\n ? 1800\n : centurySign === \"-\"\n ? 1900\n : centurySign === \"A\"\n ? 2000\n : null;\n\n if (centuryBase === null) {\n return false;\n }\n\n const year = centuryBase + yearShort;\n const date = new Date(year, month - 1, day);\n\n if (\n date.getFullYear() !== year ||\n date.getMonth() !== month - 1 ||\n date.getDate() !== day\n ) {\n return false;\n }\n\n const checksumNumber = Number(\n `${normalized.slice(0, 6)}${normalized.slice(7, 10)}`,\n );\n\n return normalized[10] === FINNISH_CHECK_CHARACTERS[checksumNumber % 31];\n}\n\nconst NO_WEIGHTS_1 = [3, 7, 6, 1, 8, 9, 4, 5, 2];\nconst NO_WEIGHTS_2 = [5, 4, 3, 2, 7, 6, 5, 4, 3, 2];\n\nfunction norwegianControlDigit(digits: number[], weights: number[]): number {\n const sum = weights.reduce((acc, weight, i) => acc + weight * digits[i], 0);\n const remainder = sum % 11;\n return remainder === 0 ? 0 : 11 - remainder;\n}\n\n/**\n * Norwegian fødselsnummer. 11 digits with two mod-11 control digits.\n */\nexport function isValidNorwegianNationalId(value: string): boolean {\n const digits = value.replace(/\\D/g, \"\");\n\n if (digits.length !== 11) {\n return false;\n }\n\n const numbers = digits.split(\"\").map(Number);\n const day = Number(digits.slice(0, 2));\n const month = Number(digits.slice(2, 4));\n\n // Accounts for D-numbers (day + 40) and H-numbers (month + 40).\n const realDay = day > 40 ? day - 40 : day;\n const realMonth = month > 40 ? month - 40 : month;\n\n if (realMonth < 1 || realMonth > 12 || realDay < 1 || realDay > 31) {\n return false;\n }\n\n const k1 = norwegianControlDigit(numbers.slice(0, 9), NO_WEIGHTS_1);\n if (k1 === 11 || k1 !== numbers[9]) {\n return false;\n }\n\n const k2 = norwegianControlDigit(numbers.slice(0, 10), NO_WEIGHTS_2);\n if (k2 === 11 || k2 !== numbers[10]) {\n return false;\n }\n\n return true;\n}\n\nconst SPANISH_DNI_LETTERS = \"TRWAGMYFPDXBNJZSQVHLCKE\";\nconst SPANISH_NIE_PREFIX: Record<string, string> = { X: \"0\", Y: \"1\", Z: \"2\" };\n\n/**\n * Spanish DNI / NIE. Validates the control letter (mod-23). NIE prefixes\n * (X/Y/Z) are mapped to their numeric equivalents before the check.\n */\nexport function isValidSpanishNationalId(value: string): boolean {\n const normalized = value.replace(/[\\s-]/g, \"\").toUpperCase();\n\n if (!/^[XYZ]?\\d{7,8}[A-Z]$/.test(normalized)) {\n return false;\n }\n\n const letter = normalized.slice(-1);\n let numberPart = normalized.slice(0, -1);\n\n const prefix = numberPart[0];\n if (prefix in SPANISH_NIE_PREFIX) {\n numberPart = SPANISH_NIE_PREFIX[prefix] + numberPart.slice(1);\n }\n\n if (numberPart.length !== 8) {\n return false;\n }\n\n return SPANISH_DNI_LETTERS[Number(numberPart) % 23] === letter;\n}\n\nconst NATIONAL_ID_VALIDATORS: Record<Country, (value: string) => boolean> = {\n SE: isValidSwedishNationalId,\n FI: isValidFinnishNationalId,\n NO: isValidNorwegianNationalId,\n ES: isValidSpanishNationalId,\n};\n\n/**\n * Validates a national identity number for the given country.\n */\nexport function isValidNationalId(country: Country, value: string): boolean {\n return NATIONAL_ID_VALIDATORS[country](value);\n}\n\n/**\n * Validates a national identity number and returns the normalized (uppercased,\n * separator-free) value when valid.\n */\nexport function validateNationalId(\n country: Country,\n value: string,\n): ValidationResult {\n if (!isValidNationalId(country, value)) {\n return invalid();\n }\n\n return valid(value.replace(/[\\s-]/g, \"\").toUpperCase());\n}\n","import {\n parsePhoneNumberFromString,\n type CountryCode,\n} from \"libphonenumber-js\";\nimport { invalid, valid, type ValidationResult } from \"./types\";\n\nexport type { CountryCode };\n\n/**\n * Validates a phone number for the given country, delegating to\n * `libphonenumber-js` so every country's rules stay accurate and maintained.\n *\n * Accepts national format (with or without a leading trunk `0`) and\n * international format (`+CC` / `00CC`). On success, `normalized` holds the\n * canonical E.164 form (e.g. `+358401234567`).\n */\nexport function validatePhoneNumber(\n country: CountryCode,\n value: string,\n): ValidationResult {\n // Strip all whitespace so the display grouping (e.g. \"400 12 345\") never\n // reaches the parser; validation runs on the bare number.\n const cleaned = value.replace(/\\s/g, \"\");\n if (cleaned === \"\") {\n return invalid();\n }\n\n const parsed = parsePhoneNumberFromString(cleaned, country);\n if (!parsed || !parsed.isValid()) {\n return invalid();\n }\n\n return valid(parsed.number);\n}\n\n/**\n * Boolean convenience wrapper around {@link validatePhoneNumber}.\n */\nexport function isValidPhoneNumber(\n country: CountryCode,\n value: string,\n): boolean {\n return validatePhoneNumber(country, value).valid;\n}\n","export const modulo97 = (digits: string): number => {\n let remainder = 0;\n\n for (const digit of digits) {\n remainder = (remainder * 10 + Number(digit)) % 97;\n }\n\n return remainder;\n};\n\nexport const replaceLatinLettersWithNumbers = (value: string): string =>\n value.replace(/[A-Z]/g, (char) => String(char.charCodeAt(0) - 55));\n","import type { Country } from \"../hooks/country/countries\";\nimport { modulo97, replaceLatinLettersWithNumbers } from \"./modulo-97\";\nimport { invalid, valid, type ValidationResult } from \"./types\";\n\nconst IBAN_LENGTHS: Record<Country, number> = {\n SE: 24,\n FI: 18,\n NO: 15,\n ES: 24,\n};\n\nfunction normalize(value: string): string {\n return value.replace(/[\\s-]/g, \"\").toUpperCase();\n}\n\n/**\n * Generic IBAN check: structure, country length and the ISO 7064 mod-97\n * checksum.\n */\nexport function isValidIban(value: string, country?: Country): boolean {\n const iban = normalize(value);\n\n if (!/^[A-Z]{2}\\d{2}[A-Z0-9]+$/.test(iban)) {\n return false;\n }\n\n const ibanCountry = iban.slice(0, 2) as Country;\n\n if (country && ibanCountry !== country) {\n return false;\n }\n\n const expectedLength = IBAN_LENGTHS[ibanCountry];\n if (expectedLength && iban.length !== expectedLength) {\n return false;\n }\n\n const rearranged = iban.slice(4) + iban.slice(0, 4);\n return modulo97(replaceLatinLettersWithNumbers(rearranged)) === 1;\n}\n\nconst NO_ACCOUNT_WEIGHTS = [5, 4, 3, 2, 7, 6, 5, 4, 3, 2];\n\n/**\n * Norwegian kontonummer: 11 digits with a mod-11 control digit.\n */\nexport function isValidNorwegianAccount(value: string): boolean {\n const digits = value.replace(/\\D/g, \"\");\n\n if (digits.length !== 11) {\n return false;\n }\n\n const numbers = digits.split(\"\").map(Number);\n const sum = NO_ACCOUNT_WEIGHTS.reduce(\n (acc, weight, i) => acc + weight * numbers[i],\n 0,\n );\n const remainder = sum % 11;\n const control = remainder === 0 ? 0 : 11 - remainder;\n\n return control < 10 && control === numbers[10];\n}\n\n/**\n * Swedish clearing + account number. Bank-specific checksums vary, so this is a\n * structural check: a 4-5 digit clearing number followed by a 6-10 digit\n * account number.\n */\nexport function isValidSwedishAccount(value: string): boolean {\n const digits = value.replace(/\\D/g, \"\");\n return digits.length >= 10 && digits.length <= 15;\n}\n\n/**\n * Validates a bank account number for the given country.\n *\n * - **FI / ES** require a valid IBAN.\n * - **NO** accepts a domestic kontonummer or a Norwegian IBAN.\n * - **SE** accepts a domestic clearing + account number or a Swedish IBAN.\n */\nexport function validateBankAccount(\n country: Country,\n value: string,\n): ValidationResult {\n const normalized = normalize(value);\n const looksLikeIban = /^[A-Z]{2}\\d{2}/.test(normalized);\n\n switch (country) {\n case \"FI\":\n case \"ES\":\n return isValidIban(normalized, country) ? valid(normalized) : invalid();\n case \"NO\":\n if (looksLikeIban) {\n return isValidIban(normalized, \"NO\") ? valid(normalized) : invalid();\n }\n return isValidNorwegianAccount(normalized)\n ? valid(normalized.replace(/\\D/g, \"\"))\n : invalid();\n case \"SE\":\n if (looksLikeIban) {\n return isValidIban(normalized, \"SE\") ? valid(normalized) : invalid();\n }\n return isValidSwedishAccount(normalized)\n ? valid(normalized.replace(/\\D/g, \"\"))\n : invalid();\n }\n}\n\n/**\n * Boolean convenience wrapper around {@link validateBankAccount}.\n */\nexport function isValidBankAccount(country: Country, value: string): boolean {\n return validateBankAccount(country, value).valid;\n}\n","import { modulo97 } from \"./modulo-97\";\nimport { invalid, valid, type ValidationResult } from \"./types\";\n\nconst normalize = (value: string): string =>\n value.replace(/\\s/g, \"\").toUpperCase();\n\n/** Finnish domestic reference: 3–19 base digits and a 7-3-1 check digit. */\nexport function isValidFinnishDomesticReference(value: string): boolean {\n const reference = normalize(value);\n if (!/^[1-9]\\d{3,19}$/.test(reference)) {\n return false;\n }\n\n const base = reference.slice(0, -1);\n const checkDigit = Number(reference.at(-1));\n const weights = [7, 3, 1];\n let sum = 0;\n\n for (let index = base.length - 1, weightIndex = 0; index >= 0; index--) {\n sum += Number(base[index]) * weights[weightIndex % weights.length];\n weightIndex++;\n }\n\n return (10 - (sum % 10)) % 10 === checkDigit;\n}\n\n/** ISO 11649 RF reference using Finland's 4–20 digit reference length. */\nexport function isValidFinnishRfReference(value: string): boolean {\n const reference = normalize(value);\n if (!/^RF\\d{2}[1-9]\\d{3,19}$/.test(reference)) {\n return false;\n }\n\n const rearranged = `${reference.slice(4)}2715${reference.slice(2, 4)}`;\n return modulo97(rearranged) === 1;\n}\n\n/** Validates either a Finnish domestic or ISO 11649 RF reference. */\nexport function validateFinnishReference(value: string): ValidationResult {\n const normalized = normalize(value);\n\n return isValidFinnishDomesticReference(normalized) ||\n isValidFinnishRfReference(normalized)\n ? valid(normalized)\n : invalid();\n}\n\n/** Boolean convenience wrapper around {@link validateFinnishReference}. */\nexport function isValidFinnishReference(value: string): boolean {\n return validateFinnishReference(value).valid;\n}\n","import { invalid, valid, type ValidationResult } from \"./types\";\n\n// Pragmatic RFC-5322-ish pattern: good enough for UI validation without the\n// false negatives of an overly strict expression.\nconst EMAIL_PATTERN =\n /^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)+$/;\n\n/**\n * Common consumer email domains across the Nordics and Spain, used to power the\n * `@`-triggered autocomplete dropdown.\n */\nexport const COMMON_EMAIL_DOMAINS: readonly string[] = [\n \"gmail.com\",\n \"outlook.com\",\n \"hotmail.com\",\n \"icloud.com\",\n \"yahoo.com\",\n \"live.com\",\n \"live.se\",\n \"live.no\",\n \"hotmail.se\",\n \"hotmail.no\",\n \"telia.com\",\n \"online.no\",\n \"telenor.no\",\n \"elisanet.fi\",\n \"suomi24.fi\",\n \"telia.se\",\n \"comhem.se\",\n];\n\n/**\n * Validates an email address and returns the lowercased value when valid.\n */\nexport function validateEmail(value: string): ValidationResult {\n const trimmed = value.trim();\n\n if (!EMAIL_PATTERN.test(trimmed)) {\n return invalid();\n }\n\n const atIndex = trimmed.lastIndexOf(\"@\");\n if (atIndex >= 0) {\n const domain = trimmed.slice(atIndex + 1).toLowerCase();\n if (domain.endsWith(\".con\")) {\n return invalid();\n }\n }\n\n return valid(trimmed.toLowerCase());\n}\n\n/**\n * Boolean convenience wrapper around {@link validateEmail}.\n */\nexport function isValidEmail(value: string): boolean {\n return validateEmail(value).valid;\n}\n\n/**\n * Given the current email input, returns a list of completed email suggestions\n * based on common domains. Suggestions only appear once an `@` has been typed,\n * and are filtered by whatever partial domain follows it.\n *\n * @example\n * getEmailDomainSuggestions(\"alice@\") // → [\"alice@gmail.com\", ...]\n * getEmailDomainSuggestions(\"alice@gm\") // → [\"alice@gmail.com\"]\n */\nexport function getEmailDomainSuggestions(\n value: string,\n domains: readonly string[] = COMMON_EMAIL_DOMAINS,\n): string[] {\n const atIndex = value.indexOf(\"@\");\n\n if (atIndex < 1) {\n return [];\n }\n\n const localPart = value.slice(0, atIndex);\n const domainPart = value.slice(atIndex + 1).toLowerCase();\n\n // Don't suggest once a complete domain has been typed.\n if (domainPart.includes(\".\") && domains.includes(domainPart)) {\n return [];\n }\n\n return domains\n .filter((domain) => domain.startsWith(domainPart))\n .map((domain) => `${localPart}@${domain}`);\n}\n","import { createContext, useContext } from \"react\";\n\n/**\n * Ids shared between a `FormControl` and its label / control / helper text so\n * they stay wired together for assistive technology without the consumer ever\n * writing `htmlFor` or `aria-describedby` by hand.\n */\nexport interface FormFieldIds {\n /** Id of the focusable control (input / select). */\n control: string;\n /** Id of the label element. */\n label: string;\n /** Id of the helper text element. */\n helperText: string;\n}\n\nexport interface FormFieldContextValue {\n ids: FormFieldIds;\n /** Whether a `FormHelperText` is currently rendered, so the control knows to link it. */\n hasHelperText: boolean;\n /** Called by `FormHelperText` on mount / unmount to register its presence. */\n setHasHelperText: (present: boolean) => void;\n /**\n * Whether the control currently holds a value that should float the label\n * even when a start adornment is present (e.g. multi-select chips). A plain\n * leading icon leaves this `false` so it doesn't float the label on its own.\n */\n hasValue: boolean;\n /** Called by a value-bearing control to keep `hasValue` in sync. */\n setHasValue: (present: boolean) => void;\n}\n\nconst FormFieldContext = createContext<FormFieldContextValue | null>(null);\n\nexport const FormFieldProvider = FormFieldContext.Provider;\n\n/**\n * Reads the field context provided by the surrounding `FormControl`. Returns\n * `null` when a control is rendered outside our `FormControl`, which lets a\n * standalone control provision its own wrapper and ids.\n */\nexport const useFormField = (): FormFieldContextValue | null =>\n useContext(FormFieldContext);\n","import {\n FormHelperText as MuiFormHelperText,\n type FormHelperTextProps,\n} from \"@mui/material\";\nimport { useEffect } from \"react\";\nimport { useFormField } from \"./form-control-context\";\n\nexport type { FormHelperTextProps };\n\n/**\n * Supplementary / error text for a field. When rendered inside our\n * `FormControl` it takes the helper-text id from context and registers its\n * presence, so the control links to it via `aria-describedby` automatically.\n * Pass `error` to render it in the error colour.\n */\nexport const FormHelperText = (props: FormHelperTextProps) => {\n const ctx = useFormField();\n const setHasHelperText = ctx?.setHasHelperText;\n\n useEffect(() => {\n setHasHelperText?.(true);\n return () => setHasHelperText?.(false);\n }, [setHasHelperText]);\n\n return <MuiFormHelperText id={ctx?.ids.helperText} {...props} />;\n};\n","import {\n InputLabel as MuiInputLabel,\n useFormControl,\n type InputLabelProps,\n} from \"@mui/material\";\nimport { useFormField } from \".\";\n\nexport type { InputLabelProps };\n\n/**\n * Floating label for a field. When rendered inside our `FormControl` it links\n * itself to the control automatically via `htmlFor` / `id`, so the consumer\n * never has to wire them. MUI appends the required asterisk and reads focus /\n * error / required state from the surrounding `FormControl` on its own.\n */\nexport const InputLabel = (props: InputLabelProps) => {\n const ctx = useFormField();\n const formControl = useFormControl();\n\n // MUI force-shrinks the label whenever a start adornment is present. We don't\n // want the label to float just because of a leading icon — only on focus, when\n // the field has a value, or when a value-bearing adornment (e.g. multi-select\n // chips) reports itself via `hasValue` — so it stays in its placeholder spot\n // beside a plain icon until the user interacts.\n const shrink = formControl?.adornedStart\n ? Boolean(formControl.focused || formControl.filled || ctx?.hasValue)\n : undefined;\n\n return (\n <MuiInputLabel\n id={ctx?.ids.label}\n htmlFor={ctx?.ids.control}\n shrink={shrink}\n {...props}\n />\n );\n};\n","import { createTranslation } from \"../../i18n\";\n\n/**\n * Translated labels for the searchable selects built on MUI's `Autocomplete`\n * (`Autocomplete`, `AutocompleteField`, `EmailInput`, and the country picker in\n * `PhoneNumberInput`). MUI's own defaults are English, so these are applied for\n * every language. Consumers can still override any of them per-instance with\n * MUI's `noOptionsText` / `loadingText` / `openText` / `closeText` / `clearText`.\n */\nexport const useAutocompleteLabels = createTranslation({\n noOptions: {\n no: \"Ingen alternativer\",\n se: \"Inga alternativ\",\n fi: \"Ei vaihtoehtoja\",\n es: \"Sin opciones\",\n },\n loading: {\n no: \"Laster…\",\n se: \"Laddar…\",\n fi: \"Ladataan…\",\n es: \"Cargando…\",\n },\n open: { no: \"Åpne\", se: \"Öppna\", fi: \"Avaa\", es: \"Abrir\" },\n close: { no: \"Lukk\", se: \"Stäng\", fi: \"Sulje\", es: \"Cerrar\" },\n clear: { no: \"Tøm\", se: \"Rensa\", fi: \"Tyhjennä\", es: \"Borrar\" },\n});\n\n/**\n * The same labels mapped onto MUI's `Autocomplete` prop names, ready to spread\n * before `...rest` so a consumer-supplied value still wins.\n */\nexport const useAutocompleteTextProps = () => {\n const t = useAutocompleteLabels();\n\n return {\n noOptionsText: t.noOptions,\n loadingText: t.loading,\n openText: t.open,\n closeText: t.close,\n clearText: t.clear,\n };\n};\n","import {\n Autocomplete as MuiAutocomplete,\n OutlinedInput,\n type AutocompleteRenderInputParams,\n type AutocompleteProps as MuiAutocompleteProps,\n} from \"@mui/material\";\nimport {\n forwardRef,\n useEffect,\n useMemo,\n useState,\n type ReactNode,\n} from \"react\";\nimport {\n COMMON_EMAIL_DOMAINS,\n getEmailDomainSuggestions,\n} from \"../../validation\";\nimport { Chip } from \"../data-display\";\nimport { FormControl, useFormField } from \".\";\nimport { FormHelperText } from \"./form-control/form-helper-text\";\nimport { InputLabel } from \"./input-label\";\nimport type { SelectOption } from \"./select\";\nimport { useAutocompleteTextProps } from \"./use-autocomplete-labels\";\n\ntype AutocompleteOption = SelectOption | string;\n\n/** MUI props we forward untouched (free-solo so both modes type-check). */\ntype ForwardedMuiProps = Omit<\n MuiAutocompleteProps<AutocompleteOption, false, false, true>,\n | \"ref\"\n | \"renderInput\"\n | \"renderValue\"\n | \"options\"\n | \"value\"\n | \"defaultValue\"\n | \"onChange\"\n | \"onInputChange\"\n | \"inputValue\"\n | \"freeSolo\"\n | \"multiple\"\n | \"getOptionLabel\"\n | \"getOptionDisabled\"\n | \"isOptionEqualToValue\"\n | \"filterOptions\"\n>;\n\ntype AutocompleteBaseProps = ForwardedMuiProps & {\n /** Floating label. Rendered as an `InputLabel` and linked automatically. */\n label?: ReactNode;\n /** Helper / error text shown below the control and linked via `aria-describedby`. */\n helperText?: ReactNode;\n /** Searchable options. Ignored in `email` mode, where suggestions are derived from the input. */\n options?: SelectOption[];\n /** Puts the control in an error state. */\n error?: boolean;\n /** Marks the control as required. */\n required?: boolean;\n /** Placeholder shown in the text input. */\n placeholder?: string;\n};\n\ntype AutocompleteSingleProps = {\n /** Enable selecting multiple values. Omit (or `false`) for single-select. */\n multiple?: false;\n /** Selected value (controlled). */\n value?: string;\n /** Initial value (uncontrolled). */\n defaultValue?: string;\n /** Called with the next string value. */\n onChange?: (value: string) => void;\n /**\n * Email mode: lets the user type freely and, once they type `@`, suggests\n * completions from common providers (gmail, outlook, …).\n */\n email?: boolean;\n /** Domains offered in `email` mode. @default COMMON_EMAIL_DOMAINS */\n domains?: readonly string[];\n /** Maximum number of email suggestions to show. @default 6 */\n maxSuggestions?: number;\n};\n\ntype AutocompleteMultipleProps = {\n /** Enable selecting multiple values, rendered as removable chips. */\n multiple: true;\n /** Currently selected values (controlled). */\n value?: string[];\n /** Initially selected values (uncontrolled). */\n defaultValue?: string[];\n /** Called with the next array of selected values. */\n onChange?: (value: string[]) => void;\n /** Minimum number of values that must stay selected. @default 1 */\n min?: number;\n /** Maximum number of values that can be selected. Unlimited when omitted. */\n max?: number;\n};\n\nexport type AutocompleteProps = AutocompleteBaseProps &\n (AutocompleteSingleProps | AutocompleteMultipleProps);\n\nconst optionLabel = (option: AutocompleteOption) =>\n typeof option === \"string\" ? option : option.label;\n\ntype ModeControlProps = {\n /** Wired `id` from the surrounding `FormControl` context. */\n controlId?: string;\n /** `aria-describedby` target, present only when helper text exists. */\n describedBy?: string;\n};\n\ntype SingleControlProps = AutocompleteBaseProps &\n AutocompleteSingleProps &\n ModeControlProps;\n\nconst SingleAutocompleteControl = forwardRef<\n HTMLDivElement,\n SingleControlProps\n>(function SingleAutocompleteControl(\n {\n controlId,\n describedBy,\n options = [],\n value,\n defaultValue = \"\",\n onChange,\n error,\n placeholder,\n email = false,\n domains = COMMON_EMAIL_DOMAINS,\n maxSuggestions = 6,\n ...rest\n },\n ref,\n) {\n const labels = useAutocompleteTextProps();\n const isControlled = value !== undefined;\n const [internal, setInternal] = useState(defaultValue);\n const current = isControlled ? value : internal;\n\n const commit = (next: string) => {\n if (!isControlled) setInternal(next);\n onChange?.(next);\n };\n\n const emailSuggestions = useMemo(\n () =>\n email\n ? getEmailDomainSuggestions(current, domains).slice(0, maxSuggestions)\n : [],\n [email, current, domains, maxSuggestions],\n );\n\n const selectedOption = useMemo(\n () => options.find((option) => option.value === current) ?? null,\n [options, current],\n );\n\n const renderInput = (params: AutocompleteRenderInputParams) => (\n <OutlinedInput\n {...params.slotProps.input}\n fullWidth\n placeholder={placeholder}\n error={error}\n type={email ? \"email\" : undefined}\n inputProps={{\n ...params.slotProps.htmlInput,\n \"aria-describedby\": describedBy,\n }}\n />\n );\n\n const shared: Partial<\n MuiAutocompleteProps<AutocompleteOption, false, false, true>\n > = {\n id: controlId,\n getOptionLabel: optionLabel,\n ...labels,\n ...rest,\n };\n\n if (email) {\n return (\n <MuiAutocomplete<AutocompleteOption, false, false, true>\n {...shared}\n ref={ref}\n renderInput={renderInput}\n freeSolo\n options={emailSuggestions}\n inputValue={current}\n onInputChange={(_event, nextInput) => commit(nextInput)}\n // Suggestions are already filtered by the input, so don't filter twice.\n filterOptions={(list) => list}\n />\n );\n }\n\n return (\n <MuiAutocomplete<AutocompleteOption, false, false, true>\n {...shared}\n ref={ref}\n renderInput={renderInput}\n options={options}\n value={selectedOption}\n isOptionEqualToValue={(option, val) =>\n typeof option !== \"string\" &&\n typeof val !== \"string\" &&\n option.value === val.value\n }\n onChange={(_event, next) =>\n commit(next && typeof next !== \"string\" ? next.value : (next ?? \"\"))\n }\n />\n );\n});\n\ntype MultipleControlProps = AutocompleteBaseProps &\n AutocompleteMultipleProps &\n ModeControlProps;\n\nconst MultipleAutocompleteControl = forwardRef<\n HTMLDivElement,\n MultipleControlProps\n>(function MultipleAutocompleteControl(\n {\n controlId,\n describedBy,\n options = [],\n value,\n defaultValue = [],\n onChange,\n error,\n placeholder,\n disabled,\n min = 1,\n max,\n multiple,\n ...rest\n },\n ref,\n) {\n const ctx = useFormField();\n const labels = useAutocompleteTextProps();\n const isControlled = value !== undefined;\n const [internal, setInternal] = useState<string[]>(defaultValue);\n const selected = isControlled ? value : internal;\n\n // Chips render as a start adornment, which alone wouldn't float the label.\n // Report the selection so the label shrinks while values are present.\n const setHasValue = ctx?.setHasValue;\n useEffect(() => {\n setHasValue?.(selected.length > 0);\n }, [setHasValue, selected.length]);\n useEffect(() => () => setHasValue?.(false), [setHasValue]);\n\n const selectedOptions = useMemo(\n () =>\n selected\n .map((v) => options.find((option) => option.value === v))\n .filter((option): option is SelectOption => option !== undefined),\n [selected, options],\n );\n\n const atMax = max !== undefined && selected.length >= max;\n\n const commit = (next: string[]) => {\n if (!isControlled) setInternal(next);\n onChange?.(next);\n };\n\n const renderInput = (params: AutocompleteRenderInputParams) => (\n <OutlinedInput\n {...params.slotProps.input}\n fullWidth\n placeholder={placeholder}\n error={error}\n inputProps={{\n ...params.slotProps.htmlInput,\n \"aria-describedby\": describedBy,\n }}\n />\n );\n\n // The forwarded MUI props are typed against the single-mode generic; they're\n // structurally compatible with multiple mode, so narrow them here.\n const shared: Partial<\n MuiAutocompleteProps<AutocompleteOption, true, boolean, false>\n > = {\n id: controlId,\n getOptionLabel: optionLabel,\n ...labels,\n ...(rest as Partial<\n MuiAutocompleteProps<AutocompleteOption, true, boolean, false>\n >),\n };\n\n return (\n <MuiAutocomplete<AutocompleteOption, true, boolean, false>\n {...shared}\n ref={ref}\n multiple={multiple}\n disabled={disabled}\n disableCloseOnSelect\n // Clearing would empty the selection, which breaks `min`, so hide the\n // clear-all affordance whenever a minimum is enforced.\n disableClearable={min > 0}\n renderInput={renderInput}\n options={options}\n value={selectedOptions}\n getOptionDisabled={(option) =>\n atMax && typeof option !== \"string\" && !selected.includes(option.value)\n }\n isOptionEqualToValue={(option, val) =>\n typeof option !== \"string\" &&\n typeof val !== \"string\" &&\n option.value === val.value\n }\n renderValue={(items, getItemProps) =>\n items.map((option, index) => {\n const { key, onDelete, ...itemProps } = getItemProps({ index });\n const canDelete = !disabled && selected.length > min;\n return (\n <Chip\n key={key}\n size=\"small\"\n label={optionLabel(option)}\n onDelete={canDelete ? onDelete : undefined}\n {...itemProps}\n />\n );\n })\n }\n onChange={(_event, next) => {\n const nextValues = next\n .filter(\n (option): option is SelectOption => typeof option !== \"string\",\n )\n .map((option) => option.value);\n // Guard the lower bound: covers chip delete and any stray change.\n if (nextValues.length < min) return;\n commit(nextValues);\n }}\n />\n );\n});\n\n/**\n * The bare autocomplete, wired to the surrounding `FormControl` via context.\n * Links `aria-describedby` only when a `FormHelperText` is actually present, so\n * it never points at a missing id. Dispatches to the single- or multiple-select\n * implementation so each keeps its own hooks and value type.\n */\nconst AutocompleteControl = forwardRef<HTMLDivElement, AutocompleteProps>(\n function AutocompleteControl(props, ref) {\n const ctx = useFormField();\n const controlId = ctx?.ids.control;\n const describedBy = ctx?.hasHelperText ? ctx.ids.helperText : undefined;\n\n if (props.multiple) {\n return (\n <MultipleAutocompleteControl\n {...props}\n ref={ref}\n controlId={controlId}\n describedBy={describedBy}\n />\n );\n }\n\n return (\n <SingleAutocompleteControl\n {...props}\n ref={ref}\n controlId={controlId}\n describedBy={describedBy}\n />\n );\n },\n);\n\n/**\n * Searchable select built on MUI's `Autocomplete`.\n *\n * Works two ways:\n * - **Standalone (all-in-one):** pass `label` / `helperText` and `options` and\n * it renders its own `FormControl`, label and helper text, generating and\n * wiring all ids for you.\n * - **Composed:** drop it inside a `FormControl` next to `InputLabel` /\n * `FormHelperText` and it picks up the shared ids from context.\n *\n * Pass `multiple` to select several values at once, shown as removable chips and\n * bounded by `min` (default 1) and `max`. Pass `email` (single mode only) to\n * turn it into an email field that suggests common domains once the user types\n * `@` — the same autocomplete behaviour, driven by free text.\n */\nexport const Autocomplete = forwardRef<HTMLDivElement, AutocompleteProps>(\n function Autocomplete(\n { label, helperText, error, required, disabled, id, ...rest },\n ref,\n ) {\n const ctx = useFormField();\n\n const control = (\n <AutocompleteControl\n ref={ref}\n error={error}\n disabled={disabled}\n {...rest}\n />\n );\n\n if (ctx) {\n // Already inside a FormControl: render only the control.\n return control;\n }\n\n // Standalone: provide our own FormControl so the ids get generated and wired.\n return (\n <FormControl\n id={id}\n error={error}\n required={required}\n disabled={disabled}\n >\n {label != null && <InputLabel>{label}</InputLabel>}\n {control}\n {helperText != null && (\n <FormHelperText error={error}>{helperText}</FormHelperText>\n )}\n </FormControl>\n );\n },\n);\n","import {\n Checkbox as MuiCheckbox,\n type CheckboxProps as MuiCheckboxProps,\n} from \"@mui/material\";\nimport { forwardRef } from \"react\";\n\nexport type CheckboxProps = Omit<MuiCheckboxProps, \"color\" | \"size\">;\n/**\n * Checkbox built on MUI's `Checkbox`, styled by the global theme\n * (`checkbox.theme.tsx`). Kept composite — pair it with `FormControlLabel` for a\n * label instead of forwarding label / typography props:\n *\n * ```tsx\n * <FormControlLabel control={<Checkbox />} label=\"Label\" />\n * ```\n */\nexport const Checkbox = forwardRef<HTMLButtonElement, CheckboxProps>(\n function Checkbox(props, ref) {\n return (\n <MuiCheckbox\n ref={ref}\n icon={checkboxBox}\n checkedIcon={checkboxBox}\n {...props}\n />\n );\n },\n);\n\nconst checkboxBox = (\n <span className=\"lea-checkbox-box\" aria-hidden>\n <svg className=\"lea-checkbox-check\" viewBox=\"0 0 24 24\">\n <path\n d=\"M5 12.5l4.5 4.5L19 7\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth={3}\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n pathLength={1}\n />\n </svg>\n </span>\n);\n","import { createTranslation } from \"../../../i18n\";\n\n/**\n * Translated labels for `CalendarHeader`: the prev/next month button names and\n * the month-year label's \"switch to year/day view\" suffix. Consumers can\n * override any of these per-instance via `DatePicker`'s `calendarHeaderLabels`\n * prop.\n */\nexport const useCalendarHeaderLabels = createTranslation({\n previousMonth: { no: \"Forrige måned\", se: \"Föregående månad\", fi: \"Edellinen kuukausi\", es: \"Mes anterior\" },\n nextMonth: { no: \"Neste måned\", se: \"Nästa månad\", fi: \"Seuraava kuukausi\", es: \"Mes siguiente\" },\n switchToYearView: { no: \"bytt til årsvisning\", se: \"byt till årsvy\", fi: \"vaihda vuosinäkymään\", es: \"cambiar a vista de año\" },\n switchToDayView: { no: \"bytt til datovisning\", se: \"byt till datumvy\", fi: \"vaihda päivänäkymään\", es: \"cambiar a vista de fecha\" },\n});\n\nexport type CalendarHeaderLabels = Partial<ReturnType<typeof useCalendarHeaderLabels>>;\n","import { focusVisibleStyles } from \"@/theme/utils\";\nimport Box from \"@mui/material/Box\";\nimport IconButton from \"@mui/material/IconButton\";\nimport { usePickerAdapter } from \"@mui/x-date-pickers/hooks\";\nimport { type PickersCalendarHeaderProps } from \"@mui/x-date-pickers/PickersCalendarHeader\";\nimport { ChevronDown, ChevronLeft, ChevronRight } from \"lucide-react\";\nimport {\n useCalendarHeaderLabels,\n type CalendarHeaderLabels,\n} from \"./use-calendar-header-labels\";\n\nconst cap = (s: string) => s.charAt(0).toUpperCase() + s.slice(1);\n\nconst chevronButtonSx = {\n width: 40,\n height: 40,\n border: \"1px solid\",\n borderColor: \"border.base\",\n color: \"text.base\",\n \"&:hover\": { backgroundColor: \"bg.subtle\" },\n \"&.Mui-disabled\": { opacity: 0.45, color: \"text.base\" },\n} as const;\n\n/**\n * Replaces MUI's default calendar header for the day picker with the Lea Bank\n * layout: a previous / next month chevron on each side and a centered, clickable\n * month-year label (with a caret) that switches to the year view. The chevrons\n * are muted at the `minDate` / `maxDate` bounds. Month navigation is only shown\n * while the day grid is visible; in the year view only the label remains.\n */\nexport function CalendarHeader({\n currentMonth,\n onMonthChange,\n onViewChange,\n view,\n minDate,\n maxDate,\n disabled,\n labels,\n}: PickersCalendarHeaderProps & { labels?: CalendarHeaderLabels }) {\n const adapter = usePickerAdapter();\n const t = useCalendarHeaderLabels();\n const l = { ...t, ...labels };\n\n const isDayView = view === \"day\";\n const prevMuted =\n !!disabled ||\n (minDate != null && !adapter.isAfter(currentMonth, adapter.startOfMonth(minDate)));\n const nextMuted =\n !!disabled ||\n (maxDate != null &&\n !adapter.isBefore(\n adapter.startOfMonth(currentMonth),\n adapter.startOfMonth(maxDate),\n ));\n\n const label = `${cap(adapter.formatByString(currentMonth, \"LLLL\"))} ${adapter.getYear(\n currentMonth,\n )}`;\n const switchLabel = `${label}, ${\n isDayView ? l.switchToYearView : l.switchToDayView\n }`;\n\n return (\n <Box\n sx={{\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"space-between\",\n gap: 1,\n px: 0.5,\n pb: 1,\n }}\n >\n {isDayView ? (\n <IconButton\n aria-label={l.previousMonth}\n disabled={prevMuted}\n onClick={() => onMonthChange(adapter.addMonths(currentMonth, -1))}\n sx={chevronButtonSx}\n >\n <ChevronLeft size={20} aria-hidden />\n </IconButton>\n ) : (\n <Box sx={{ width: 40, height: 40 }} />\n )}\n\n <Box\n component=\"button\"\n type=\"button\"\n aria-label={switchLabel}\n disabled={!!disabled}\n onClick={() => onViewChange?.(isDayView ? \"year\" : \"day\")}\n sx={{\n display: \"inline-flex\",\n alignItems: \"center\",\n gap: 0.75,\n px: 1,\n py: 0.5,\n border: \"none\",\n borderRadius: 2,\n background: \"transparent\",\n cursor: \"pointer\",\n fontFamily: \"inherit\",\n fontSize: \"1.0625rem\",\n fontWeight: \"fontWeightMedium\",\n color: \"text.base\",\n \"&:hover\": { backgroundColor: \"bg.subtle\" },\n \"&:disabled\": { cursor: \"default\", opacity: 0.45 },\n ...focusVisibleStyles,\n }}\n >\n {label}\n <Box\n component=\"span\"\n sx={{\n display: \"inline-flex\",\n color: \"purple.base\",\n transition: \"transform .15s\",\n transform: isDayView ? \"none\" : \"rotate(180deg)\",\n }}\n >\n <ChevronDown size={16} aria-hidden />\n </Box>\n </Box>\n\n {isDayView ? (\n <IconButton\n aria-label={l.nextMonth}\n disabled={nextMuted}\n onClick={() => onMonthChange(adapter.addMonths(currentMonth, 1))}\n sx={chevronButtonSx}\n >\n <ChevronRight size={20} aria-hidden />\n </IconButton>\n ) : (\n <Box sx={{ width: 40, height: 40 }} />\n )}\n </Box>\n );\n}\n","/*\n * The picker sheet is rounder than the default drawer. There is no 24px step\n * in src/theme/tokens/shape.ts, so the value is set through the drawer's\n * `--drawer-radius` custom property rather than overriding `border-radius`,\n * which the drawer sets with a more specific selector.\n */\n.Popup {\n --drawer-radius: 1.5rem;\n}\n","import Box from \"@mui/material/Box\";\nimport Typography from \"@mui/material/Typography\";\nimport { type ReactNode } from \"react\";\n\nexport type DrawerToolbarProps = {\n /** Small uppercase context label shown above the title. */\n eyebrow?: ReactNode;\n /** Drawer heading. */\n title?: ReactNode;\n /** id set on the title so the drawer dialog can reference it via `aria-labelledby`. */\n titleId?: string;\n /** Set by MUI's layout; when true the toolbar must not render. */\n hidden?: boolean;\n};\n\n/**\n * Replaces the default `DatePickerToolbar`. Renders the Lea Bank drawer header:\n * an optional purple uppercase eyebrow and a large title. Both are supplied by\n * `DatePicker` through `slotProps.toolbar`.\n */\nexport function DrawerToolbar({ eyebrow, title, titleId, hidden }: DrawerToolbarProps) {\n if (hidden) return null;\n\n return (\n <Box sx={{ px: 3, pt: 1, pb: 1.5 }}>\n {eyebrow != null && (\n <Typography\n component=\"p\"\n sx={{\n color: \"text.accent\",\n fontWeight: \"fontWeightBold\",\n textTransform: \"uppercase\",\n letterSpacing: \"0.06em\",\n fontSize: \"0.8125rem\",\n mb: 0.5,\n }}\n >\n {eyebrow}\n </Typography>\n )}\n {title != null && (\n <Typography\n component=\"h2\"\n id={titleId}\n sx={{ color: \"text.base\", fontWeight: \"fontWeightMedium\", fontSize: \"1.75rem\" }}\n >\n {title}\n </Typography>\n )}\n </Box>\n );\n}\n","import { createTranslation } from \"../../../i18n\";\n\n/**\n * Translated labels for `ViewToggle`: the month/year segment labels and the\n * `role=\"group\"` accessible name. Consumers can override any of these\n * per-instance via `DatePicker`'s `viewToggleLabels` prop.\n */\nexport const useViewToggleLabels = createTranslation({\n month: { no: \"Måned\", se: \"Månad\", fi: \"Kuukausi\", es: \"Mes\" },\n year: { no: \"År\", se: \"År\", fi: \"Vuosi\", es: \"Año\" },\n selectView: { no: \"Velg visning\", se: \"Välj vy\", fi: \"Valitse näkymä\", es: \"Seleccionar vista\" },\n});\n\nexport type ViewToggleLabels = Partial<ReturnType<typeof useViewToggleLabels>>;\n","import { focusVisibleStyles } from \"@/theme/utils\";\nimport Box from \"@mui/material/Box\";\nimport {\n useViewToggleLabels,\n type ViewToggleLabels,\n} from \"./use-view-toggle-labels\";\n\nexport type ToggleView = \"month\" | \"year\";\nexport type MonthYearOrder = \"month-year\" | \"year-month\";\n\nconst getSegments = (\n order: MonthYearOrder,\n labels: Record<\"month\" | \"year\", string>,\n): { view: ToggleView; label: string }[] => {\n const month = { view: \"month\" as const, label: labels.month };\n const year = { view: \"year\" as const, label: labels.year };\n return order === \"year-month\" ? [year, month] : [month, year];\n};\n\nexport type ViewToggleProps = {\n /** The currently active view. */\n currentView: ToggleView;\n /** Called with the view the user switched to. */\n onViewChange: (view: ToggleView) => void;\n /** Order of month and year segments. Default: \"month-year\" */\n order?: MonthYearOrder;\n /** Override the built-in translated labels per-instance. */\n labels?: ViewToggleLabels;\n};\n\n/**\n * Segmented control for the month/year-only picker. Shows two pill segments,\n * month first then year, with the active segment raised on a white pill. Used as\n * the header of the month/year `viewRenderers`; switching segments changes the\n * picker view. Each segment is a toggle button exposing `aria-pressed`, grouped\n * under a labelled `role=\"group\"`.\n */\nexport function ViewToggle({\n currentView,\n onViewChange,\n order = \"month-year\",\n labels,\n}: ViewToggleProps) {\n const t = useViewToggleLabels();\n const l = { ...t, ...labels };\n const segments = getSegments(order, l);\n return (\n <Box\n role=\"group\"\n aria-label={l.selectView}\n sx={{\n display: \"flex\",\n gap: 0.5,\n p: 0.5,\n mb: 1,\n borderRadius: \"999px\",\n backgroundColor: \"bg.subtle\",\n }}\n >\n {segments.map(({ view, label }) => {\n const active = view === currentView;\n return (\n <Box\n key={view}\n component=\"button\"\n type=\"button\"\n aria-pressed={active}\n onClick={() => onViewChange(view)}\n sx={{\n flex: 1,\n minHeight: 40,\n border: \"none\",\n borderRadius: \"999px\",\n cursor: \"pointer\",\n fontFamily: \"inherit\",\n fontSize: \"0.9375rem\",\n fontWeight: \"fontWeightMedium\",\n backgroundColor: active ? \"bg.base\" : \"transparent\",\n color: active ? \"text.base\" : \"text.subtle\",\n boxShadow: active ? \"0px 1px 3px rgba(0, 0, 0, 0.12)\" : \"none\",\n transition: \"background-color .15s, color .15s\",\n \"&:hover\": {\n color: \"text.base\",\n },\n ...focusVisibleStyles,\n }}\n >\n {label}\n </Box>\n );\n })}\n </Box>\n );\n}\n","import { type DatePickerProps } from \"@mui/x-date-pickers/DatePicker\";\nimport { type DateViewRendererProps } from \"@mui/x-date-pickers/dateViewRenderers\";\nimport { usePickerActionsContext } from \"@mui/x-date-pickers/hooks\";\nimport { type DateView } from \"@mui/x-date-pickers/models\";\nimport { MonthCalendar } from \"@mui/x-date-pickers/MonthCalendar\";\nimport { YearCalendar } from \"@mui/x-date-pickers/YearCalendar\";\nimport { type MonthYearOrder, ViewToggle } from \"./view-toggle\";\nimport { type ViewToggleLabels } from \"./use-view-toggle-labels\";\n\ntype RendererProps = DateViewRendererProps<DateView>;\n\n/**\n * Factory function that creates `viewRenderers` for the month/year-only picker.\n * The day view is intentionally absent (that mode uses MUI's standard `DateCalendar`);\n * these only drive the `views={[\"year\", \"month\"]}` configuration with the Måned / År toggle\n * and a month to year drill. Supports configurable order via `monthYearOrder`.\n */\nexport const createDateViewRenderers = (\n order: MonthYearOrder = \"month-year\",\n labels?: ViewToggleLabels,\n): DatePickerProps[\"viewRenderers\"] => {\n const isYearFirst = order === \"year-month\";\n\n /**\n * Month view of the month/year-only picker: the segmented toggle above MUI's\n * `MonthCalendar`. Behavior depends on `order`:\n * - month-first: intermediate step, advances to year view\n * - year-first: final step, commits and closes\n */\n const MonthView = (props: RendererProps) => {\n const actions = usePickerActionsContext();\n return (\n <div>\n <ViewToggle\n currentView=\"month\"\n onViewChange={(view) => actions.setView(view)}\n order={order}\n labels={labels}\n />\n <MonthCalendar\n value={props.value ?? null}\n referenceDate={props.referenceDate}\n minDate={props.minDate}\n maxDate={props.maxDate}\n disableFuture={props.disableFuture}\n disablePast={props.disablePast}\n shouldDisableMonth={props.shouldDisableMonth}\n timezone={props.timezone}\n onChange={(date) => {\n if (isYearFirst) {\n // In year-first mode, month is the final step\n actions.setValue(date, { changeImportance: \"accept\" });\n } else {\n // In month-first mode, month is intermediate, advance to year\n actions.setValue(date, { changeImportance: \"set\" });\n actions.setView(\"year\");\n }\n }}\n />\n </div>\n );\n };\n\n /**\n * Year view of the month/year-only picker. Behavior depends on `order`:\n * - month-first: final step, commits and closes\n * - year-first: intermediate step, advances to month view\n */\n const YearView = (props: RendererProps) => {\n const actions = usePickerActionsContext();\n return (\n <div>\n <ViewToggle\n currentView=\"year\"\n onViewChange={(view) => actions.setView(view)}\n order={order}\n labels={labels}\n />\n <YearCalendar\n value={props.value ?? null}\n referenceDate={props.referenceDate}\n minDate={props.minDate}\n maxDate={props.maxDate}\n disableFuture={props.disableFuture}\n disablePast={props.disablePast}\n shouldDisableYear={props.shouldDisableYear}\n timezone={props.timezone}\n onChange={(date) => {\n if (isYearFirst) {\n // In year-first mode, year is intermediate, advance to month\n actions.setValue(date, { changeImportance: \"set\" });\n actions.setView(\"month\");\n } else {\n // In month-first mode, year is the final step\n actions.setValue(date, { changeImportance: \"accept\" });\n }\n }}\n />\n </div>\n );\n };\n\n return {\n month: (props) => <MonthView {...props} />,\n year: (props) => <YearView {...props} />,\n };\n};\n","import { createTranslation } from \"../../../i18n\";\n\n/**\n * Translated default titles for `DatePicker`'s mobile drawer header, used when\n * the `title` prop is omitted.\n */\nexport const useDatePickerTitleLabels = createTranslation({\n selectDate: { no: \"Velg dato\", se: \"Välj datum\", fi: \"Valitse päivä\", es: \"Seleccionar fecha\" },\n selectMonthYear: { no: \"Velg måned og år\", se: \"Välj månad och år\", fi: \"Valitse kuukausi ja vuosi\", es: \"Seleccionar mes y año\" },\n});\n","import { type DialogProps } from \"@mui/material/Dialog\";\nimport { type PopperProps } from \"@mui/material/Popper\";\nimport { useTheme } from \"@mui/material/styles\";\nimport useMediaQuery from \"@mui/material/useMediaQuery\";\nimport { AdapterDateFns } from \"@mui/x-date-pickers/AdapterDateFns\";\nimport {\n DatePicker as MuiDatePicker,\n type DatePickerProps as MuiDatePickerProps,\n} from \"@mui/x-date-pickers/DatePicker\";\nimport { LocalizationProvider } from \"@mui/x-date-pickers/LocalizationProvider\";\nimport { esES, fiFI, nbNO, svSE } from \"@mui/x-date-pickers/locales\";\nimport { format, type Locale } from \"date-fns\";\nimport { es, fi, nb, sv } from \"date-fns/locale\";\nimport { CalendarSearch } from \"lucide-react\";\nimport { forwardRef, useMemo, type ReactNode } from \"react\";\nimport { useLanguage, type Language } from \"../../../i18n\";\nimport * as Drawer from \"../../feedback/drawer\";\nimport { CalendarHeader } from \"./calendar-header\";\nimport sheetStyles from \"./datepicker-sheet.module.css\";\nimport { DrawerToolbar } from \"./drawer-toolbar\";\nimport { createDateViewRenderers } from \"./view-renderers\";\nimport { type MonthYearOrder } from \"./view-toggle\";\nimport { type ViewToggleLabels } from \"./use-view-toggle-labels\";\nimport { type CalendarHeaderLabels } from \"./use-calendar-header-labels\";\nimport { useDatePickerTitleLabels } from \"./use-datepicker-title-labels\";\n\nexport { type ViewToggleLabels, type CalendarHeaderLabels };\n\ntype Slots = NonNullable<MuiDatePickerProps[\"slots\"]>;\n\nconst DEFAULT_VIEWS = [\"year\", \"month\", \"day\"] as const;\n\n// Maps the provider language to a `date-fns` locale, so month names and weekday\n// formatting follow the single `language` prop unless `adapterLocale` overrides.\nconst LOCALE_FOR_LANGUAGE: Record<Language, Locale> = {\n no: nb,\n se: sv,\n fi: fi,\n es: es,\n};\n\n// MUI X ships translations for the picker chrome (\"Velg dato\", \"Forrige\n// måned\", \"Avbryt\", …), which otherwise falls back to English.\nconst PICKER_TEXT: Record<Language, typeof nbNO> = {\n no: nbNO,\n se: svSE,\n fi: fiFI,\n es: esES,\n};\n\nconst localeTextFor = (language: Language) =>\n PICKER_TEXT[language].components.MuiLocalizationProvider.defaultProps\n .localeText;\n\nconst OpenPickerIcon = () => <CalendarSearch size={20} aria-hidden />;\n\n// Lowercase two-letter weekday labels to match the design, from the resolved\n// locale rather than a fixed array (`nb` is unchanged: sø ma ti on to fr lø).\nconst weekdayFormatter = (locale: Locale) => (date: Date) =>\n format(date, \"EEEEEE\", { locale }).toLowerCase();\n\n/**\n * Sizes the desktop popover to the trigger field's width, so the calendar always\n * lines up with the input (rather than sizing to the calendar's own content).\n */\nconst sameWidthAsInput: NonNullable<PopperProps[\"modifiers\"]>[number] = {\n name: \"sameWidth\",\n enabled: true,\n phase: \"beforeWrite\",\n requires: [\"computeStyles\"],\n fn: ({ state }) => {\n state.styles.popper.width = `${state.rects.reference.width}px`;\n },\n effect: ({ state }) => {\n const reference = state.elements.reference as HTMLElement;\n state.elements.popper.style.width = `${reference.offsetWidth}px`;\n },\n};\n\n/**\n * Renders the mobile views inside a bottom sheet with the Lea Bank chrome\n * (rounded top corners + grab handle) instead of MUI's default modal `Dialog`.\n * The picker's `dialog` slot is called with `Dialog` props, so we adapt them to\n * the drawer's `open` / `onOpenChange` pair. MUI passes the generated dialog\n * name via `slotProps.paper[\"aria-labelledby\"]` (pointing at the toolbar title\n * id), so we forward it onto the popup (the `role=\"dialog\"` element) to give\n * the sheet an accessible name.\n */\nfunction DrawerDialog({ open, onClose, children, slotProps }: DialogProps) {\n const forwardedPaper =\n typeof slotProps?.paper === \"object\" ? slotProps.paper : undefined;\n const ariaLabelledby = (\n forwardedPaper as { \"aria-labelledby\"?: string } | undefined\n )?.[\"aria-labelledby\"];\n\n return (\n <Drawer.Root\n side=\"bottom\"\n open={open}\n onOpenChange={(nextOpen, eventDetails) => {\n if (nextOpen) return;\n // MUI X's handler ignores both arguments, but the reason is mapped so\n // the slot still honours the `DialogProps` contract.\n onClose?.(\n eventDetails.event,\n eventDetails.reason === \"outside-press\"\n ? \"backdropClick\"\n : \"escapeKeyDown\",\n );\n }}\n >\n <Drawer.Portal>\n <Drawer.Backdrop />\n <Drawer.Viewport>\n <Drawer.Popup\n aria-labelledby={ariaLabelledby}\n className={sheetStyles.Popup}\n >\n <Drawer.Handle />\n {children}\n </Drawer.Popup>\n </Drawer.Viewport>\n </Drawer.Portal>\n </Drawer.Root>\n );\n}\n\nexport type DatePickerProps = MuiDatePickerProps & {\n /** Helper / error text shown below the control and linked via `aria-describedby`. */\n helperText?: ReactNode;\n /** Puts the control in an error state and styles the helper text accordingly. */\n error?: boolean;\n /** Marks the control as required. */\n required?: boolean;\n /**\n * `date-fns` locale used by the internal `LocalizationProvider`. Defaults to\n * the `LeaProvider` language (`no`->`nb`, `se`->`sv`, `fi`->`fi`, `es`->`es`);\n * set this to override.\n */\n adapterLocale?: Locale;\n /** Small uppercase context label shown above the drawer title on mobile. */\n eyebrow?: ReactNode;\n /** Drawer heading on mobile. Defaults from `views` (\"Velg dato\" or \"Velg måned og år\"). */\n title?: ReactNode;\n /** Order of month and year in the month/year picker. Default: \"month-year\" */\n monthYearOrder?: MonthYearOrder;\n /**\n * Override the month/year toggle's translated labels (`month`, `year`,\n * `selectView`) per-instance. Only used by the month/year picker\n * (`views={[\"year\", \"month\"]}`).\n */\n viewToggleLabels?: ViewToggleLabels;\n /**\n * Override the day calendar header's translated labels (`previousMonth`,\n * `nextMonth`, `switchToYearView`, `switchToDayView`) per-instance. Only\n * used by the day picker (default `views`).\n */\n calendarHeaderLabels?: CalendarHeaderLabels;\n};\n\n/**\n * DatePicker built on MUI's responsive `DatePicker` (`@mui/x-date-pickers`),\n * styled to the Lea Bank design.\n *\n * Two calendar designs, chosen by `views`:\n * - **Day picker** (default): MUI's `DateCalendar` day grid with a centered Lea\n * Bank header (prev/next month chevrons either side of a clickable month-year\n * label that switches to the year list) and lowercase Monday-first weekdays.\n * - **Month/year picker** (`views={[\"year\", \"month\"]}`): a Måned / År segmented\n * toggle above the month / year grids. Control the order via `monthYearOrder`:\n * \"month-year\" (default) or \"year-month\" (for Sweden and other locales).\n * Opens on the first view and drills through to the second.\n *\n * - **Desktop:** a compact popover (\"dropdown\").\n * - **Mobile:** a bottom `Drawer` with an `eyebrow` + `title` header. The switch\n * happens at `theme.breakpoints.up(\"sm\")` by default; override with\n * `desktopModeMediaQuery`.\n *\n * Selecting a value commits immediately (`closeOnSelect`) in both modes.\n * Configure which views are shown via `views` (e.g. `views={[\"year\", \"month\"]}`).\n * The trigger is the picker's accessible field,\n * themed to match the library's other inputs (see `date-picker.theme.ts`), and a\n * `LocalizationProvider` + `AdapterDateFns` are bundled in (locale follows the\n * `LeaProvider` language, defaulting to Norwegian `nb`; set `adapterLocale` to\n * override). MUI X's own texts (the open-picker button, month navigation,\n * action bar) come from its bundled locale pack for that language — override\n * them per-instance with `localeText`.\n */\nexport const DatePicker = forwardRef<HTMLDivElement, DatePickerProps>(\n function DatePicker(\n {\n helperText,\n error,\n required,\n adapterLocale,\n desktopModeMediaQuery,\n eyebrow,\n title,\n monthYearOrder = \"month-year\",\n viewToggleLabels,\n calendarHeaderLabels,\n views = DEFAULT_VIEWS,\n openTo,\n format,\n viewRenderers,\n dayOfWeekFormatter,\n closeOnSelect = true,\n slots,\n slotProps,\n onChange,\n ...rest\n },\n ref,\n ) {\n const theme = useTheme();\n const language = useLanguage();\n const titleLabels = useDatePickerTitleLabels();\n const resolvedDesktopQuery =\n desktopModeMediaQuery ?? theme.breakpoints.up(\"sm\");\n const isDesktop = useMediaQuery(resolvedDesktopQuery);\n\n // `adapterLocale` still wins when provided; otherwise follow the language.\n const resolvedAdapterLocale =\n adapterLocale ?? LOCALE_FOR_LANGUAGE[language];\n\n const resolvedViews = views;\n const isMonthYear = !resolvedViews.includes(\"day\");\n const resolvedTitle =\n title ??\n (isMonthYear ? titleLabels.selectMonthYear : titleLabels.selectDate);\n\n // For month/year mode with year-first order, default format to \"yyyy MMMM\" (e.g., \"2026 august\")\n const isYearFirst = isMonthYear && monthYearOrder === \"year-month\";\n const resolvedFormat = format ?? (isYearFirst ? \"yyyy MMMM\" : undefined);\n\n // Day mode uses the centered Lea Bank header and lowercase Monday-first\n // weekdays; month/year mode uses our Måned / År segmented toggle with\n // configurable order, drilling month -> year (or year -> month), unless\n // the consumer supplies their own.\n const resolvedViewRenderers =\n viewRenderers ??\n (isMonthYear\n ? createDateViewRenderers(monthYearOrder, viewToggleLabels)\n : undefined);\n // When using year-first order, open on the year view; otherwise default to month\n const resolvedOpenTo =\n openTo ?? (isYearFirst ? \"year\" : isMonthYear ? \"month\" : undefined);\n const localeFormatter = useMemo(\n () => weekdayFormatter(resolvedAdapterLocale),\n [resolvedAdapterLocale],\n );\n const resolvedDayOfWeekFormatter = dayOfWeekFormatter ?? localeFormatter;\n\n const handleChange: MuiDatePickerProps[\"onChange\"] = (value, context) => {\n onChange?.(value, context);\n };\n\n const existingTextField =\n typeof slotProps?.textField === \"object\"\n ? slotProps.textField\n : undefined;\n\n const sharedSlots: Slots = {\n openPickerIcon: OpenPickerIcon,\n // The custom centered header only applies to the day calendar; the\n // month/year mode renders its own toggle via `viewRenderers`.\n ...(isMonthYear ? {} : { calendarHeader: CalendarHeader }),\n };\n const slotsForMode: Slots = isDesktop\n ? { ...sharedSlots, ...slots }\n : {\n ...sharedSlots,\n dialog: DrawerDialog,\n toolbar: DrawerToolbar as unknown as Slots[\"toolbar\"],\n ...slots,\n };\n\n const slotPropsForMode = {\n openPickerButton: {\n sx: {\n border: \"none\",\n color: \"text.subtle\",\n \"&:hover\": { backgroundColor: \"transparent\", color: \"text.base\" },\n },\n },\n // Desktop popover follows the input width (harmless on mobile, which uses a drawer).\n popper: { modifiers: [sameWidthAsInput] },\n ...(isMonthYear ? {} : { calendarHeader: { labels: calendarHeaderLabels } }),\n ...slotProps,\n textField: {\n error,\n required,\n helperText,\n fullWidth: true,\n ...existingTextField,\n },\n ...(isDesktop\n ? {}\n : {\n // Commit on tap, so the drawer needs no Cancel / OK action bar.\n actionBar: { actions: [] },\n toolbar: { hidden: false, eyebrow, title: resolvedTitle },\n }),\n } as MuiDatePickerProps[\"slotProps\"];\n\n return (\n <LocalizationProvider\n dateAdapter={AdapterDateFns}\n adapterLocale={resolvedAdapterLocale}\n localeText={localeTextFor(language)}\n >\n <MuiDatePicker\n ref={ref}\n views={resolvedViews}\n openTo={resolvedOpenTo}\n format={resolvedFormat}\n viewRenderers={resolvedViewRenderers}\n dayOfWeekFormatter={resolvedDayOfWeekFormatter}\n desktopModeMediaQuery={resolvedDesktopQuery}\n closeOnSelect={closeOnSelect}\n slots={slotsForMode}\n slotProps={slotPropsForMode}\n onChange={handleChange}\n {...rest}\n />\n </LocalizationProvider>\n );\n },\n);\n","import { forwardRef, type FocusEventHandler, type ReactNode } from \"react\";\nimport { Autocomplete } from \"./autocomplete\";\n\nexport type EmailInputProps = {\n /** Current value (controlled). */\n value?: string;\n /** Initial value (uncontrolled). */\n defaultValue?: string;\n /** Called with the next string value. */\n onChange?: (value: string) => void;\n /** Domains offered once the user types `@`. Defaults to common providers. */\n domains?: readonly string[];\n /** Maximum number of suggestions to show. @default 6 */\n maxSuggestions?: number;\n /** Floating label. Rendered as an `InputLabel` and linked automatically. */\n label?: ReactNode;\n /** Helper / error text shown below the control and linked via `aria-describedby`. */\n helperText?: ReactNode;\n /** Placeholder shown in the text input. */\n placeholder?: string;\n /** Puts the control in an error state. */\n error?: boolean;\n /** Marks the control as required. */\n required?: boolean;\n /** Disables the control. */\n disabled?: boolean;\n /** Blur handler (e.g. for react-hook-form touched state). */\n onBlur?: FocusEventHandler<HTMLDivElement>;\n};\n\n/**\n * Email text field that suggests common domains in a dropdown once the user\n * types `@`. Works controlled (`value` + `onChange`) or uncontrolled\n * (`defaultValue`), standalone (`label` / `helperText`) or inside a\n * `FormControl`.\n *\n */\nexport const EmailInput = forwardRef<HTMLDivElement, EmailInputProps>(\n function EmailInput(props, ref) {\n return <Autocomplete ref={ref} email {...props} />;\n },\n);\n","import {\n useFormContext,\n type Control,\n type FieldValues,\n} from \"react-hook-form\";\n\n/**\n * Resolves the `control` instance for a field component. Uses the explicit\n * `control` prop when provided, otherwise reads from the nearest `FormProvider`.\n */\nexport function useResolvedControl<T extends FieldValues>(\n control?: Control<T>,\n): Control<T> {\n const ctx = useFormContext<T>();\n const resolved = control ?? (ctx?.control as Control<T> | undefined);\n\n if (!resolved) {\n throw new Error(\n \"Field components need a `control` prop or a surrounding <FormProvider>.\",\n );\n }\n\n return resolved;\n}\n","import { Controller, type FieldValues } from \"react-hook-form\";\nimport { Autocomplete, type AutocompleteProps } from \"../autocomplete\";\nimport type { BaseFieldProps } from \"./field-types\";\nimport { useResolvedControl } from \"./use-field-control\";\n\n/**\n * Distributes `Omit` across the `AutocompleteProps` union so the single- and\n * multiple-select props (e.g. `email`, `min`, `max`) survive rather than\n * collapsing to the keys common to both branches.\n */\ntype DistributiveOmit<T, K extends PropertyKey> = T extends unknown\n ? Omit<T, K>\n : never;\n\nexport type AutocompleteFieldProps<T extends FieldValues> = BaseFieldProps<T> &\n DistributiveOmit<\n AutocompleteProps,\n \"name\" | \"value\" | \"defaultValue\" | \"onChange\" | \"error\"\n >;\n\n/**\n * `Autocomplete` connected to react-hook-form via `Controller`. Reads `control`\n * from the nearest `FormProvider` when the prop is omitted. Supports both\n * single (`string`) and `multiple` (`string[]`) selection.\n */\nexport const AutocompleteField = <T extends FieldValues>({\n name,\n control,\n rules,\n disabled,\n label,\n helperText,\n ...rest\n}: AutocompleteFieldProps<T>) => {\n const resolved = useResolvedControl(control);\n\n return (\n <Controller\n control={resolved}\n name={name}\n rules={rules}\n render={({ field, fieldState }) => {\n // Bridge the discriminated union once: value shape follows `multiple`.\n const autocompleteProps = {\n ...rest,\n label,\n value: field.value ?? (rest.multiple ? [] : \"\"),\n onChange: field.onChange,\n onBlur: field.onBlur,\n error: !!fieldState.error,\n helperText: fieldState.error?.message ?? helperText,\n disabled: disabled ?? field.disabled,\n } as AutocompleteProps;\n\n return <Autocomplete {...autocompleteProps} />;\n }}\n />\n );\n};\n","import {\n FormControl as MuiFormControl,\n type FormControlProps,\n} from \"@mui/material\";\nimport { useId, useMemo, useState, type FocusEvent } from \"react\";\nimport {\n FormFieldProvider,\n type FormFieldContextValue,\n} from \"./form-control-context\";\n\nexport type { FormControlProps };\n\n/**\n * Wrapper around MUI's `FormControl` that generates a unique base id (via\n * `useId`, overridable with the `id` prop) and shares the derived label /\n * control / helper-text ids with its children through context. This lets\n * `Input`, `Select`, `InputLabel` and `FormHelperText` wire `htmlFor`, `id` and\n * `aria-describedby` automatically — the consumer never writes them.\n *\n * MUI's own `FormControl` context still propagates `error` / `required` /\n * `disabled` / focused state to children; we only layer the ids on top.\n */\nexport const FormControl = ({\n id,\n fullWidth = true,\n focused: focusedProp,\n onFocus,\n onBlur,\n children,\n ...rest\n}: FormControlProps) => {\n const reactId = useId();\n const baseId = id ?? reactId;\n\n const [hasHelperText, setHasHelperText] = useState(false);\n const [hasValue, setHasValue] = useState(false);\n\n // MUI only floats the label on focus when a child input reports focus through\n // its context. The `OutlinedInput` that `Autocomplete` injects (and the other\n // fields here) doesn't reliably do that, so we track focus at the wrapper via\n // bubbling focus/blur events and drive MUI's `focused` prop ourselves. This\n // makes every field's label float on focus consistently, reusing the existing\n // shrink styling. A caller-supplied `focused` prop still wins.\n const [focused, setFocused] = useState(false);\n\n const handleFocus = (event: FocusEvent<HTMLDivElement>) => {\n setFocused(true);\n onFocus?.(event);\n };\n const handleBlur = (event: FocusEvent<HTMLDivElement>) => {\n setFocused(false);\n onBlur?.(event);\n };\n\n const value = useMemo<FormFieldContextValue>(\n () => ({\n ids: {\n control: baseId,\n label: `${baseId}-label`,\n helperText: `${baseId}-helper-text`,\n },\n hasHelperText,\n setHasHelperText,\n hasValue,\n setHasValue,\n }),\n [baseId, hasHelperText, hasValue],\n );\n\n return (\n <FormFieldProvider value={value}>\n <MuiFormControl\n id={baseId}\n fullWidth={fullWidth}\n focused={focusedProp ?? focused}\n onFocus={handleFocus}\n onBlur={handleBlur}\n {...rest}\n >\n {children}\n </MuiFormControl>\n </FormFieldProvider>\n );\n};\n","import {\n Box,\n FormLabel as MuiFormLabel,\n type FormLabelProps,\n} from \"@mui/material\";\nimport { useFormField } from \"./form-control-context\";\n\n/**\n * Group label for non-floating controls (e.g. a `RadioGroup`). When rendered\n * inside our `FormControl` it claims the shared label id, so a sibling\n * `RadioGroup` can point its `aria-labelledby` at it automatically — the\n * consumer never wires the ids by hand. Reads required / error / focus state\n * from the surrounding `FormControl` like MUI's own `FormLabel`.\n */\nexport const FormLabel = (props: FormLabelProps) => {\n const ctx = useFormField();\n const { children, ...rest } = props;\n const hasAdjacentContent = Array.isArray(children) && children.length > 1;\n\n return (\n <MuiFormLabel\n id={ctx?.ids.label}\n sx={{\n display: \"inline-flex\",\n alignItems: \"center\",\n gap: 1,\n width: \"fit-content\",\n paddingBlockEnd: hasAdjacentContent ? 0 : 1.5,\n fontWeight: \"medium\",\n color: \"text.base\",\n // MUI turns the label primary when the FormControl is focused; keep it\n // neutral (the input/control already signals focus).\n \"&.Mui-focused\": { color: \"text.base\" },\n }}\n {...rest}\n >\n {hasAdjacentContent ? <Box sx={{ display: \"inline-flex\", alignItems: \"center\", gap: 1 }}>{children}</Box> : children}\n </MuiFormLabel>\n );\n};\n","import { palette, durations, easings, shape, transition } from \"@/theme/tokens\";\nimport { Box, type SxProps, type Theme } from \"@mui/material\";\n\nexport type RadioSize = \"small\" | \"medium\";\n\nconst sizes: Record<RadioSize, { outer: string; dot: string }> = {\n small: { outer: \"1rem\", dot: \"0.45rem\" },\n medium: { outer: \"1.3rem\", dot: \"0.6rem\" },\n};\n\nexport type RadioCircleProps = {\n /** When true, fills the circle and springs the dot in. */\n checked?: boolean;\n size?: RadioSize;\n sx?: SxProps<Theme>;\n};\n\n/**\n * The bare radio visual — a bordered circle with a dot that springs in when\n * `checked`. Single source of truth shared by `Radio` (as its `icon` /\n * `checkedIcon`) and `RadioCardIndicator`, so the look stays identical wherever a\n * radio appears.\n *\n * Self-styled (not a MUI theme override) because it renders outside `MuiRadio`\n * too. When used as `Radio`'s icons, swapping `<RadioCircle />` ⇄\n * `<RadioCircle checked />` reconciles in place, so the dot animates.\n */\nexport const RadioCircle = ({\n checked = false,\n size = \"medium\",\n sx,\n}: RadioCircleProps) => {\n const { outer, dot } = sizes[size];\n return (\n <Box\n aria-hidden\n className=\"lea-radio-circle\"\n sx={[\n {\n display: \"inline-flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n flexShrink: 0,\n width: outer,\n height: outer,\n borderRadius: shape.full,\n border: `2px solid ${\n checked ? palette.purple.base : palette.border.base\n }`,\n backgroundColor: checked ? palette.purple.base : palette.bg.base,\n transition: transition(\n [\"background-color\", \"border-color\"],\n durations.normal,\n ),\n // Hover darkens the outline, but only while unchecked.\n ...(checked\n ? {}\n : { \"&:hover\": { borderColor: palette.border.strong } }),\n },\n ...(Array.isArray(sx) ? sx : [sx]),\n ]}\n >\n <Box\n sx={{\n width: dot,\n height: dot,\n borderRadius: shape.full,\n backgroundColor: palette.purple.contrast,\n transform: checked ? \"scale(1)\" : \"scale(0)\",\n transition: transition(\n [\"transform\"],\n durations.emphasis,\n easings.spring,\n ),\n }}\n />\n </Box>\n );\n};\n","import {\n Radio as MuiRadio,\n RadioGroup as MuiRadioGroup,\n type RadioProps as MuiRadioProps,\n type RadioGroupProps as MuiRadioGroupProps,\n} from \"@mui/material\";\nimport { createContext, forwardRef, useContext } from \"react\";\nimport { useFormField } from \"./form-control\";\nimport { RadioCircle, type RadioSize } from \"./radio-circle\";\n\nexport type { RadioSize };\n\ntype RadioGroupContextValue = { size?: RadioSize };\nconst RadioGroupContext = createContext<RadioGroupContextValue>({});\n\n/** Reads the `size` set on the surrounding `RadioGroup`, if any. */\nexport const useRadioGroupSize = (): RadioSize | undefined =>\n useContext(RadioGroupContext).size;\n\nexport type RadioProps = Omit<MuiRadioProps, \"color\" | \"size\"> & {\n size?: RadioSize;\n};\n\nexport type RadioGroupProps = MuiRadioGroupProps & {\n /** Size applied to all child `Radio` components unless overridden per-item. */\n size?: RadioSize;\n};\n\n/**\n * Radio built on MUI's `Radio`, styled by the global theme (`radio.theme.ts`).\n * Kept composite — pair it with `FormControlLabel` for a label instead of\n * forwarding label / typography props, and place it inside a `RadioGroup` so\n * selection stays mutually exclusive:\n *\n * ```tsx\n * <RadioGroup value={value} onChange={(_, v) => setValue(v)}>\n * <FormControlLabel value=\"a\" control={<Radio />} label=\"A\" />\n * <FormControlLabel value=\"b\" control={<Radio />} label=\"B\" />\n * </RadioGroup>\n * ```\n */\nexport const Radio = forwardRef<HTMLButtonElement, RadioProps>(function Radio(\n { size, ...props },\n ref,\n) {\n const groupSize = useRadioGroupSize();\n const resolvedSize = size ?? groupSize;\n return (\n <MuiRadio\n ref={ref}\n icon={<RadioCircle size={resolvedSize} />}\n checkedIcon={<RadioCircle checked size={resolvedSize} />}\n {...props}\n />\n );\n});\n\n/**\n * Thin wrapper around MUI's `RadioGroup`. Radios are only meaningful as a\n * mutually-exclusive set, so reach for this rather than placing a bare `Radio`.\n *\n * When rendered inside our `FormControl` it points its `aria-labelledby` at the\n * surrounding `FormLabel` automatically (via the shared label id), so the group\n * gets an accessible name without the consumer wiring it. Also applies a default\n * gap between rows, overridable via `sx`.\n */\nexport const RadioGroup = forwardRef<HTMLDivElement, RadioGroupProps>(\n function RadioGroup(\n { sx, size, \"aria-labelledby\": ariaLabelledBy, ...props },\n ref,\n ) {\n const formCtx = useFormField();\n return (\n <RadioGroupContext.Provider value={{ size }}>\n <MuiRadioGroup\n ref={ref}\n aria-labelledby={ariaLabelledBy ?? formCtx?.ids.label}\n sx={[{ gap: 1 }, ...(Array.isArray(sx) ? sx : [sx])]}\n {...props}\n />\n </RadioGroupContext.Provider>\n );\n },\n);\n","import { Text } from \"@/components/typography/text\";\nimport { Box, useRadioGroup, type SxProps, type Theme } from \"@mui/material\";\nimport { LucideIcon } from \"lucide-react\";\nimport { createContext, forwardRef, useContext, type ReactNode } from \"react\";\nimport { Radio, useRadioGroupSize } from \".\";\nimport { RadioCircle } from \"./radio-circle\";\n\ntype Orientation = \"horizontal\" | \"vertical\";\n\ntype RadioCardContextValue = { checked: boolean; orientation: Orientation };\nconst RadioCardContext = createContext<RadioCardContextValue>({\n checked: false,\n orientation: \"horizontal\",\n});\nconst useRadioCard = () => useContext(RadioCardContext);\n\nexport type RadioCardProps = {\n /** Value submitted to the surrounding `RadioGroup` when this card is chosen. */\n value: string | number | boolean;\n /** `\"horizontal\"` (indicator + text in a row) or `\"vertical\"` (icon stacked above text). */\n orientation?: \"horizontal\" | \"vertical\";\n disabled?: boolean;\n /** Controlled checked state for standalone use (ignored inside a `RadioGroup`). */\n checked?: boolean;\n /** Change handler for standalone use (ignored inside a `RadioGroup`). */\n onChange?: (event: React.ChangeEvent<HTMLInputElement>) => void;\n sx?: SxProps<Theme>;\n children?: ReactNode;\n size?: \"sm\" | \"lg\";\n};\n\n/**\n * A selectable card. Not a MUI component — it wraps our `Radio` for the actual\n * selection (group membership, keyboard, a11y) and renders a styled, fully\n * clickable surface around composable pieces: `RadioCardContent` (wraps the\n * text), `RadioCardIndicator` (optional), `RadioCardIcon`, `RadioCardLabel`,\n * `RadioCardDescription`.\n *\n * Children are laid out as plain flex items, so the indicator is just another\n * child — place it before or after `RadioCardContent` and it sits at that edge\n * (the content grows to fill the row, pushing the indicator to the side).\n *\n * Place cards inside a `RadioGroup` so selection stays mutually exclusive; the\n * card derives its checked styling from the group automatically.\n *\n * ```tsx\n * <RadioGroup value={value} onChange={(_, v) => setValue(v)}>\n * <RadioCard value=\"10\">\n * <RadioCardContent>\n * <RadioCardLabel>1316 kr/mnd</RadioCardLabel>\n * <RadioCardDescription>Over 10 år</RadioCardDescription>\n * </RadioCardContent>\n * <RadioCardIndicator />\n * </RadioCard>\n * </RadioGroup>\n * ```\n */\nexport const RadioCard = forwardRef<HTMLDivElement, RadioCardProps>(\n function RadioCard(\n {\n value,\n orientation = \"horizontal\",\n disabled,\n checked: checkedProp,\n onChange,\n sx,\n children,\n size = \"lg\",\n },\n ref,\n ) {\n const group = useRadioGroup();\n const inGroup = group != null;\n const checked = inGroup\n ? String(group?.value) === String(value)\n : Boolean(checkedProp);\n\n const vertical = orientation === \"vertical\";\n\n return (\n <RadioCardContext.Provider value={{ checked, orientation }}>\n <Box\n ref={ref}\n component=\"label\"\n data-checked={checked}\n sx={[\n {\n position: \"relative\",\n display: \"flex\",\n flexDirection: vertical ? \"column\" : \"row\",\n alignItems: \"center\",\n justifyContent: vertical ? \"center\" : \"flex-start\",\n textAlign: vertical ? \"center\" : \"left\",\n gap: 1.5,\n paddingInline: 2,\n paddingBlock: vertical\n ? size === \"sm\"\n ? 2\n : 4\n : size === \"sm\"\n ? 1.5\n : 2,\n borderRadius: \"xl\",\n border: \"1px solid\",\n borderColor: \"border.base\",\n backgroundColor: \"bg.base\",\n cursor: \"pointer\",\n transition:\n \"background-color 0.2s ease-in-out, border-color 0.2s ease-in-out\",\n \"&:hover\": { borderColor: \"border.strong\" },\n \"&[data-checked='true']\": {\n borderColor: \"purple.base\",\n backgroundColor: \"bg.accent\",\n },\n \"&:focus-visible\": {\n outline: \"2px solid\",\n outlineColor: \"purple.base\",\n outlineOffset: 2,\n },\n ...(disabled && {\n opacity: 0.6,\n cursor: \"default\",\n pointerEvents: \"none\",\n }),\n },\n ...(Array.isArray(sx) ? sx : [sx]),\n ]}\n >\n {/* Functional control — visually hidden but focusable; the label makes\n the whole card clickable. Inside a RadioGroup the group drives\n checked/onChange, so we only pass them when standalone. */}\n <Box\n sx={{\n position: \"absolute\",\n width: \"1px\",\n height: \"1px\",\n overflow: \"hidden\",\n clip: \"rect(0 0 0 0)\",\n whiteSpace: \"nowrap\",\n }}\n >\n <Radio\n value={value}\n disabled={disabled}\n {...(inGroup ? {} : { checked: checkedProp, onChange })}\n />\n </Box>\n\n {children}\n </Box>\n </RadioCardContext.Provider>\n );\n },\n);\n\n/**\n * Optional radio dot for a `RadioCard`. Reuses the shared `RadioCircle` and\n * reflects the card's checked state. Omit it for icon-only cards.\n */\nexport const RadioCardIndicator = () => {\n const { checked } = useRadioCard();\n const size = useRadioGroupSize();\n return <RadioCircle checked={checked} size={size} />;\n};\n\nexport type RadioCardIconProps = {\n /** Icon box size (predefined, overridable). */\n size?: number | string;\n icon: LucideIcon;\n};\n\n/**\n * Fixed-size icon slot so every card's icon renders at the same size regardless\n * of the icon passed in.\n */\nexport const RadioCardIcon = ({ size = 24, icon }: RadioCardIconProps) => {\n const Icon = icon;\n return (\n <Box\n component={Icon}\n size={size}\n aria-hidden\n sx={{\n display: \"inline-flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n flexShrink: 0,\n color: \"text.base\",\n \"& svg\": { width: \"100%\", height: \"100%\" },\n }}\n />\n );\n};\n\n/**\n * Wraps the text lines (`RadioCardLabel` / `RadioCardDescription`) into a column.\n * Grows to fill the row in `horizontal` orientation — so a sibling\n * `RadioCardIndicator` is pushed to the opposite edge — and centers in\n * `vertical`.\n */\nexport const RadioCardContent = ({\n children,\n sx,\n}: {\n children: ReactNode;\n sx?: SxProps<Theme>;\n}) => {\n const { orientation } = useRadioCard();\n const vertical = orientation === \"vertical\";\n return (\n <Box\n sx={[\n {\n display: \"flex\",\n flexDirection: \"column\",\n gap: 0.25,\n ...(vertical\n ? { alignItems: \"center\", textAlign: \"center\" }\n : { flex: 1, alignItems: \"flex-start\", textAlign: \"left\" }),\n },\n ...(Array.isArray(sx) ? sx : [sx]),\n ]}\n >\n {children}\n </Box>\n );\n};\n\n/** Primary line of a `RadioCard`. */\nexport const RadioCardLabel = ({ children }: { children: ReactNode }) => (\n <Text fontWeight=\"medium\" sx={{ color: \"text.base\", lineHeight: 1.3 }}>\n {children}\n </Text>\n);\n\n/** Secondary, muted line of a `RadioCard`. */\nexport const RadioCardDescription = ({ children }: { children: ReactNode }) => (\n <Text fontSize=\"sm\" sx={{ color: \"text.subtle\", lineHeight: 1.3 }}>\n {children}\n </Text>\n);\n","import { createTranslation } from \"../../../i18n\";\n\n/**\n * Translated accessible name for the info trigger a field renders next to its\n * label when given a `tooltip`.\n */\nexport const useTooltipTriggerLabels = createTranslation({\n moreInformation: {\n no: \"Mer informasjon\",\n se: \"Mer information\",\n fi: \"Lisätietoja\",\n es: \"Más información\",\n },\n});\n","import { Box } from \"@mui/material\";\nimport { InfoIcon } from \"lucide-react\";\nimport type { ReactNode } from \"react\";\nimport { Controller, type FieldValues } from \"react-hook-form\";\nimport { Tooltip } from \"../../data-display\";\nimport { FormControl } from \"../form-control\";\nimport { FormHelperText } from \"../form-control/form-helper-text\";\nimport { FormLabel } from \"../form-control/form-label\";\nimport { RadioGroup, type RadioGroupProps } from \"../radio\";\nimport { RadioCard, RadioCardIndicator } from \"../radio-card\";\nimport type {\n BaseFieldProps,\n FieldOption,\n FieldValueTransform,\n} from \"./field-types\";\nimport { useResolvedControl } from \"./use-field-control\";\nimport { useTooltipTriggerLabels } from \"./use-tooltip-trigger-labels\";\n\nexport type RadioCardFieldProps<T extends FieldValues> = BaseFieldProps<T> &\n FieldValueTransform & {\n label: ReactNode;\n options: FieldOption[];\n /** CSS grid-template-columns for the option layout. Defaults to two equal columns. */\n gridColumns?: string;\n /** Size passed to each `RadioCard`. */\n cardSize?: \"sm\" | \"lg\";\n /** Tooltip content to display when hovering over the field. */\n tooltip?: ReactNode;\n } & Omit<RadioGroupProps, \"value\" | \"onChange\" | \"name\" | \"defaultValue\">;\n\nconst defaultFormat = (value: unknown) =>\n value === undefined || value === null ? \"\" : String(value);\n\n/**\n * `RadioGroup` of `RadioCard` options connected to react-hook-form via\n * `Controller`. Reads `control` from the nearest `FormProvider` when the prop\n * is omitted.\n *\n * Pass optional `format` / `parse` to coerce values (e.g. boolean <-> string).\n */\nexport const RadioCardField = <T extends FieldValues>({\n name,\n control,\n rules,\n disabled,\n label,\n options,\n format = defaultFormat,\n parse,\n gridColumns = \"1fr 1fr\",\n cardSize = \"sm\",\n tooltip,\n size,\n ...rest\n}: RadioCardFieldProps<T>) => {\n const resolved = useResolvedControl(control);\n const labels = useTooltipTriggerLabels();\n\n return (\n <Controller\n control={resolved}\n name={name}\n rules={rules}\n render={({ field, fieldState }) => (\n <FormControl error={!!fieldState.error} disabled={disabled}>\n <FormLabel>\n <span>{label}</span>\n {tooltip && (\n // The library `Tooltip`'s built-in trigger is a real button, so\n // the tooltip is reachable by keyboard and has a name. `color`\n // stays inherited to keep the icon looking as it does today.\n <Tooltip\n title={tooltip}\n ariaLabel={labels.moreInformation}\n triggerIcon={<InfoIcon size={16} aria-hidden />}\n triggerSx={{\n color: \"inherit\",\n \"&:hover\": { color: \"inherit\" },\n }}\n />\n )}\n </FormLabel>\n <RadioGroup\n {...rest}\n {...field}\n size={size}\n value={format(field.value)}\n onChange={(_, value) =>\n field.onChange(parse ? parse(value) : value)\n }\n >\n <Box\n sx={{\n display: \"grid\",\n gap: 1.5,\n gridTemplateColumns: gridColumns,\n }}\n >\n {options.map((option) => (\n <RadioCard\n key={option.value}\n value={option.value}\n size={cardSize}\n disabled={disabled}\n >\n <RadioCardIndicator />\n {option.label}\n </RadioCard>\n ))}\n </Box>\n </RadioGroup>\n {fieldState.error?.message ? (\n <FormHelperText error>{fieldState.error.message}</FormHelperText>\n ) : null}\n </FormControl>\n )}\n />\n );\n};\n","import { FieldValues } from \"react-hook-form\";\nimport { RadioCardField, RadioCardFieldProps } from \"./radio-card-field\";\n\n// component-library: src/components/form/fields/boolean-radio-card-field.tsx\nconst booleanFormat = (value: unknown): string =>\n value === true ? \"true\" : value === false ? \"false\" : \"\";\n\nconst booleanParse = (value: string): boolean | undefined =>\n value === \"true\" ? true : value === \"false\" ? false : undefined;\n\nexport const BooleanRadioCardField = <T extends FieldValues>(\n props: Omit<RadioCardFieldProps<T>, \"format\" | \"parse\">,\n) => <RadioCardField {...props} format={booleanFormat} parse={booleanParse} />;\n","import { FormControlLabel } from \"@mui/material\";\nimport type { ReactNode } from \"react\";\nimport { Controller, type FieldValues } from \"react-hook-form\";\nimport { Checkbox } from \"../checkbox\";\nimport { FormControl } from \"../form-control\";\nimport { FormHelperText } from \"../form-control/form-helper-text\";\n\nimport type { BaseFieldProps } from \"./field-types\";\nimport { useResolvedControl } from \"./use-field-control\";\n\nexport type CheckboxFieldProps<T extends FieldValues> = BaseFieldProps<T> & {\n label: ReactNode;\n};\n\n/**\n * `Checkbox` connected to react-hook-form via `Controller`, composed with\n * `FormControlLabel`. Reads `control` from the nearest `FormProvider` when the\n * prop is omitted.\n */\nexport const CheckboxField = <T extends FieldValues>({\n name,\n control,\n rules,\n disabled,\n label,\n}: CheckboxFieldProps<T>) => {\n const resolved = useResolvedControl(control);\n\n return (\n <Controller\n control={resolved}\n name={name}\n rules={rules}\n render={({ field: { value, onChange, ...field }, fieldState }) => (\n <FormControl error={!!fieldState.error} disabled={disabled}>\n <FormControlLabel\n control={\n <Checkbox\n {...field}\n checked={!!value}\n onChange={(_, checked) => onChange(checked)}\n disabled={disabled}\n />\n }\n label={label}\n />\n {fieldState.error?.message ? (\n <FormHelperText error>{fieldState.error.message}</FormHelperText>\n ) : null}\n </FormControl>\n )}\n />\n );\n};\n","import { Controller, type FieldValues } from \"react-hook-form\";\nimport { DatePicker, type DatePickerProps } from \"../datepicker\";\nimport type { BaseFieldProps } from \"./field-types\";\nimport { useResolvedControl } from \"./use-field-control\";\n\nexport type DatePickerFieldProps<T extends FieldValues> = BaseFieldProps<T> &\n Omit<DatePickerProps, \"name\" | \"value\" | \"defaultValue\" | \"error\" | \"onChange\">;\n\n/**\n * `DatePicker` connected to react-hook-form via `Controller`. Reads `control`\n * from the nearest `FormProvider` when the prop is omitted.\n */\nexport const DatePickerField = <T extends FieldValues>({\n name,\n control,\n rules,\n disabled,\n helperText,\n ...rest\n}: DatePickerFieldProps<T>) => {\n const resolved = useResolvedControl(control);\n\n return (\n <Controller\n control={resolved}\n name={name}\n rules={rules}\n render={({ field, fieldState }) => (\n <DatePicker\n {...rest}\n inputRef={field.ref}\n name={field.name}\n value={field.value ?? null}\n onChange={(value, context) => field.onChange(value, context)}\n onClose={field.onBlur}\n error={!!fieldState.error}\n helperText={fieldState.error?.message ?? helperText}\n disabled={disabled ?? field.disabled}\n />\n )}\n />\n );\n};\n","import { Controller, type FieldValues } from \"react-hook-form\";\nimport { EmailInput, type EmailInputProps } from \"../email-input\";\nimport type { BaseFieldProps } from \"./field-types\";\nimport { useResolvedControl } from \"./use-field-control\";\n\nexport type EmailFieldProps<T extends FieldValues> = BaseFieldProps<T> &\n Omit<\n EmailInputProps,\n \"name\" | \"value\" | \"defaultValue\" | \"onChange\" | \"error\"\n >;\n\n/**\n * `EmailInput` (with `@` domain autocomplete) connected to react-hook-form via\n * `Controller`. Reads `control` from the nearest `FormProvider` when the prop is\n * omitted.\n */\nexport const EmailField = <T extends FieldValues>({\n name,\n control,\n rules,\n disabled,\n label,\n helperText,\n ...rest\n}: EmailFieldProps<T>) => {\n const resolved = useResolvedControl(control);\n\n return (\n <Controller\n control={resolved}\n name={name}\n rules={rules}\n render={({ field, fieldState }) => (\n <EmailInput\n {...rest}\n label={label}\n value={field.value ?? \"\"}\n onChange={field.onChange}\n onBlur={field.onBlur}\n error={!!fieldState.error}\n helperText={fieldState.error?.message ?? helperText}\n disabled={disabled ?? field.disabled}\n />\n )}\n />\n );\n};\n","import { OutlinedInput, type OutlinedInputProps } from \"@mui/material\";\nimport { forwardRef, type ReactNode } from \"react\";\nimport { FormControl, useFormField } from \".\";\nimport { FormHelperText } from \"./form-control/form-helper-text\";\nimport { InputLabel } from \"./input-label\";\n\nexport type InputProps = OutlinedInputProps & {\n /** Floating label. Rendered as an `InputLabel` and linked automatically. */\n label?: ReactNode;\n /** Helper / error text shown below the control and linked via `aria-describedby`. */\n helperText?: ReactNode;\n};\n\n/**\n * The bare control, wired to the surrounding `FormControl` via context. Links\n * `aria-describedby` only when a `FormHelperText` is actually present, so it\n * never points at a missing id.\n */\nconst InputControl = forwardRef<HTMLInputElement, OutlinedInputProps>(\n function InputControl(rest, ref) {\n const ctx = useFormField();\n const describedBy = ctx?.hasHelperText\n ? ctx.ids.helperText\n : rest[\"aria-describedby\"];\n\n return (\n <OutlinedInput\n ref={ref}\n id={ctx?.ids.control}\n {...rest}\n inputProps={{\n \"aria-describedby\": describedBy,\n ...rest.inputProps,\n }}\n />\n );\n },\n);\n\n/**\n * Text input built on MUI's `OutlinedInput`.\n *\n * Works two ways:\n * - **Standalone (all-in-one):** pass `label` / `helperText` and it renders its\n * own `FormControl`, label and helper text, generating and wiring all ids for\n * you. Pass `multiline` (+ `minRows`) for a textarea.\n * - **Composed:** drop it inside a `FormControl` next to `InputLabel` /\n * `FormHelperText` and it picks up the shared ids from context.\n */\nexport const Input = forwardRef<HTMLInputElement, InputProps>(function Input(\n { label, helperText, error, required, disabled, id, ...rest },\n ref,\n) {\n const ctx = useFormField();\n\n if (ctx) {\n // Already inside a FormControl: render only the control.\n return (\n <InputControl\n ref={ref}\n error={error}\n required={required}\n disabled={disabled}\n {...rest}\n />\n );\n }\n\n // Standalone: provide our own FormControl so the ids get generated and wired.\n return (\n <FormControl id={id} error={error} required={required} disabled={disabled}>\n {label != null && <InputLabel>{label}</InputLabel>}\n <InputControl ref={ref} {...rest} />\n {helperText != null && (\n <FormHelperText error={error}>{helperText}</FormHelperText>\n )}\n </FormControl>\n );\n});\n","import { Controller, type FieldValues } from \"react-hook-form\";\nimport { Input, type InputProps } from \"../input\";\nimport type { BaseFieldProps } from \"./field-types\";\nimport { useResolvedControl } from \"./use-field-control\";\n\nexport type InputFieldProps<T extends FieldValues> = BaseFieldProps<T> &\n Omit<InputProps, \"name\" | \"value\" | \"defaultValue\" | \"error\">;\n\n/**\n * `Input` connected to react-hook-form via `Controller`. Reads `control` from\n * the nearest `FormProvider` when the prop is omitted.\n */\nexport const InputField = <T extends FieldValues>({\n name,\n control,\n rules,\n disabled,\n label,\n helperText,\n ...rest\n}: InputFieldProps<T>) => {\n const resolved = useResolvedControl(control);\n\n return (\n <Controller\n control={resolved}\n name={name}\n rules={rules}\n render={({ field, fieldState }) => (\n <Input\n {...rest}\n {...field}\n label={label}\n value={field.value ?? \"\"}\n error={!!fieldState.error}\n helperText={fieldState.error?.message ?? helperText}\n disabled={disabled ?? field.disabled}\n />\n )}\n />\n );\n};\n","import {\n MenuItem,\n Select as MuiSelect,\n type SelectProps as MuiSelectProps,\n} from \"@mui/material\";\nimport { forwardRef, type ReactNode } from \"react\";\nimport { FormControl, useFormField } from \".\";\nimport { FormHelperText } from \"./form-control/form-helper-text\";\nimport { InputLabel } from \"./input-label\";\n\nexport type SelectOption = { label: string; value: string };\n\nexport type SelectProps = MuiSelectProps & {\n /** Floating label. Rendered as an `InputLabel` and linked automatically. */\n label?: ReactNode;\n /** Helper / error text shown below the control and linked via `aria-describedby`. */\n helperText?: ReactNode;\n /** Convenience: render `MenuItem`s from a list instead of passing children. */\n options?: SelectOption[];\n};\n\ntype SelectControlProps = MuiSelectProps & { options?: SelectOption[] };\n\n/**\n * The bare select, wired to the surrounding `FormControl` via context. Links\n * `aria-describedby` only when a `FormHelperText` is actually present, so it\n * never points at a missing id.\n */\nconst SelectControl = forwardRef<HTMLDivElement, SelectControlProps>(\n function SelectControl({ options, children, inputProps, ...rest }, ref) {\n const ctx = useFormField();\n const describedBy = ctx?.hasHelperText\n ? ctx.ids.helperText\n : inputProps?.[\"aria-describedby\"];\n\n return (\n <MuiSelect\n ref={ref}\n id={ctx?.ids.control}\n labelId={ctx?.ids.label}\n inputProps={{ \"aria-describedby\": describedBy, ...inputProps }}\n {...rest}\n >\n {options && options.length > 0\n ? options.map((option) => (\n <MenuItem key={option.value} value={option.value}>\n {option.label}\n </MenuItem>\n ))\n : children}\n </MuiSelect>\n );\n },\n);\n\n/**\n * Select built on MUI's `Select`.\n *\n * Works two ways:\n * - **Standalone (all-in-one):** pass `label` / `helperText` and `options` (or\n * `MenuItem` children) and it renders its own `FormControl`, label and helper\n * text, generating and wiring all ids for you.\n * - **Composed:** drop it inside a `FormControl` next to `InputLabel` /\n * `FormHelperText` and it picks up the shared ids from context.\n */\nexport const Select = forwardRef<HTMLDivElement, SelectProps>(function Select(\n {\n label,\n helperText,\n options,\n children,\n error,\n required,\n disabled,\n id,\n ...rest\n },\n ref,\n) {\n const ctx = useFormField();\n\n const control = (\n <SelectControl\n ref={ref}\n options={options}\n error={error}\n required={required}\n disabled={disabled}\n {...rest}\n >\n {children}\n </SelectControl>\n );\n\n if (ctx) {\n // Already inside a FormControl: render only the control.\n return control;\n }\n\n // Standalone: provide our own FormControl so the ids get generated and wired.\n return (\n <FormControl id={id} error={error} required={required} disabled={disabled}>\n {label != null && <InputLabel>{label}</InputLabel>}\n {control}\n {helperText != null && (\n <FormHelperText error={error}>{helperText}</FormHelperText>\n )}\n </FormControl>\n );\n});\n","import { Box, MenuItem, type SelectChangeEvent } from \"@mui/material\";\nimport {\n forwardRef,\n useCallback,\n useEffect,\n useLayoutEffect,\n useMemo,\n useRef,\n useState,\n type MouseEvent,\n type ReactNode,\n} from \"react\";\nimport { Chip } from \"../data-display\";\nimport { Checkbox } from \"./checkbox\";\nimport { Select, type SelectOption, type SelectProps } from \"./select\";\n\ntype SelectedItem = { value: string; label: string };\n\ntype SelectedChipsProps = {\n items: SelectedItem[];\n canDelete: boolean;\n onDelete: (value: string, event: MouseEvent) => void;\n};\n\n// Gap between chips, in px (matches the `gap: 0.5` * 8px theme spacing below).\nconst CHIP_GAP = 4;\n\n/**\n * Renders the selected values as chips on a single line. When they don't all\n * fit, the overflow is collapsed into a trailing `+N` badge rather than\n * wrapping onto a second line. Widths are measured off-screen so the visible\n * row can reserve room for the badge before deciding how many chips to show.\n */\nfunction SelectedChips({ items, canDelete, onDelete }: SelectedChipsProps) {\n const containerRef = useRef<HTMLDivElement>(null);\n const measureRef = useRef<HTMLDivElement>(null);\n const [visibleCount, setVisibleCount] = useState(items.length);\n\n const recompute = useCallback(() => {\n const container = containerRef.current;\n const measure = measureRef.current;\n if (!container || !measure) return;\n\n const available = container.clientWidth;\n // The measurement row renders every chip followed by a single badge.\n const children = Array.from(measure.children) as HTMLElement[];\n const badgeEl = children[children.length - 1];\n const chipEls = children.slice(0, -1);\n const badgeWidth = badgeEl ? badgeEl.offsetWidth + CHIP_GAP : 0;\n\n const total = chipEls.reduce(\n (sum, el, index) => sum + el.offsetWidth + (index > 0 ? CHIP_GAP : 0),\n 0,\n );\n if (total <= available) {\n setVisibleCount(items.length);\n return;\n }\n\n let used = 0;\n let count = 0;\n for (let i = 0; i < chipEls.length; i++) {\n const next = chipEls[i].offsetWidth + (i > 0 ? CHIP_GAP : 0);\n if (used + next + badgeWidth <= available) {\n used += next;\n count += 1;\n } else {\n break;\n }\n }\n setVisibleCount(count);\n }, [items.length]);\n\n const itemsKey = items.map((item) => item.value).join(\"|\");\n\n useLayoutEffect(() => {\n recompute();\n // Re-measure when the set of chips or the delete affordance changes.\n }, [recompute, itemsKey, canDelete]);\n\n useEffect(() => {\n const container = containerRef.current;\n if (!container || typeof ResizeObserver === \"undefined\") return;\n const observer = new ResizeObserver(() => recompute());\n observer.observe(container);\n return () => observer.disconnect();\n }, [recompute]);\n\n const hiddenCount = Math.max(items.length - visibleCount, 0);\n\n const renderChip = (item: SelectedItem) => (\n <Chip\n key={item.value}\n size=\"small\"\n label={item.label}\n sx={{ flexShrink: 0, maxWidth: \"100%\" }}\n onMouseDown={(event) => event.stopPropagation()}\n onDelete={canDelete ? (event) => onDelete(item.value, event) : undefined}\n />\n );\n\n const badge = (count: number) => (\n <Chip\n color=\"grey\"\n size=\"small\"\n label={`+${count}`}\n sx={{ flexShrink: 0 }}\n onMouseDown={(event) => event.stopPropagation()}\n />\n );\n\n return (\n <Box sx={{ position: \"relative\", flex: 1, minWidth: 0, display: \"flex\" }}>\n {/* Off-screen measurement row: always renders every chip + a badge. */}\n <Box\n ref={measureRef}\n aria-hidden\n sx={{\n position: \"absolute\",\n top: 0,\n left: 0,\n visibility: \"hidden\",\n pointerEvents: \"none\",\n height: 0,\n overflow: \"hidden\",\n display: \"flex\",\n gap: 0.5,\n }}\n >\n {items.map((item) => renderChip(item))}\n {badge(items.length)}\n </Box>\n\n <Box\n ref={containerRef}\n sx={{\n flex: 1,\n minWidth: 0,\n display: \"flex\",\n flexWrap: \"nowrap\",\n alignItems: \"center\",\n gap: 0.5,\n overflow: \"hidden\",\n }}\n >\n {items.slice(0, visibleCount).map((item) => renderChip(item))}\n {hiddenCount > 0 && badge(hiddenCount)}\n </Box>\n </Box>\n );\n}\n\nexport type MultiSelectProps = Omit<\n SelectProps,\n | \"multiple\"\n | \"value\"\n | \"defaultValue\"\n | \"onChange\"\n | \"renderValue\"\n | \"children\"\n> & {\n /** Options rendered as checkbox menu items. */\n options: SelectOption[];\n /** Currently selected values (controlled). */\n value?: string[];\n /** Initially selected values (uncontrolled). */\n defaultValue?: string[];\n /** Called with the next array of selected values. */\n onChange?: (value: string[], event: SelectChangeEvent<string[]>) => void;\n /** Minimum number of values that must stay selected. @default 1 */\n min?: number;\n /** Maximum number of values that can be selected. Unlimited when omitted. */\n max?: number;\n /** Override how the selected values are summarised in the closed control. */\n renderValue?: (selected: string[]) => ReactNode;\n};\n\n/**\n * Multi-select built on our `Select` (so it inherits the auto-wired ids and the\n * standalone / composed `FormControl` behaviour). Each option renders as a\n * checkbox menu item, and the closed control shows the selection as removable\n * chips by default.\n *\n * The selection is bounded by `min` (default 1, so the last value can't be\n * removed) and `max` (unlimited by default): options that would breach either\n * bound are disabled, and the constraints are also enforced on change.\n *\n * Works controlled (`value`) or uncontrolled (`defaultValue`).\n */\nexport const MultiSelect = forwardRef<HTMLDivElement, MultiSelectProps>(\n function MultiSelect(\n {\n options,\n value,\n defaultValue = [],\n onChange,\n renderValue,\n min = 1,\n max,\n disabled,\n ...rest\n },\n ref,\n ) {\n const isControlled = value !== undefined;\n const [internal, setInternal] = useState<string[]>(defaultValue);\n const selected = isControlled ? value : internal;\n\n const labelByValue = useMemo(() => {\n const map = new Map<string, string>();\n options.forEach((option) => map.set(option.value, option.label));\n return map;\n }, [options]);\n\n const atMax = max !== undefined && selected.length >= max;\n const atMin = selected.length <= min;\n\n const commit = (next: string[], event: SelectChangeEvent<string[]>) => {\n if (!isControlled) setInternal(next);\n onChange?.(next, event);\n };\n\n const handleChange = (event: SelectChangeEvent<string[]>) => {\n const next = event.target.value;\n const nextValues = typeof next === \"string\" ? next.split(\",\") : next;\n\n // Enforce the bounds even if a disabled item is somehow toggled.\n const isAdding = nextValues.length > selected.length;\n if (isAdding && max !== undefined && nextValues.length > max) return;\n const isRemoving = nextValues.length < selected.length;\n if (isRemoving && nextValues.length < min) return;\n\n commit(nextValues, event);\n };\n\n const handleDelete = (valueToRemove: string, event: MouseEvent) => {\n if (selected.length <= min) return;\n const nextValues = selected.filter((v) => v !== valueToRemove);\n // Synthesise a select-shaped event so consumers still read the new value.\n const syntheticEvent = {\n ...event,\n target: { value: nextValues, name: (rest as { name?: string }).name },\n } as unknown as SelectChangeEvent<string[]>;\n commit(nextValues, syntheticEvent);\n };\n\n const canDelete = !disabled && selected.length > min;\n\n const defaultRenderValue = (sel: string[]) => (\n <SelectedChips\n items={sel.map((v) => ({ value: v, label: labelByValue.get(v) ?? v }))}\n canDelete={canDelete}\n onDelete={handleDelete}\n />\n );\n\n return (\n <Select\n ref={ref}\n multiple\n disabled={disabled}\n value={selected}\n onChange={handleChange as SelectProps[\"onChange\"]}\n renderValue={\n (renderValue ?? defaultRenderValue) as SelectProps[\"renderValue\"]\n }\n {...rest}\n >\n {options.map((option) => {\n const isSelected = selected.includes(option.value);\n const isDisabled = (atMax && !isSelected) || (atMin && isSelected);\n return (\n <MenuItem\n key={option.value}\n value={option.value}\n disabled={isDisabled}\n sx={{\n display: \"flex\",\n alignItems: \"center\",\n gap: 1,\n }}\n >\n <Checkbox checked={isSelected} disableRipple tabIndex={-1} />\n\n <Box\n component=\"span\"\n sx={{\n flex: 1,\n }}\n >\n {option.label}\n </Box>\n </MenuItem>\n );\n })}\n </Select>\n );\n },\n);\n","import { Controller, type FieldValues } from \"react-hook-form\";\nimport { MultiSelect, type MultiSelectProps } from \"../multi-select\";\nimport type { BaseFieldProps } from \"./field-types\";\nimport { useResolvedControl } from \"./use-field-control\";\n\nexport type MultiSelectFieldProps<T extends FieldValues> = BaseFieldProps<T> &\n Omit<MultiSelectProps, \"name\" | \"value\" | \"defaultValue\" | \"error\">;\n\n/**\n * `MultiSelect` connected to react-hook-form via `Controller`. Reads `control` from\n * the nearest `FormProvider` when the prop is omitted.\n */\nexport const MultiSelectField = <T extends FieldValues>({\n name,\n control,\n rules,\n disabled,\n label,\n helperText,\n options,\n ...rest\n}: MultiSelectFieldProps<T>) => {\n const resolved = useResolvedControl(control);\n\n return (\n <Controller\n control={resolved}\n name={name}\n rules={rules}\n render={({ field, fieldState }) => (\n <MultiSelect\n {...rest}\n {...field}\n label={label}\n options={options}\n error={!!fieldState.error}\n helperText={fieldState.error?.message ?? helperText}\n disabled={disabled ?? field.disabled}\n />\n )}\n />\n );\n};\n","import { SxProps, Theme } from \"@mui/material\";\nimport { palette, spacing } from \"../tokens\";\n\n/**\n * Styling for the `NumberInput` stepper, trailing unit and leading icon. These\n * are exported as `sx` objects the component applies (there is no dedicated MUI\n * slot to override globally), keeping the component lean while the visual tokens\n * live here, mirroring the shared building blocks in `field-base`.\n */\n\n/** Applied to the `OutlinedInput`: drop the trailing padding, lay the parts in a row. */\nexport const numberInputRootSx: SxProps<Theme> = {\n pr: 0,\n display: \"flex\",\n \"& .MuiInputAdornment-positionEnd\": { mr: \"0.5rem\" },\n};\n\n/** Root style when the label is rendered outside the field. */\nexport const numberInputExternalLabelRootSx: SxProps<Theme> = [\n numberInputRootSx,\n {\n alignItems: \"center\",\n \"& .MuiInputBase-input\": {\n paddingBlockStart: spacing(1),\n paddingBlockEnd: spacing(1),\n },\n \"& .MuiInputAdornment-positionStart\": {\n marginTop: spacing(0.5),\n },\n },\n];\n\n/** The stacked +/- buttons. Kept as a row of circular icon buttons. */\nexport const numberInputStepperSx: SxProps<Theme> = {\n display: \"flex\",\n flexDirection: \"row\",\n ml: 0,\n gap: 0.5,\n \"& button\": {\n flex: 1,\n borderColor: palette.border.subtle,\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n },\n};\n\n/**\n * End adornment wrapper when a `unit` is present — lays the unit (and, if shown,\n * the steppers) in a row that stretches to the field's full height so the unit\n * divider runs edge to edge.\n */\nexport const numberInputEndSx: SxProps<Theme> = {\n ml: 0,\n gap: 1,\n height: \"auto\",\n maxHeight: \"none\",\n alignSelf: \"stretch\",\n};\n\n/** Trailing unit text, separated from the value by a light divider. */\nexport const numberInputUnitSx: SxProps<Theme> = {\n display: \"flex\",\n alignItems: \"center\",\n alignSelf: \"stretch\",\n pl: \"0.75rem\",\n color: palette.text.subtle,\n borderLeft: \"1px solid\",\n borderColor: palette.border.subtle,\n whiteSpace: \"nowrap\",\n};\n\n/** Leading decorative icon. */\nexport const numberInputStartSx: SxProps<Theme> = {\n color: palette.text.subtle,\n};\n","import { NumberField as BaseNumberField } from \"@base-ui/react/number-field\";\nimport { Box, useFormControl } from \"@mui/material\";\nimport IconButton from \"@mui/material/IconButton\";\nimport InputAdornment from \"@mui/material/InputAdornment\";\nimport OutlinedInput from \"@mui/material/OutlinedInput\";\nimport { type SxProps, type Theme } from \"@mui/material/styles\";\nimport { Minus, Plus } from \"lucide-react\";\nimport { useId, type ReactNode } from \"react\";\nimport { FormControl, useFormField } from \".\";\nimport { createTranslation } from \"../../i18n\";\nimport {\n numberInputExternalLabelRootSx,\n numberInputEndSx,\n numberInputRootSx,\n numberInputStartSx,\n numberInputStepperSx,\n numberInputUnitSx,\n} from \"../../theme/components/number-input.theme\";\nimport { FormHelperText } from \"./form-control/form-helper-text\";\nimport { FormLabel } from \"./form-control/form-label\";\nimport { InputLabel } from \"./input-label\";\n\nexport type NumberInputProps = BaseNumberField.Root.Props & {\n /** Floating label. Rendered as an `InputLabel` and linked automatically. */\n label?: ReactNode;\n /** Where the label sits when this component renders one itself. @default \"inside\" */\n labelPlacement?: \"inside\" | \"outside\";\n /** Helper / error text shown below the control and linked via `aria-describedby`. */\n helperText?: ReactNode;\n /** Renders the field in its error state (border, label and helper colour). */\n error?: boolean;\n /** Reflects `required` onto the control and the label asterisk. */\n required?: boolean;\n /** Disables the input and the stepper buttons. */\n disabled?: boolean;\n /** Control density. @default \"medium\" */\n size?: \"small\" | \"medium\";\n /** Placeholder shown while the field is empty. */\n placeholder?: string;\n /**\n * Decorative leading icon (e.g. a category glyph). Rendered `aria-hidden`, so\n * the visible label must carry the meaning.\n */\n startIcon?: ReactNode;\n /**\n * Trailing unit shown inside the field (e.g. `kr`, `kr/mnd`). Rendered as real\n * text linked to the input via `aria-describedby` — not a placeholder — so it\n * is announced and survives typing.\n */\n unit?: ReactNode;\n /**\n * Whether to render the increment / decrement stepper buttons.\n * @default true\n */\n showSteppers?: boolean;\n};\n\ntype NumberInputControlProps = BaseNumberField.Root.Props & {\n labelPlacement?: \"inside\" | \"outside\";\n size?: \"small\" | \"medium\";\n placeholder?: string;\n startIcon?: ReactNode;\n unit?: ReactNode;\n showSteppers?: boolean;\n};\n\nfunction SSRInitialFilled(\n _: Pick<BaseNumberField.Root.Props, \"value\" | \"defaultValue\">,\n) {\n return null;\n}\nSSRInitialFilled.muiName = \"Input\";\n\nfunction NumberInputControl({\n labelPlacement = \"inside\",\n size = \"medium\",\n disabled,\n required,\n placeholder,\n startIcon,\n unit,\n showSteppers = true,\n ...rootProps\n}: NumberInputControlProps) {\n const ctx = useFormField();\n const muiFormControl = useFormControl();\n const unitId = useId();\n const stepperLabels = useStepperLabels();\n const resolvedDisabled = disabled ?? muiFormControl?.disabled;\n const resolvedRequired = required ?? muiFormControl?.required;\n\n // The input is described by any combination of helper text + the trailing\n // unit, in reading order, and never points at an element that isn't rendered.\n const describedBy =\n [\n ctx?.hasHelperText ? ctx.ids.helperText : null,\n unit != null ? unitId : null,\n ]\n .filter(Boolean)\n .join(\" \") || undefined;\n const labelledBy = ctx?.ids.label;\n const usesExternalFormLabel = labelPlacement === \"outside\";\n const resolvedInputSx: SxProps<Theme> = usesExternalFormLabel\n ? numberInputExternalLabelRootSx\n : numberInputRootSx;\n\n const steppers = showSteppers ? (\n <>\n <BaseNumberField.Decrement\n render={<IconButton size={size} aria-label={stepperLabels.decrease} />}\n >\n <Minus size={16} />\n </BaseNumberField.Decrement>\n <BaseNumberField.Increment\n render={<IconButton size={size} aria-label={stepperLabels.increase} />}\n >\n <Plus size={16} />\n </BaseNumberField.Increment>\n </>\n ) : null;\n\n let endAdornment: ReactNode;\n if (unit != null) {\n endAdornment = (\n <InputAdornment position=\"end\" sx={numberInputEndSx}>\n <Box component=\"span\" id={unitId} sx={numberInputUnitSx}>\n {unit}\n </Box>\n {showSteppers && <Box sx={numberInputStepperSx}>{steppers}</Box>}\n </InputAdornment>\n );\n } else if (showSteppers) {\n // Keep the stepper-only markup identical to before.\n endAdornment = (\n <InputAdornment position=\"end\" sx={numberInputStepperSx}>\n {steppers}\n </InputAdornment>\n );\n }\n\n return (\n <BaseNumberField.Root\n {...rootProps}\n disabled={resolvedDisabled}\n required={resolvedRequired}\n render={(props) => (\n <div {...props} style={{ ...props.style, display: \"contents\" }} />\n )}\n >\n <BaseNumberField.Input\n id={ctx?.ids.control}\n render={(props, state) => (\n <OutlinedInput\n size={size}\n placeholder={placeholder}\n inputRef={props.ref}\n value={state.inputValue}\n onBlur={props.onBlur}\n onChange={props.onChange}\n onKeyUp={props.onKeyUp}\n onKeyDown={props.onKeyDown}\n onFocus={props.onFocus}\n slotProps={{\n input: {\n ...props,\n \"aria-labelledby\": labelledBy,\n \"aria-describedby\": describedBy,\n \"aria-invalid\": muiFormControl?.error ? true : undefined,\n },\n }}\n startAdornment={\n startIcon != null ? (\n <InputAdornment\n position=\"start\"\n aria-hidden\n sx={numberInputStartSx}\n >\n {startIcon}\n </InputAdornment>\n ) : undefined\n }\n endAdornment={endAdornment}\n sx={resolvedInputSx}\n />\n )}\n />\n </BaseNumberField.Root>\n );\n}\n\n/**\n * Numeric input built on Base UI's `NumberField` (value / min / max / step /\n * formatting) and MUI's `OutlinedInput` (look), with stacked increment /\n * decrement buttons.\n *\n * Works two ways, like `Input`:\n * - **Standalone (all-in-one):** pass `label` / `helperText` and it renders its\n * own `FormControl`, label and helper text, wiring all ids.\n * - **Composed:** drop it inside a `FormControl` and it picks up the shared ids\n * and state from context.\n *\n * For money and other open-ended amounts, set `showSteppers={false}` and use a\n * `unit` (e.g. `kr`) instead — a stepper is only helpful for small bounded\n * counts.\n */\nexport function NumberInput({\n label,\n labelPlacement = \"inside\",\n helperText,\n error,\n required,\n disabled,\n id,\n size = \"medium\",\n placeholder,\n startIcon,\n unit,\n showSteppers = true,\n ...rest\n}: NumberInputProps) {\n const ctx = useFormField();\n\n if (ctx) {\n return (\n <NumberInputControl\n {...rest}\n labelPlacement={labelPlacement}\n size={size}\n required={required}\n disabled={disabled}\n placeholder={placeholder}\n startIcon={startIcon}\n unit={unit}\n showSteppers={showSteppers}\n />\n );\n }\n\n return (\n <FormControl\n id={id}\n error={error}\n required={required}\n disabled={disabled}\n size={size}\n >\n <SSRInitialFilled value={rest.value} defaultValue={rest.defaultValue} />\n {label != null &&\n (labelPlacement === \"outside\" ? (\n <FormLabel>{label}</FormLabel>\n ) : (\n <InputLabel>{label}</InputLabel>\n ))}\n <NumberInputControl\n {...rest}\n labelPlacement={labelPlacement}\n size={size}\n required={required}\n disabled={disabled}\n placeholder={placeholder}\n startIcon={startIcon}\n unit={unit}\n showSteppers={showSteppers}\n />\n {helperText != null && (\n <FormHelperText error={error} role={error ? \"alert\" : undefined}>\n {helperText}\n </FormHelperText>\n )}\n </FormControl>\n );\n}\n\nconst useStepperLabels = createTranslation({\n increase: {\n no: \"Øk\",\n se: \"Öka\",\n fi: \"Lisää\",\n es: \"Aumentar\",\n },\n decrease: {\n no: \"Reduser\",\n se: \"Minska\",\n fi: \"Vähennä\",\n es: \"Disminuir\",\n },\n});\n","import { Controller, type FieldValues } from \"react-hook-form\";\nimport { NumberInput, type NumberInputProps } from \"../number-input\";\nimport type { BaseFieldProps } from \"./field-types\";\nimport { useResolvedControl } from \"./use-field-control\";\n\nexport type NumberFieldProps<T extends FieldValues> = BaseFieldProps<T> &\n Omit<\n NumberInputProps,\n \"name\" | \"value\" | \"defaultValue\" | \"error\" | \"onValueChange\"\n >;\n\n/**\n * `NumberInput` connected to react-hook-form via `Controller`. Reads `control`\n * from the nearest `FormProvider` when the prop is omitted. The form value is\n * the raw `number | null` from the field.\n */\nexport const NumberField = <T extends FieldValues>({\n name,\n control,\n rules,\n disabled,\n label,\n helperText,\n ...rest\n}: NumberFieldProps<T>) => {\n const resolved = useResolvedControl(control);\n\n return (\n <Controller\n control={resolved}\n name={name}\n rules={rules}\n render={({ field, fieldState }) => (\n <NumberInput\n {...rest}\n name={field.name}\n inputRef={field.ref}\n label={label}\n value={field.value ?? null}\n onValueChange={(value) => field.onChange(value)}\n onBlur={field.onBlur}\n error={!!fieldState.error}\n helperText={fieldState.error?.message ?? helperText}\n disabled={disabled ?? field.disabled}\n />\n )}\n />\n );\n};\n","import { Components, Theme } from \"@mui/material\";\nimport { ArrowDown } from \"lucide-react\";\nimport { createElement } from \"react\";\n\nimport {\n colors,\n durations,\n easings,\n fontSizes,\n fontWeights,\n palette,\n shape,\n spacing,\n transition,\n typography,\n} from \"../tokens\";\nimport { focusVisibleStyles } from \"../utils\";\n\nconst defaultExpandIcon = createElement(ArrowDown, { \"aria-hidden\": true });\n\n/**\n * Lea styling for MUI Accordion. Importing `Accordion` / `AccordionSummary` /\n * `AccordionDetails` from `@mui/material` (with the app `ThemeProvider` + this theme)\n * applies these defaults and style overrides.\n */\nexport const accordionTheme: Pick<\n Components<Theme>,\n \"MuiAccordion\" | \"MuiAccordionSummary\" | \"MuiAccordionDetails\"\n> = {\n MuiAccordion: {\n defaultProps: {\n disableGutters: true,\n elevation: 0,\n square: true,\n },\n styleOverrides: {\n root: {\n borderRadius: shape[\"4xl\"],\n backgroundColor: palette.bg.base,\n border: `1px solid ${palette.border.base}`,\n \"&::before\": {\n display: \"none\",\n },\n '&[data-variant=\"filled\"]': {\n border: \"none\",\n backgroundColor: palette.bg.base,\n },\n },\n },\n },\n MuiAccordionSummary: {\n defaultProps: {\n expandIcon: defaultExpandIcon,\n },\n styleOverrides: {\n root: {\n paddingBlock: spacing(1),\n paddingInline: spacing(2),\n borderRadius: shape[\"4xl\"],\n transition: transition(\n [\"border-color\", \"background-color\"],\n durations.emphasis,\n easings.standard,\n ),\n border: \"1px solid transparent\",\n \"&:hover\": {\n borderColor: palette.border.strong,\n },\n \"&:active\": {\n backgroundColor: colors.purple[50],\n },\n ...focusVisibleStyles,\n \"&:focus-visible\": {\n ...focusVisibleStyles[\"&:focus-visible\"],\n outlineOffset: \"0.125rem\",\n },\n },\n content: {\n marginLeft: 0,\n marginBlock: 0,\n color: palette.text.base,\n fontFamily: typography.fontFamily,\n fontSize: fontSizes.md,\n fontWeight: fontWeights.medium,\n lineHeight: 1.5,\n },\n expandIconWrapper: {\n transition: transition(\n [\"transform\"],\n durations.emphasis,\n easings.standard,\n ),\n \"&.Mui-expanded\": {\n transform: \"rotate(180deg)\",\n },\n },\n },\n },\n MuiAccordionDetails: {\n styleOverrides: {\n root: {\n padding: spacing(2),\n fontFamily: typography.fontFamily,\n fontSize: fontSizes.md,\n lineHeight: 1.5,\n color: palette.text.base,\n },\n },\n },\n};\n","import {\n durations,\n easings,\n fontSizes,\n fontWeights,\n palette,\n shape,\n spacing,\n transition,\n} from \"../tokens\";\nimport { focusVisibleStyles } from \"../utils\";\n\nexport const actionButtonVariant = {\n props: { variant: \"action\" as const },\n style: {\n ...focusVisibleStyles,\n color: palette.text.base,\n backgroundColor: palette.bg.base,\n outline: `1px solid ${palette.border.strong}`,\n border: \"none\",\n borderRadius: shape.full,\n paddingInlineStart: spacing(3.5),\n paddingInlineEnd: spacing(0.5),\n paddingBlock: spacing(0.5),\n fontSize: fontSizes.lg,\n textTransform: \"uppercase\" as const,\n fontWeight: fontWeights.bold,\n svg: {\n display: \"inline-block\",\n width: 48,\n height: 48,\n borderRadius: shape.full,\n marginInlineStart: spacing(3),\n backgroundColor: palette.bg.contrast,\n color: palette.text.contrast,\n transition: [\n transition([\"transform\"], durations.emphasis, easings.spring),\n transition([\"background-color\"]),\n ].join(\", \"),\n },\n \"&:hover\": {\n svg: {\n transform: \"rotate(-45deg) scale(1.08)\",\n backgroundColor: palette.purple.base,\n },\n },\n \"& .MuiTouchRipple-root\": {\n color: palette.purple.subtle,\n },\n \"&:active\": {\n outline: `2px solid ${palette.purple.base}`,\n color: palette.text.base,\n },\n },\n};\n","import { Components, Theme } from \"@mui/material\";\nimport {\n colors,\n fontSizes,\n fontWeights,\n palette,\n shape,\n spacing,\n} from \"../tokens\";\n\nconst { status, text } = palette;\n\ntype Severity = \"success\" | \"info\" | \"warning\" | \"error\";\n\nconst severities: Severity[] = [\"success\", \"info\", \"warning\", \"error\"];\n\n/**\n * Non-semantic colours, for messages that shouldn't read as a status. Same\n * names as `Chip` so `color=\"purple\"` means the same thing library-wide.\n */\nconst brandColours = {\n purple: { base: palette.purple.base, subtle: palette.purple.subtle },\n grey: { base: colors.neutral[700], subtle: colors.neutral[100] },\n} as const;\n\n/** The three `variant` recipes shared by every severity and brand colour. */\nconst colourStyles = ({ base, subtle }: { base: string; subtle: string }) => ({\n standard: {\n backgroundColor: subtle,\n color: text.base,\n \"& .MuiAlert-icon\": { color: base },\n },\n filled: {\n backgroundColor: base,\n color: text.contrast,\n \"& .MuiAlert-icon\": { color: text.contrast },\n },\n outlined: {\n backgroundColor: \"transparent\",\n color: text.base,\n border: \"1px solid\",\n borderColor: base,\n \"& .MuiAlert-icon\": { color: base },\n },\n});\n\nexport const alertTheme: Components<Theme>[\"MuiAlert\"] = {\n defaultProps: {\n variant: \"standard\",\n },\n styleOverrides: {\n root: {\n borderRadius: shape.xl,\n alignItems: \"flex-start\",\n fontSize: fontSizes.md,\n fontWeight: fontWeights.regular,\n lineHeight: 1.5,\n padding: `${spacing(1)} ${spacing(2)}`,\n gap: spacing(1.5),\n \"& .MuiAlertTitle-root\": {\n marginBottom: 0,\n },\n \"& .MuiAlert-action .MuiIconButton-root\": {\n borderColor: \"transparent\",\n },\n \"& .MuiAlert-action\": {\n padding: 0,\n },\n // `size` is not a MUI Alert prop, so the wrapper passes it as an\n // attribute rather than letting an invalid `size` reach the DOM.\n '&[data-size=\"sm\"]': {\n fontSize: fontSizes.sm,\n padding: `${spacing(0.5)} ${spacing(1.5)}`,\n gap: spacing(1),\n \"& .MuiAlertTitle-root\": {\n fontSize: fontSizes.sm,\n },\n \"& .MuiAlert-icon\": {\n fontSize: fontSizes.lg,\n minHeight: spacing(2.5),\n flexShrink: 0,\n },\n \"& .MuiAlert-message\": {\n // Match the icon's leftover MUI padding so the first line sits on\n // the same centre line as the glyph, the way `lg` already does.\n paddingBlock: spacing(0.7),\n },\n },\n },\n icon: {\n alignItems: \"center\",\n marginRight: 0,\n minHeight: \"1.5rem\",\n flexShrink: 0,\n },\n message: {\n padding: 0,\n paddingBlock: spacing(0.7),\n display: \"flex\",\n flexDirection: \"column\",\n },\n },\n variants: [\n ...severities.flatMap((severity) => {\n const { standard, filled, outlined } = colourStyles(status[severity]);\n\n return [\n { props: { severity, variant: \"standard\" as const }, style: standard },\n { props: { severity, variant: \"filled\" as const }, style: filled },\n { props: { severity, variant: \"outlined\" as const }, style: outlined },\n ];\n }),\n // Listed after the severities so an explicit `color` wins over the colour\n // implied by `severity` when both match.\n ...Object.entries(brandColours).flatMap(([key, tokens]) => {\n const color = key as keyof typeof brandColours;\n const { standard, filled, outlined } = colourStyles(tokens);\n\n return [\n { props: { color, variant: \"standard\" as const }, style: standard },\n { props: { color, variant: \"filled\" as const }, style: filled },\n { props: { color, variant: \"outlined\" as const }, style: outlined },\n ];\n }),\n ],\n};\n","import { CSSObject } from \"@mui/material\";\nimport { palette } from \"../tokens\";\n\n/**\n * Shared building blocks for the outlined form fields (text `Input`, `Select`,\n * `Autocomplete` and the date-picker trigger). Keeping height, padding, the\n * collapsed notch and the border-state colours in one place means editing a\n * field's look here updates every input at once; component-specific styling\n * stays in each component's own theme file.\n */\n\n// Every single-line field is the same fixed height — only the multiline\n// textarea is allowed to grow (the input theme applies this conditionally).\nexport const FIELD_HEIGHT = \"54px\";\n\n// Vertical padding leaves room for the floated label above the value, so the\n// text input, select, autocomplete and picker all line up at the same height.\nexport const fieldPadding = {\n paddingInlineStart: \"0.9rem\",\n paddingBlockStart: \"1.5rem\",\n paddingBlockEnd: \"0.5rem\",\n} as const;\n\n/**\n * We draw the field border ourselves, so MUI's notch and its legend are\n * collapsed. Parameterised by the notched-outline class because\n * `OutlinedInput` and `PickersOutlinedInput` name that element differently.\n */\nexport const collapsedNotch = (outlineClass: string): CSSObject => ({\n [`& .${outlineClass}`]: {\n top: 0,\n inset: 0,\n },\n [`& .${outlineClass} legend`]: {\n display: \"none\",\n },\n});\n\n/**\n * Hover / focus / error border treatment shared by every outlined field.\n * Parameterised by the notched-outline class for the same reason as\n * `collapsedNotch`.\n *\n * Focus is keyed off `:focus-within` rather than `.Mui-focused`: the latter is\n * not applied to the `OutlinedInput` root that `Autocomplete` injects its input\n * into, so `:focus-within` is the only selector that lights up the focus border\n * across every field consistently.\n */\nexport const fieldBorderStates = (outlineClass: string): CSSObject => ({\n [`&:hover:not(:focus-within):not(.Mui-disabled):not(.Mui-error) .${outlineClass}`]:\n {\n borderWidth: \"2px\",\n borderColor: palette.border.strong,\n },\n [`&:focus-within:not(.Mui-error) .${outlineClass}`]: {\n borderWidth: \"2px\",\n borderColor: palette.border.accent,\n },\n [`&.Mui-error .${outlineClass}`]: {\n borderWidth: \"2px\",\n borderColor: palette.status.error.base,\n },\n [`&.Mui-error:hover:not(:focus-within):not(.Mui-disabled) .${outlineClass}`]: {\n borderWidth: \"2px\",\n borderColor: palette.status.error.base,\n },\n [`&.Mui-error:focus-within .${outlineClass}`]: {\n borderWidth: \"2px\",\n borderColor: palette.status.error.base,\n },\n});\n","import { Components, Theme } from \"@mui/material\";\nimport { ChevronDown, X } from \"lucide-react\";\nimport { createElement } from \"react\";\nimport { palette, shape, shadows } from \"../tokens\";\nimport { FIELD_HEIGHT, fieldPadding } from \"./field-base\";\n\nexport const autocompleteTheme: Components<Theme>[\"MuiAutocomplete\"] = {\n defaultProps: {\n fullWidth: true,\n popupIcon: createElement(ChevronDown, { size: 20 }),\n clearIcon: createElement(X, { size: 18 }),\n },\n styleOverrides: {\n root: {\n backgroundColor: palette.bg.base,\n borderRadius: shape.xl,\n },\n // The OutlinedInput root that Autocomplete injects its input into.\n inputRoot: {\n paddingTop: 0,\n paddingBottom: 0,\n paddingLeft: 0,\n \"& .MuiAutocomplete-input\": {\n ...fieldPadding,\n paddingInlineEnd: \"0.9rem\",\n },\n // Leave room for the clear + popup indicators, which sit absolutely at the end.\n \"&:has(.MuiAutocomplete-endAdornment) .MuiAutocomplete-input\": {\n paddingInlineEnd: \"4rem\",\n },\n // Multiple mode: selected values render as chips inside the field. Let them\n // wrap in the value area below the floated label and grow the field to fit.\n // The extra `adornedStart` class outranks the shared fixed-height rule.\n \"&.MuiInputBase-adornedStart:has(.MuiAutocomplete-tag)\": {\n height: \"auto\",\n minHeight: FIELD_HEIGHT,\n flexWrap: \"wrap\",\n alignItems: \"center\",\n gap: \"4px\",\n paddingTop: \"1.5rem\",\n paddingBottom: \"0.5rem\",\n paddingInlineStart: \"0.65rem\",\n \"& .MuiAutocomplete-tag\": {\n margin: 0,\n },\n \"& .MuiAutocomplete-input\": {\n padding: 0,\n paddingInlineStart: \"0.25rem\",\n minWidth: \"40px\",\n width: \"auto\",\n flexGrow: 1,\n },\n },\n },\n endAdornment: {\n right: \"0.75rem\",\n },\n // The popup / clear controls are `IconButton`s, which the global icon-button\n // theme gives a circular border — reset that so they read as plain glyphs.\n popupIndicator: {\n border: \"none\",\n padding: \"0.25rem\",\n color: palette.text.base,\n \"&:hover\": { backgroundColor: \"transparent\" },\n },\n clearIndicator: {\n border: \"none\",\n padding: \"0.25rem\",\n color: palette.text.base,\n \"&:hover\": { backgroundColor: \"transparent\" },\n },\n paper: {\n borderTopLeftRadius: \"0\",\n borderTopRightRadius: \"0\",\n borderBottomLeftRadius: shape.xl,\n borderBottomRightRadius: shape.xl,\n boxShadow: shadows.lg,\n border: `1px solid ${palette.border.accent}`,\n marginTop: 0,\n },\n listbox: {\n paddingInline: 4,\n paddingBlock: 4,\n maxHeight: 200,\n },\n },\n};\n","export default \"data:font/woff;base64,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\"","export default \"data:font/woff;base64,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\"","export default \"data:font/woff;base64,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\"","export default \"data:font/woff;base64,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\"","export default \"data:font/woff;base64,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\"","export default \"data:font/woff;base64,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\"","import ClashGroteskB from \"@/assets/fonts/ClashGrotesk-Bold.woff\";\nimport ClashGroteskEL from \"@/assets/fonts/ClashGrotesk-Extralight.woff\";\nimport ClashGroteskL from \"@/assets/fonts/ClashGrotesk-Light.woff\";\nimport ClashGroteskM from \"@/assets/fonts/ClashGrotesk-Medium.woff\";\nimport ClashGroteskR from \"@/assets/fonts/ClashGrotesk-Regular.woff\";\nimport ClashGroteskSB from \"@/assets/fonts/ClashGrotesk-Semibold.woff\";\nimport { Components, Theme } from \"@mui/material\";\n\n// One @font-face per weight so each requested font-weight maps to the matching\n// file (the variable .woff collapses every weight onto a single face, so we\n// keep the static faces). `font-display: optional` renders ClashGrotesk only if\n// it's ready almost immediately, otherwise it keeps the system fallback for the\n// page load — no mid-render swap to Arial, no layout shift — and caches the font\n// for next time.\nconst fontFace = (src: string, weight: number) => `\n @font-face {\n font-family: 'ClashGrotesk';\n src: url(${src}) format('woff');\n font-weight: ${weight};\n font-style: normal;\n font-display: optional;\n }\n`;\n\nexport const baselineCss: Components<Theme>[\"MuiCssBaseline\"] = {\n styleOverrides: `\n ${fontFace(ClashGroteskEL, 200)}\n ${fontFace(ClashGroteskL, 300)}\n ${fontFace(ClashGroteskR, 400)}\n ${fontFace(ClashGroteskM, 500)}\n ${fontFace(ClashGroteskSB, 600)}\n ${fontFace(ClashGroteskB, 700)}\n\n * {\n box-sizing: border-box;\n }\n\n body {\n font-family: 'ClashGrotesk', sans-serif;\n -webkit-font-smoothing: antialiased;\n -moz-osx-font-smoothing: grayscale;\n }\n `,\n};\n","import { Components, Theme } from \"@mui/material\";\nimport {\n durations,\n easings,\n fontWeights,\n palette,\n shape,\n spacing,\n transition,\n typography,\n} from \"../tokens\";\nimport { focusVisibleStyles } from \"../utils\";\n\nexport const buttonTheme: Components<Theme>[\"MuiButton\"] = {\n defaultProps: {\n variant: \"contained\",\n color: \"primary\",\n disableElevation: true,\n disableRipple: true,\n },\n styleOverrides: {\n root: {\n ...focusVisibleStyles,\n color: palette.text.contrast,\n borderRadius: shape[\"full\"],\n textTransform: \"none\",\n svg: {\n flexShrink: 0,\n },\n \"&:disabled\": {\n backgroundColor: palette.bg.subtle,\n color: palette.text.subtle,\n },\n \"&:enabled:hover\": {\n cursor: \"pointer\",\n },\n },\n\n contained: {\n backgroundColor: palette.purple.base,\n \"&:enabled:hover\": {\n backgroundColor: palette.purple.hover,\n },\n },\n colorError: {\n \"&:enabled:hover\": {\n backgroundColor: palette.status.error.subtle,\n },\n },\n colorInfo: {\n display: \"flex\",\n justifyContent: \"space-between\",\n backgroundColor: palette.bg.base,\n color: palette.text.base,\n \"&:enabled:hover\": {\n cursor: \"pointer\",\n backgroundColor: palette.bg.base,\n },\n padding: \"0.5rem 1rem\",\n width: \"100%\",\n marginBottom: \"0.5rem\",\n },\n\n outlined: {\n color: palette.text.base,\n outline: `1px solid ${palette.border.strong}`,\n border: \"none\",\n \"&:hover\": {\n outlineColor: palette.purple.base,\n color: palette.purple.base,\n },\n \"& .MuiTouchRipple-root\": {\n color: palette.purple.subtle,\n },\n \"&:active\": {\n outline: `2px solid ${palette.purple.base}`,\n color: palette.text.base,\n },\n },\n text: {\n color: palette.text.base,\n backgroundColor: palette.bg.base,\n borderRadius: shape.lg,\n fontWeight: fontWeights.regular,\n lineHeight: 0.8,\n paddingBlock: \"unset !important\",\n paddingInline: \"unset !important\",\n padding: \"unset !important\",\n gap: spacing(1),\n transition: transition([\"gap\"], durations.normal, easings.spring),\n textUnderlineOffset: \"0.3rem\",\n \"&:enabled:hover\": {\n color: palette.purple.base,\n textDecoration: \"underline\",\n gap: spacing(2),\n },\n },\n sizeSmall: {\n paddingBlock: spacing(1),\n paddingInline: spacing(2),\n fontSize: typography.body2.fontSize,\n },\n sizeLarge: {\n paddingBlock: spacing(1.5),\n paddingInline: spacing(2),\n fontSize: typography.body1.fontSize,\n },\n },\n};\n","import { Components, Theme } from \"@mui/material\";\nimport { palette, shape } from \"../tokens\";\n\nexport const cardTheme: Components<Theme>[\"MuiCard\"] = {\n defaultProps: {\n variant: \"outlined\",\n elevation: 0,\n },\n styleOverrides: {\n root: {\n borderRadius: shape[\"4xl\"],\n border: \"1px solid\",\n borderColor: palette.border.base,\n },\n },\n};\n","import { Components, Theme } from \"@mui/material\";\nimport { colors, fontSizes, fontWeights, shape, spacing } from \"../tokens\";\n\nconst { purple, blue, teal, orange, neutral, white } = colors;\n\nconst accentSlots = (foreground: string, background: string) => ({\n \"& .MuiChip-avatar\": {\n backgroundColor: foreground,\n color: background,\n marginLeft: spacing(0.5),\n },\n \"& .MuiChip-deleteIcon\": {\n backgroundColor: foreground,\n color: background,\n borderRadius: shape.full,\n \"&:hover\": {\n backgroundColor: foreground,\n color: background,\n opacity: 0.85,\n },\n },\n});\n\nconst chipColours = [\n {\n color: \"purple\" as const,\n filled: {\n backgroundColor: purple[100],\n color: purple[800],\n ...accentSlots(purple[800], purple[100]),\n },\n outlined: {\n backgroundColor: \"transparent\",\n borderColor: purple[600],\n color: purple[600],\n ...accentSlots(purple[100], purple[600]),\n },\n },\n {\n color: \"blue\" as const,\n filled: {\n backgroundColor: blue[100],\n color: blue[800],\n ...accentSlots(blue[800], blue[100]),\n },\n outlined: {\n backgroundColor: \"transparent\",\n borderColor: blue[600],\n color: blue[600],\n ...accentSlots(blue[600], white),\n },\n },\n {\n color: \"teal\" as const,\n filled: {\n backgroundColor: teal[100],\n color: teal[800],\n ...accentSlots(teal[800], teal[100]),\n },\n outlined: {\n backgroundColor: \"transparent\",\n borderColor: teal[700],\n color: teal[700],\n ...accentSlots(teal[100], teal[700]),\n },\n },\n {\n color: \"orange\" as const,\n filled: {\n backgroundColor: orange[100],\n color: orange[800],\n ...accentSlots(orange[800], orange[100]),\n },\n outlined: {\n backgroundColor: \"transparent\",\n borderColor: orange[600],\n color: orange[600],\n ...accentSlots(orange[100], orange[600]),\n },\n },\n {\n color: \"grey\" as const,\n filled: {\n backgroundColor: neutral[100],\n color: neutral[800],\n ...accentSlots(neutral[800], neutral[100]),\n },\n outlined: {\n backgroundColor: \"transparent\",\n borderColor: neutral[400],\n color: neutral[700],\n ...accentSlots(neutral[100], neutral[700]),\n },\n },\n];\n\nexport const chipTheme: Components<Theme>[\"MuiChip\"] = {\n defaultProps: {\n color: \"purple\",\n variant: \"filled\",\n size: \"medium\",\n },\n styleOverrides: {\n root: {\n borderRadius: shape.full,\n fontWeight: fontWeights.medium,\n textTransform: \"none\",\n border: \"1px solid transparent\",\n\n \"&:hover\": {\n opacity: 1,\n },\n },\n avatar: {\n width: 24,\n height: 24,\n fontSize: fontSizes.xs,\n },\n deleteIcon: {\n width: 20,\n height: 20,\n fontSize: fontSizes.sm,\n },\n sizeSmall: {\n fontSize: fontSizes.sm,\n height: \"auto\",\n \"& .MuiChip-avatar\": {\n width: 20,\n height: 20,\n },\n \"& .MuiChip-deleteIcon\": {\n width: 18,\n height: 18,\n },\n },\n sizeMedium: {\n fontSize: fontSizes.sm,\n height: \"auto\",\n padding: `${spacing(0.3)} ${spacing(0.2)}`,\n },\n },\n variants: chipColours.flatMap(({ color, filled, outlined }) => [\n {\n props: { color, variant: \"filled\" as const },\n style: filled,\n },\n {\n props: { color, variant: \"outlined\" as const },\n style: outlined,\n },\n ]),\n};\n","import { Components, Theme } from \"@mui/material\";\nimport { palette, durations, easings, shape, transition } from \"../tokens\";\n\nexport const checkboxTheme: Components<Theme>[\"MuiCheckbox\"] = {\n defaultProps: {\n disableRipple: true,\n },\n styleOverrides: {\n root: {\n padding: 0,\n\n // The box we render ourselves (checkbox.tsx) — this is what you see/style,\n // not MUI's default SVG icon.\n \"& .lea-checkbox-box\": {\n display: \"inline-flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n width: \"1.3rem\",\n height: \"1.3rem\",\n border: `2px solid ${palette.border.base}`,\n borderRadius: shape.sm,\n backgroundColor: palette.bg.base,\n color: palette.purple.contrast, // checkmark colour once checked\n transition: transition(\n [\"background-color\", \"border-color\"],\n durations.normal,\n ),\n \"&:hover\": {\n borderColor: palette.border.strong,\n },\n },\n\n // The checkmark starts \"undrawn\" (dash gap covers the whole path).\n \"& .lea-checkbox-check\": {\n width: \"100%\",\n height: \"100%\",\n \"& path\": {\n strokeDasharray: 1,\n strokeDashoffset: 1,\n transition: transition(\n [\"stroke-dashoffset\"],\n durations.emphasis,\n easings.spring,\n ),\n },\n },\n\n // Hover (unchecked only): darken the outline.\n \"&:hover:not(.Mui-checked) .lea-checkbox-box\": {\n borderColor: palette.text.base,\n },\n\n // Checked: purple fill + draw the checkmark in.\n \"&.Mui-checked .lea-checkbox-box\": {\n backgroundColor: palette.purple.base,\n borderColor: palette.purple.base,\n },\n \"&.Mui-checked .lea-checkbox-check path\": {\n strokeDashoffset: 0,\n },\n\n // Keyboard focus ring (mouse clicks won't trigger Mui-focusVisible).\n \"&.Mui-focusVisible .lea-checkbox-box\": {\n outline: `2px solid ${palette.purple.base}`,\n outlineOffset: 2,\n },\n\n \"&.Mui-disabled\": {\n opacity: 0.7,\n },\n },\n },\n};\n","import { Components, Theme } from \"@mui/material\";\nimport { fontSizes, palette, shadows, shape, spacing } from \"../tokens\";\nimport {\n FIELD_HEIGHT,\n collapsedNotch,\n fieldBorderStates,\n fieldPadding,\n} from \"./field-base\";\n\n// The picker's accessible field (PickersOutlinedInput) shares the outlined-field\n// sizing/border treatment with the other inputs; only the notched-outline class\n// name differs.\nconst NOTCH = \"MuiPickersOutlinedInput-notchedOutline\";\n\n/**\n * Styling for the MUI X Date Pickers surfaces. The day picker uses MUI's\n * `DateCalendar` day grid (with a custom centered `calendarHeader`, see\n * `calendar-header.tsx`); month/year configurations use MUI's standard themed\n * month / year grids. This file owns the visual treatment of the trigger field,\n * the desktop popover and the day / month / year grids, using design tokens.\n *\n * In `@mui/x-date-pickers` v9 the legacy single-`TextField` field structure was\n * removed, so the trigger is always the accessible `PickersTextField`. We theme\n * `MuiPickersOutlinedInput` here to match the library's `MuiOutlinedInput`\n * (collapsed notch, fixed height, shared padding) — that is what fixes the\n * label-over-border and spacing issues, since those theme keys differ.\n */\nexport const datePickerTheme: Pick<\n Components<Theme>,\n | \"MuiPickersOutlinedInput\"\n | \"MuiDateCalendar\"\n | \"MuiDayCalendar\"\n | \"MuiPickerDay\"\n | \"MuiMonthCalendar\"\n | \"MuiYearCalendar\"\n | \"MuiPickerPopper\"\n | \"MuiPickersLayout\"\n> = {\n MuiPickersOutlinedInput: {\n styleOverrides: {\n root: {\n boxSizing: \"border-box\",\n alignItems: \"flex-start\",\n padding: 0,\n borderRadius: shape.xl,\n height: FIELD_HEIGHT,\n lineHeight: \"normal\",\n\n // We draw the border ourselves, so collapse the notch and its legend.\n ...collapsedNotch(NOTCH),\n\n // --- Border states (shared with the other outlined fields) ---\n ...fieldBorderStates(NOTCH),\n\n // --- Adornments (the open-picker icon button) ---\n \"& .MuiInputAdornment-root\": {\n alignSelf: \"center\",\n },\n \"& .MuiInputAdornment-positionEnd\": {\n marginRight: spacing(2),\n },\n },\n sectionsContainer: {\n ...fieldPadding,\n paddingInlineEnd: \"0.9rem\",\n },\n },\n },\n MuiPickersLayout: {\n styleOverrides: {\n root: {\n // Always stack vertically (toolbar → calendar). MUI's grid otherwise\n // switches to a side-by-side landscape layout on wide screens, which is\n // wrong for both the popover and the bottom drawer.\n width: \"100%\",\n display: \"flex\",\n flexDirection: \"column\",\n gap: spacing(2),\n padding: spacing(3),\n paddingBlockEnd: spacing(1),\n \"& .MuiPickersLayout-contentWrapper\": {\n width: \"100%\",\n },\n },\n },\n },\n MuiDateCalendar: {\n styleOverrides: {\n root: {\n // Fill the input-width popover (see `sameWidthAsInput` in datepicker.tsx)\n // rather than MUI's fixed calendar width, so the grid lines up with the field.\n width: \"100%\",\n maxHeight: \"none\",\n },\n },\n },\n MuiDayCalendar: {\n styleOverrides: {\n header: {\n justifyContent: \"space-between\",\n },\n weekContainer: {\n justifyContent: \"space-between\",\n margin: 0,\n },\n weekDayLabel: {\n fontSize: fontSizes.sm,\n color: palette.text.subtle,\n },\n },\n },\n MuiPickerDay: {\n styleOverrides: {\n root: {\n width: 40,\n height: 40,\n fontSize: fontSizes.md,\n color: palette.text.base,\n backgroundColor: \"transparent\",\n \"&:hover, &:focus\": {\n backgroundColor: palette.bg.subtle,\n },\n \"&.MuiPickerDay-selected\": {\n backgroundColor: palette.purple.base,\n color: palette.purple.contrast,\n \"&:hover, &:focus\": {\n backgroundColor: palette.purple.hover,\n },\n },\n \"&.Mui-disabled, &.MuiPickerDay-disabled\": {\n color: palette.text.muted,\n },\n \"&.MuiPickerDay-today:not(.MuiPickerDay-selected)\": {\n outline: `1px solid ${palette.border.base}`,\n outlineOffset: -1,\n },\n },\n },\n },\n MuiMonthCalendar: {\n styleOverrides: {\n root: {\n width: \"100%\",\n justifyContent: \"space-between\",\n columnGap: 0,\n rowGap: spacing(1.5),\n },\n button: {\n flex: \"0 0 31%\",\n maxWidth: \"31%\",\n fontSize: fontSizes.md,\n fontWeight: 500,\n color: palette.text.base,\n backgroundColor: \"transparent\",\n borderRadius: shape[\"3xl\"],\n height: spacing(6),\n margin: 0,\n \"&:hover, &:focus\": {\n backgroundColor: palette.bg.subtle,\n },\n \"&.Mui-selected, &.MuiMonthCalendar-selected\": {\n backgroundColor: palette.purple.base,\n color: palette.purple.contrast,\n \"&:hover, &:focus\": {\n backgroundColor: palette.purple.hover,\n },\n },\n \"&.Mui-disabled, &.MuiMonthCalendar-disabled\": {\n backgroundColor: \"transparent\",\n color: palette.text.muted,\n },\n },\n },\n },\n MuiYearCalendar: {\n styleOverrides: {\n root: {\n width: \"100%\",\n justifyContent: \"space-between\",\n columnGap: 0,\n rowGap: spacing(1.5),\n // Keep MUI's default constrained, scrollable height so the calendar can\n // auto-scroll the current / selected year into view on open. Removing it\n // (maxHeight: none) makes the list grow full-height and never scroll.\n },\n button: {\n flex: \"0 0 31%\",\n maxWidth: \"31%\",\n fontSize: fontSizes.md,\n fontWeight: 500,\n color: palette.text.base,\n backgroundColor: \"transparent\",\n borderRadius: shape[\"3xl\"],\n height: spacing(6),\n margin: 0,\n \"&:hover, &:focus\": {\n backgroundColor: palette.bg.subtle,\n },\n \"&.Mui-selected, &.MuiYearCalendar-selected\": {\n backgroundColor: palette.purple.base,\n color: palette.purple.contrast,\n \"&:hover, &:focus\": {\n backgroundColor: palette.purple.hover,\n },\n },\n \"&.Mui-disabled, &.MuiYearCalendar-disabled\": {\n backgroundColor: \"transparent\",\n color: palette.text.muted,\n },\n },\n },\n },\n MuiPickerPopper: {\n styleOverrides: {\n paper: {\n // The popper itself is sized to the input width (see `sameWidthAsInput`);\n // make the paper fill it so the calendar lines up with the field.\n width: \"100%\",\n boxSizing: \"border-box\",\n borderRadius: shape.xl,\n boxShadow: shadows.md,\n border: `1px solid ${palette.border.subtle}`,\n },\n },\n },\n};\n","import { Components, Theme } from \"@mui/material\";\n\nimport {\n fontSizes,\n fontWeights,\n palette,\n shadows,\n shape,\n spacing,\n} from \"../tokens\";\n\nexport const dialogTheme: Pick<\n Components<Theme>,\n \"MuiDialog\" | \"MuiDialogTitle\" | \"MuiDialogContent\"\n> = {\n MuiDialog: {\n styleOverrides: {\n root: {\n \"& .MuiBackdrop-root\": {\n backgroundColor: \"rgba(15, 16, 16, 0.5)\",\n },\n },\n paper: {\n backgroundColor: palette.bg.base,\n color: palette.text.base,\n borderRadius: shape[\"4xl\"],\n boxShadow: shadows.xl,\n },\n },\n },\n MuiDialogTitle: {\n styleOverrides: {\n root: {\n display: \"flex\",\n alignItems: \"flex-start\",\n justifyContent: \"space-between\",\n gap: spacing(1),\n padding: `${spacing(3)} ${spacing(3)} ${spacing(2)}`,\n fontSize: fontSizes.lg,\n fontWeight: fontWeights.semibold,\n color: palette.text.base,\n },\n },\n },\n MuiDialogContent: {\n styleOverrides: {\n root: {\n padding: `0 ${spacing(3)} ${spacing(3)}`,\n color: palette.text.base,\n },\n },\n },\n};\n","import { Components, SxProps, Theme } from \"@mui/material\";\n\nimport { fontSizes, fontWeights, palette, shadows, spacing } from \"../tokens\";\n\nexport const drawerTheme: Pick<Components<Theme>, \"MuiDrawer\"> = {\n MuiDrawer: {\n defaultProps: {\n anchor: \"right\",\n elevation: 0,\n },\n styleOverrides: {\n root: {\n \"& .MuiBackdrop-root\": {\n backgroundColor: \"rgba(15, 16, 16, 0.5)\",\n },\n },\n paper: {\n display: \"flex\",\n flexDirection: \"column\",\n backgroundColor: palette.bg.base,\n color: palette.text.base,\n boxShadow: shadows.xl,\n \"&.MuiDrawer-paperAnchorLeft, &.MuiDrawer-paperAnchorRight\": {\n width: \"min(360px, 100vw)\",\n },\n },\n },\n },\n};\n\nexport const drawerHeaderSx: SxProps<Theme> = {\n display: \"flex\",\n alignItems: \"flex-start\",\n justifyContent: \"space-between\",\n gap: spacing(1),\n padding: `${spacing(3)} ${spacing(3)} ${spacing(2)}`,\n fontSize: fontSizes.lg,\n fontWeight: fontWeights.semibold,\n color: palette.text.base,\n};\n\nexport const drawerBodySx: SxProps<Theme> = {\n flex: 1,\n overflowY: \"auto\",\n padding: `0 ${spacing(3)} ${spacing(3)}`,\n color: palette.text.base,\n};\n","import { Components, Theme } from \"@mui/material\";\nimport { palette, fontWeights, spacing } from \"../tokens\";\n\nexport const formControlLabelTheme: Components<Theme>[\"MuiFormControlLabel\"] = {\n styleOverrides: {\n root: {\n margin: 0,\n display: \"flex\",\n alignItems: \"center\",\n gap: spacing(1.5),\n paddingBlockEnd: spacing(1),\n fontWeight: fontWeights.medium,\n color: palette.text.base,\n },\n },\n};\n","import { Components, Theme } from \"@mui/material\";\n\nexport const formControlTheme: Components<Theme>[\"MuiFormControl\"] = {\n defaultProps: {\n variant: \"outlined\",\n },\n styleOverrides: {\n root: {\n position: \"relative\",\n // While the label still rests over the field (not yet floated), hide the\n // input placeholder so the two never overlap. Once the label shrinks on\n // focus/fill this stops matching and MUI's default placeholder returns.\n // Centralised here because every field is wrapped by this FormControl,\n // and it works regardless of DOM structure (unlike MUI's sibling-based\n // rule, which misses Autocomplete's `renderInput`).\n \"&:has(.MuiInputLabel-root:not(.MuiInputLabel-shrink)) .MuiInputBase-input::placeholder\":\n {\n opacity: 0,\n },\n \"&:has(.MuiSelect-nativeInput[value='']) .MuiInputLabel-root.MuiInputLabel-shrink\":\n {\n transform: \"translate(14px, 17px) scale(1)\",\n maxWidth: \"calc(100% - 24px)\",\n top: 0,\n },\n \"&:has(.MuiSelect-nativeInput[value='']):has(.MuiInputAdornment-positionStart) .MuiInputLabel-root.MuiInputLabel-shrink\":\n {\n transform: \"translate(2.4rem, 17px) scale(1)\",\n maxWidth: \"calc(100% - 24px)\",\n top: 0,\n },\n \"&:has(.MuiInputAdornment-positionStart) .MuiInputLabel-root:not(.MuiInputLabel-shrink)\":\n {\n transform: \"translate(2.4rem, 17px) scale(1)\",\n },\n \"&:has(.MuiInputAdornment-positionStart) .MuiInputLabel-root.MuiInputLabel-shrink\":\n {\n transform: \"translate(2.4rem, -9px) scale(0.75)\",\n },\n },\n },\n};\n","import { Components, Theme } from \"@mui/material\";\nimport {\n palette,\n durations,\n easings,\n shape,\n spacing,\n transition,\n} from \"../tokens\";\nimport { focusVisibleStyles } from \"../utils\";\n\nexport const iconButtonTheme: Components<Theme>[\"MuiIconButton\"] = {\n defaultProps: {\n size: \"large\",\n },\n styleOverrides: {\n root: {\n ...focusVisibleStyles,\n borderRadius: shape.full,\n textTransform: \"none\",\n border: \"2px solid\",\n transition: [\n transition([\"background-color\"], durations.emphasis, easings.spring),\n transition([\"color\"], durations.emphasis, easings.spring),\n ].join(\", \"),\n svg: {\n flexShrink: 0,\n },\n },\n sizeSmall: {\n padding: spacing(1),\n svg: {\n width: 16,\n height: 16,\n },\n },\n sizeLarge: {\n padding: spacing(1),\n svg: {\n width: 24,\n height: 24,\n },\n },\n },\n variants: [\n {\n props: {\n color: \"primary\",\n },\n style: {\n borderColor: palette.border.strong,\n color: palette.text.base,\n \"&:hover\": {\n borderColor: palette.purple.base,\n backgroundColor: palette.purple.base,\n color: palette.purple.contrast,\n },\n },\n },\n {\n props: {\n color: \"secondary\",\n },\n style: {\n borderColor: palette.purple.base,\n color: palette.purple.base,\n \"&:hover\": {\n borderColor: palette.border.strong,\n backgroundColor: palette.purple.base,\n color: palette.purple.contrast,\n },\n },\n },\n ],\n};\n","import { Components, Theme } from \"@mui/material\";\nimport { palette, shape } from \"../tokens\";\nimport {\n FIELD_HEIGHT,\n collapsedNotch,\n fieldBorderStates,\n fieldPadding,\n} from \"./field-base\";\n\nconst NOTCH = \"MuiOutlinedInput-notchedOutline\";\n\nexport const inputTheme: Components<Theme>[\"MuiOutlinedInput\"] = {\n styleOverrides: {\n root: {\n boxSizing: \"border-box\",\n alignItems: \"flex-start\",\n padding: 0,\n borderRadius: shape.xl,\n lineHeight: \"normal\",\n\n // Fixed height for single-line fields (text input + select). The textarea\n // keeps its intrinsic, row-driven height.\n \"&:not(.MuiInputBase-multiline)\": {\n height: FIELD_HEIGHT,\n },\n\n // We draw the border ourselves, so collapse MUI's notch and its legend.\n ...collapsedNotch(NOTCH),\n\n // --- Border states ---\n ...fieldBorderStates(NOTCH),\n // NB: clicking focuses the field on mousedown, so `:active` and\n // `.Mui-focused` coincide — excluding focused here made this unreachable.\n \"&:active:not(.Mui-error):not(.Mui-disabled)\": {\n backgroundColor: palette.bg.subtle,\n [`& .${NOTCH}`]: {\n borderWidth: \"2px\",\n borderColor: palette.border.accent,\n },\n },\n\n \"&.MuiFormLabel-root .MuiInputLabel-root .Mui-focused\": {\n color: palette.text.base,\n },\n\n // --- Value positioning ---\n \"& .MuiInputBase-input\": {\n padding: 0,\n ...fieldPadding,\n paddingInlineEnd: \"0.9rem\",\n },\n \"& .MuiSelect-select\": {\n ...fieldPadding,\n paddingInlineEnd: \"2.5rem\",\n minHeight: \"unset\",\n display: \"flex\",\n alignItems: \"flex-end\",\n boxSizing: \"border-box\",\n },\n\n // --- Adornments ---\n \"& .MuiInputAdornment-root\": {\n height: \"auto\",\n maxHeight: \"none\",\n alignSelf: \"center\",\n },\n \"& .MuiInputAdornment-positionEnd\": {\n marginRight: \"0.9rem\",\n },\n // The value sits low in the field to clear the floated label, so a centred\n // icon reads as too high next to it. Nudge the leading icon down onto the\n // text line (margin on a centre-aligned flex item shifts it by half).\n \"& .MuiInputAdornment-positionStart\": {\n marginLeft: \"0.7rem\",\n marginTop: \"0.25rem\",\n },\n \"&:has(.MuiInputAdornment-positionStart) .MuiInputBase-input\": {\n paddingInlineStart: \"0\",\n },\n \"&:has(.MuiSelect-select) .MuiInputAdornment-positionEnd\": {\n position: \"absolute\",\n right: \"2.4rem\",\n top: \"50%\",\n transform: \"translateY(-50%)\",\n margin: 0,\n pointerEvents: \"none\",\n },\n \"&:has(.MuiSelect-select):has(.MuiInputAdornment-positionEnd) .MuiSelect-select\":\n {\n paddingInlineEnd: \"4.25rem\",\n },\n },\n input: {\n \"&:-webkit-autofill, &:-webkit-autofill:hover, &:-webkit-autofill:focus, &:-webkit-autofill:active\":\n {\n WebkitBoxShadow: `0 0 0 100px ${palette.bg.base} inset`,\n WebkitTextFillColor: palette.text.base,\n caretColor: palette.text.base,\n },\n },\n },\n};\n\nexport const inputLabelTheme: Components<Theme>[\"MuiInputLabel\"] = {\n styleOverrides: {\n shrink: {\n top: \"1rem\",\n },\n },\n};\n","import { Components, Theme } from \"@mui/material\";\nimport { fontWeights } from \"../tokens\";\nimport { focusVisibleStyles } from \"../utils\";\n\nexport const linkTheme: Components<Theme>[\"MuiLink\"] = {\n defaultProps: {\n underline: \"none\",\n },\n styleOverrides: {\n root: {\n ...focusVisibleStyles,\n fontWeight: fontWeights.regular,\n cursor: \"pointer\",\n textDecoration: \"none\",\n textUnderlineOffset: \"0.3rem\",\n \"&:hover\": {\n textDecoration: \"underline\",\n },\n },\n },\n};\n","import { Components, Theme } from \"@mui/material\";\nimport { palette, shape, spacing } from \"../tokens\";\n\nexport const menuItemTheme: Components<Theme>[\"MuiMenuItem\"] = {\n defaultProps: {\n disableRipple: true,\n },\n styleOverrides: {\n root: {\n borderRadius: shape.md,\n paddingBlock: spacing(1),\n \"&:hover\": {\n backgroundColor: palette.bg.subtle,\n },\n \"&.Mui-selected\": {\n backgroundColor: palette.bg.accent,\n },\n },\n },\n};\n","import { Components, Theme } from \"@mui/material\";\nimport { palette } from \"../tokens\";\n\n// The radio visual (circle + dot, incl. hover / checked styling) lives in the\n// shared `RadioCircle` component (radio-circle.tsx) so it can be reused outside\n// MuiRadio (e.g. RadioCardIndicator). This override only handles the bits that\n// depend on MuiRadio's own state.\nexport const radioTheme: Components<Theme>[\"MuiRadio\"] = {\n defaultProps: {\n disableRipple: true,\n },\n styleOverrides: {\n root: {\n padding: 0,\n\n // Keyboard focus ring (mouse clicks won't trigger Mui-focusVisible).\n \"&.Mui-focusVisible .lea-radio-circle\": {\n outline: `2px solid ${palette.purple.base}`,\n outlineOffset: 2,\n },\n\n \"&.Mui-disabled\": {\n opacity: 0.7,\n },\n },\n },\n};\n","import { Components, Theme } from \"@mui/material\";\nimport { ChevronDown } from \"lucide-react\";\nimport { palette, shadows, shape } from \"../tokens\";\n\nexport const selectTheme: Components<Theme>[\"MuiSelect\"] = {\n defaultProps: {\n variant: \"outlined\",\n IconComponent: ChevronDown,\n MenuProps: {\n slotProps: {\n root: {\n sx: {},\n },\n paper: {\n elevation: 0,\n sx: {\n borderTopLeftRadius: \"0\",\n borderTopRightRadius: \"0\",\n borderBottomLeftRadius: shape[\"xl\"],\n borderBottomRightRadius: shape[\"xl\"],\n boxShadow: shadows.lg,\n border: `1px solid ${palette.border.accent}`,\n maxHeight: 200,\n },\n },\n list: {\n sx: {\n paddingInline: 0.5,\n paddingBlock: 0.5,\n display: \"flex\",\n flexDirection: \"column\",\n gap: \"0.1rem\",\n },\n },\n },\n },\n },\n styleOverrides: {\n root: {\n color: palette.text.base,\n backgroundColor: palette.bg.base,\n borderRadius: shape[\"xl\"],\n\n // Keep focus ring visible while the menu is open (focus moves to the listbox).\n \"&:has(.MuiSelect-select[aria-expanded='true']:not(.Mui-error)) .MuiOutlinedInput-notchedOutline\":\n {\n borderWidth: \"2px\",\n borderColor: palette.border.accent,\n borderBottomLeftRadius: 0,\n borderBottomRightRadius: 0,\n },\n },\n select: {\n minHeight: \"unset\",\n },\n icon: {\n right: \"0.9rem\",\n width: \"1.25rem\",\n height: \"1.25rem\",\n color: palette.text.base,\n },\n },\n};\n","import { alpha, Components, Theme } from \"@mui/material\";\nimport { palette, spacing } from \"../tokens\";\n\nexport const sliderTheme: Components<Theme>[\"MuiSlider\"] = {\n styleOverrides: {\n root: {\n color: palette.primary.main,\n paddingBlock: spacing(1),\n },\n rail: {\n opacity: 1,\n backgroundColor: palette.primary.light,\n },\n track: {\n border: \"none\",\n backgroundColor: palette.primary.main,\n },\n thumb: {\n width: 24,\n height: 24,\n backgroundColor: palette.primary.main,\n \"&:hover, &.Mui-focusVisible\": {\n boxShadow: `0 0 0 ${spacing(1)} ${alpha(palette.primary.main, 0.18)}`,\n },\n },\n },\n};","import { Components, Theme } from \"@mui/material\";\nimport { fontSizes } from \"../tokens\";\n\ntype FontSizeToken = keyof typeof fontSizes;\n\nconst isFontSizeToken = (value: unknown): value is FontSizeToken =>\n typeof value === \"string\" && value in fontSizes;\n\nexport const typographyTheme: Components<Theme>[\"MuiTypography\"] = {\n styleOverrides: {\n root: ({ ownerState }) => {\n if (isFontSizeToken(ownerState.fontSize)) {\n return { fontSize: fontSizes[ownerState.fontSize] };\n }\n },\n },\n};\n","import { Components, Theme } from \"@mui/material\";\nimport { accordionTheme } from \"./accordion.theme\";\nimport { actionButtonVariant } from \"./action-button.theme\";\nimport { alertTheme } from \"./alert.theme\";\nimport { autocompleteTheme } from \"./autocomplete.theme\";\nimport { baselineCss } from \"./baseline-css\";\nimport { buttonTheme } from \"./button.theme\";\nimport { cardTheme } from \"./card.theme\";\nimport { chipTheme } from \"./chip.theme\";\nimport { checkboxTheme } from \"./checkbox.theme\";\nimport { datePickerTheme } from \"./date-picker.theme\";\nimport { dialogTheme } from \"./dialog.theme\";\nimport { drawerTheme } from \"./drawer.theme\";\nimport { formControlLabelTheme } from \"./form-control-label.theme\";\nimport { formControlTheme } from \"./form-control.theme\";\nimport { iconButtonTheme } from \"./icon-button.theme\";\nimport { inputLabelTheme, inputTheme } from \"./input.theme\";\nimport { linkTheme } from \"./link.theme\";\nimport { menuItemTheme } from \"./menu-item.theme\";\nimport { radioTheme } from \"./radio.theme\";\nimport { selectTheme } from \"./select.theme\";\nimport { sliderTheme } from \"./slider.theme\";\nimport { tooltipTheme } from \"./tooltip.theme\";\nimport { typographyTheme } from \"./typography.theme\";\n\nexport const components: Components<Theme> = {\n ...accordionTheme,\n ...dialogTheme,\n ...drawerTheme,\n ...tooltipTheme,\n ...datePickerTheme,\n MuiCssBaseline: baselineCss,\n MuiButton: {\n ...buttonTheme,\n variants: [actionButtonVariant],\n },\n MuiAlert: alertTheme,\n MuiIconButton: iconButtonTheme,\n MuiLink: linkTheme,\n MuiAutocomplete: autocompleteTheme,\n MuiCard: cardTheme,\n MuiChip: chipTheme,\n MuiCheckbox: checkboxTheme,\n MuiMenuItem: menuItemTheme,\n MuiRadio: radioTheme,\n MuiSlider: sliderTheme,\n MuiTypography: typographyTheme,\n MuiSelect: selectTheme,\n MuiFormControl: formControlTheme,\n MuiFormControlLabel: formControlLabelTheme,\n MuiOutlinedInput: inputTheme,\n MuiInputLabel: inputLabelTheme,\n};\n","import type { Theme } from \"@mui/material/styles\";\nimport { handleBreakpoints } from \"@mui/system\";\nimport { ShapeToken } from \"./types\";\n\nconst resolveRadius = (theme: Theme, value: unknown) => {\n // Named token → look it up in `theme.shape` (e.g. \"md\" → 5 → \"5px\").\n if (typeof value === \"string\" && theme.shape && value in theme.shape) {\n return `${theme.shape[value as ShapeToken]}px`;\n }\n // Number → keep MUI's default behaviour (multiply by `shape.borderRadius`),\n // so the many existing numeric `borderRadius` usages don't change.\n if (typeof value === \"number\") {\n const base = theme.shape?.sm;\n return value * (typeof base === \"number\" ? base : 4);\n }\n // Anything else is already a CSS value (\"4px\", \"50%\", …) → pass through.\n return value;\n};\n\n/**\n * Custom `sx` resolver for `borderRadius` so the radius design tokens work as\n * string shorthands — `borderRadius=\"md\"`, `sx={{ borderRadius: \"2xl\" }}` — while\n * numbers keep MUI's default `shape.borderRadius` scaling. Wired into the theme\n * via `unstable_sxConfig` (see `theme/index.ts`).\n */\nexport const borderRadiusSx = (props: object) => {\n const { borderRadius, theme } = props as {\n borderRadius?: unknown;\n theme: Theme;\n };\n if (borderRadius == null) return {};\n return handleBreakpoints(props, borderRadius, (value: unknown) => ({\n borderRadius: resolveRadius(theme, value),\n }));\n};\nborderRadiusSx.filterProps = [\"borderRadius\"];\n","import { Components, createTheme, CssVarsTheme, Theme } from \"@mui/material\";\nimport \"./mui-augmentation\";\nimport { components } from \"./components\";\nimport { borderRadiusSx } from \"./sx-config\";\nimport {\n breakpoints,\n colors,\n durations,\n easings,\n fontSizes,\n fontWeights,\n palette,\n shadows,\n shape,\n spacing,\n transition,\n typography,\n} from \"./tokens\";\n\nconst theme = createTheme({\n breakpoints: { values: breakpoints },\n palette,\n typography,\n shape,\n fontSizes,\n colors,\n shadowTokens: shadows,\n fontWeights,\n space: spacing,\n easings,\n durations,\n transition,\n components: components as unknown as Components<\n Omit<Theme, \"palette\" | \"components\"> & CssVarsTheme\n >,\n cssVariables: true,\n // Resolve `borderRadius` string tokens (\"md\", \"2xl\", …) from `theme.shape`,\n // while numbers keep MUI's default scaling. See sx-config.ts.\n unstable_sxConfig: {\n borderRadius: { themeKey: \"shape\", style: borderRadiusSx },\n },\n});\n\nexport { breakpoints, type Breakpoint } from \"./tokens/breakpoints\";\nexport * from \"./token-types\";\nexport * from \"./types\";\nexport { theme };\n","import { SxProps, Theme } from \"@mui/material\";\nimport { theme } from \"..\";\nimport { palette, shadows, shape, spacing } from \"../tokens\";\n\n/**\n * Styling for `PhoneNumberInput`. The label floats on the field's top border,\n * with the value and the leading country trigger vertically centred. The country\n * trigger opens a searchable popover (a MUI `Autocomplete` rendered inline).\n * These `sx` objects keep the component file lean, mirroring `number-input.theme`.\n */\n\n/** Applied to the outer `OutlinedInput`: centre the row and give the value room. */\nexport const phoneNumberInputRootSx: SxProps<Theme> = {\n display: \"flex\",\n alignItems: \"center\",\n \"& .MuiInputAdornment-positionStart\": {\n marginTop: 0,\n marginLeft: 0,\n marginRight: 0,\n height: \"auto\",\n maxHeight: \"none\",\n alignSelf: \"stretch\",\n },\n // The floated label sits on the top border, so the value can sit centred with\n // balanced padding; the leading inset keeps the number off the trigger divider.\n \"& .MuiInputBase-input\": {\n paddingBlockStart: `1.5rem!important`,\n paddingBlockEnd: spacing(1),\n paddingInlineStart: \"0.6rem!important\",\n },\n};\n\n/**\n * Applied to the standalone `FormControl`. Pins the floated (shrunk) label to\n * the top-left of the border instead of the generic start-adornment offset\n * (`translate(2.4rem, …)` from `formControlTheme`), which would land it over the\n * country flag. Matches that rule's specificity so this wins by source order.\n */\nexport const phoneNumberFormControlSx: SxProps<Theme> = {\n \"&:has(.MuiInputAdornment-positionStart) .MuiInputLabel-root.MuiInputLabel-shrink\":\n { transform: \"translate(6.5rem, -9px) scale(0.75)\" },\n};\n\n/** The compact country trigger button embedded in the leading adornment. */\nexport const countryTriggerSx: SxProps<Theme> = {\n height: \"100%\",\n display: \"flex\",\n alignItems: \"center\",\n gap: \"0.2rem\",\n fontSize: \"1rem!important\",\n fontFamily: theme.typography.fontFamily,\n paddingInlineStart: spacing(1),\n paddingInlineEnd: spacing(0.5),\n borderRight: `1px solid ${palette.border.subtle}`,\n color: palette.text.base,\n whiteSpace: \"nowrap\",\n borderTopLeftRadius: shape.xl,\n borderBottomLeftRadius: shape.xl,\n \"&:hover\": { backgroundColor: palette.bg.subtle },\n // Fixed dial-code slot so the trigger keeps a constant width across dial codes\n // (e.g. +1 vs +358); this keeps the floated label aligned with the value.\n \"& .LeaPhoneCountryDialTrigger\": {\n minWidth: \"2.5rem\",\n },\n \"& .LeaPhoneCountryTriggerChevron\": {\n color: palette.text.subtle,\n flexShrink: 0,\n },\n \"&.Mui-disabled\": { opacity: 0.6 },\n};\n\n/** The flag glyph shown in the trigger and the option rows. */\nexport const countryFlagSx: SxProps<Theme> = {\n fontSize: \"1.15rem\",\n lineHeight: 1,\n};\n\n/** The popper wrapping the search popover, above the field. */\nexport const countryPopperSx: SxProps<Theme> = {\n zIndex: (theme) => theme.zIndex.modal,\n paddingBlock: \"0.25rem\",\n};\n\n/**\n * The popover surface holding the search box and the country list. Its width is\n * set at runtime to match the input it anchors to, so the two line up exactly.\n */\nexport const countryPopoverSx: SxProps<Theme> = {\n maxWidth: \"90vw\",\n backgroundColor: palette.bg.base,\n borderRadius: shape.sm,\n boxShadow: shadows.lg,\n border: `1px solid ${palette.border.accent}`,\n overflow: \"hidden\",\n};\n\n/**\n * Neutralises the global `MuiAutocomplete` theme for our inline instance: drop\n * the root's boxed background and radius so the search box reads as a flat row\n * of our own popover. (The listbox popper is pulled back into flow on the\n * `InlineListbox` element itself, since it renders as a sibling of the root.)\n */\nexport const countryAutocompleteSx: SxProps<Theme> = {\n backgroundColor: \"transparent\",\n borderRadius: 0,\n};\n\n/** The search input at the top of the popover. */\nexport const countrySearchSx: SxProps<Theme> = {\n paddingInline: \"0.9rem!important\",\n paddingBlock: \"0.6rem!important\",\n borderBottom: `1px solid ${palette.border.subtle}`,\n color: palette.text.base,\n // The global Autocomplete theme injects tall field padding onto its input;\n // reset it with a higher-specificity selector so the value aligns with the icon.\n \"&.MuiAutocomplete-inputRoot .MuiAutocomplete-input\": { padding: 0 },\n \"& svg\": {\n color: palette.text.subtle,\n flexShrink: 0,\n marginRight: \"0.5rem\",\n },\n};\n\n/**\n * Strips the `Autocomplete`'s own paper so our popover surface is the only one;\n * the listbox renders inline beneath the search box.\n */\nexport const countryListPaperSx: SxProps<Theme> = {\n boxShadow: \"none\",\n border: 0,\n margin: 0,\n borderRadius: 0,\n backgroundColor: \"transparent\",\n};\n\n/** An option row: flag, country name (grows), dialling code. */\nexport const countryOptionSx: SxProps<Theme> = {\n display: \"flex\",\n alignItems: \"center\",\n gap: \"0.6rem\",\n \"& .LeaPhoneCountryName\": {\n flex: 1,\n overflow: \"hidden\",\n textOverflow: \"ellipsis\",\n whiteSpace: \"nowrap\",\n },\n \"& .LeaPhoneCountryDial\": {\n color: palette.text.subtle,\n },\n};\n","import {\n getCountries,\n getCountryCallingCode,\n type CountryCode,\n} from \"libphonenumber-js\";\n\nexport type { CountryCode };\n\n/**\n * Countries surfaced at the top of the country-code select. Lea Bank's core\n * markets, in priority order. The rest of the world follows, sorted by their\n * localised name.\n */\nexport const PINNED_COUNTRIES: readonly CountryCode[] = [\n \"FI\",\n \"SE\",\n \"NO\",\n \"ES\",\n];\n\nexport interface CountryOption {\n /** ISO 3166-1 alpha-2 code, e.g. `\"FI\"`. */\n code: CountryCode;\n /** International dialling code without the leading `+`, e.g. `\"358\"`. */\n dialCode: string;\n /** Localised country name, e.g. `\"Finland\"`. */\n name: string;\n /** Flag emoji derived from the ISO code. Purely decorative. */\n flag: string;\n /** Whether this is one of the pinned core-market countries. */\n pinned: boolean;\n}\n\n/**\n * Turns a two-letter ISO country code into its flag emoji by mapping each\n * letter to the matching Unicode regional-indicator symbol. No asset library\n * needed — the platform renders the pair as a flag.\n */\nexport function flagEmoji(code: string): string {\n return code\n .toUpperCase()\n .replace(/[A-Z]/g, (char) =>\n String.fromCodePoint(127397 + char.charCodeAt(0)),\n );\n}\n\n/**\n * Builds the ordered country list for the select: the pinned core markets\n * first, then every remaining country sorted by its name in the given locale.\n * Country names come from `Intl.DisplayNames`, so they follow the active locale\n * with no hand-maintained list.\n */\nexport function getCountryOptions(locale: string): CountryOption[] {\n const displayNames = new Intl.DisplayNames([locale], { type: \"region\" });\n const all = getCountries();\n\n const toOption = (code: CountryCode, pinned: boolean): CountryOption => ({\n code,\n dialCode: getCountryCallingCode(code),\n name: displayNames.of(code) ?? code,\n flag: flagEmoji(code),\n pinned,\n });\n\n const pinned = PINNED_COUNTRIES.filter((code) => all.includes(code)).map(\n (code) => toOption(code, true),\n );\n\n const rest = all\n .filter((code) => !PINNED_COUNTRIES.includes(code))\n .map((code) => toOption(code, false))\n .sort((a, b) => a.name.localeCompare(b.name, locale));\n\n return [...pinned, ...rest];\n}\n","import {\n Box,\n ButtonBase,\n ClickAwayListener,\n Divider,\n InputAdornment,\n InputBase,\n Popper,\n OutlinedInput,\n Autocomplete,\n createFilterOptions,\n type OutlinedInputProps,\n type PopperProps,\n type SxProps,\n type Theme,\n} from \"@mui/material\";\nimport { AsYouType } from \"libphonenumber-js\";\nimport { ChevronDown, Search } from \"lucide-react\";\nimport {\n Fragment,\n useMemo,\n useRef,\n useState,\n type ChangeEvent,\n type FocusEvent,\n type ReactNode,\n type RefObject,\n} from \"react\";\nimport { FormControl, useFormField } from \"..\";\nimport { createTranslation, useLanguage, type Language } from \"../../../i18n\";\nimport {\n countryAutocompleteSx,\n countryFlagSx,\n countryListPaperSx,\n countryOptionSx,\n countryPopoverSx,\n countryPopperSx,\n countrySearchSx,\n countryTriggerSx,\n phoneNumberFormControlSx,\n phoneNumberInputRootSx,\n} from \"../../../theme/components/phone-number-input.theme\";\nimport { validatePhoneNumber } from \"../../../validation/phone\";\nimport { FormHelperText } from \"../form-control/form-helper-text\";\nimport { InputLabel } from \"../input-label\";\nimport {\n getCountryOptions,\n type CountryCode,\n type CountryOption,\n} from \"./countries\";\n\n/** The default country and the locale used to name/sort the list, per language. */\nconst LANGUAGE_TO_COUNTRY: Record<Language, CountryCode> = {\n no: \"NO\",\n se: \"SE\",\n fi: \"FI\",\n es: \"ES\",\n};\n\nconst LANGUAGE_TO_LOCALE: Record<Language, string> = {\n no: \"nb-NO\",\n se: \"sv-SE\",\n fi: \"fi-FI\",\n es: \"es-ES\",\n};\n\n/** Details reported alongside every change so the consumer can react to validity. */\nexport interface PhoneNumberMeta {\n /** The selected country. */\n country: CountryCode;\n /** Canonical E.164 number when valid (e.g. `\"+358401234567\"`), otherwise `undefined`. */\n e164?: string;\n /** Whether the current number is a valid phone number for the country. */\n isValid: boolean;\n}\n\nexport type PhoneNumberInputProps = Omit<\n OutlinedInputProps,\n \"value\" | \"defaultValue\" | \"onChange\" | \"type\" | \"startAdornment\"\n> & {\n /** Floating label. Rendered as an `InputLabel` and linked automatically. */\n label?: ReactNode;\n /** Helper / error text shown below the control and linked via `aria-describedby`. */\n helperText?: ReactNode;\n /** Selected country (controlled). Pair with `onCountryChange`. */\n country?: CountryCode;\n /** Initial country when uncontrolled. Defaults to the country for the active locale. */\n defaultCountry?: CountryCode;\n /** Fired when the user picks a different country. */\n onCountryChange?: (country: CountryCode) => void;\n /** The national number as displayed (controlled). Pair with `onChange`. */\n value?: string;\n /** Initial national number when uncontrolled. */\n defaultValue?: string;\n /** Fired on every keystroke with the formatted national number and validity meta. */\n onChange?: (value: string, meta: PhoneNumberMeta) => void;\n /**\n * Show a built-in \"invalid number\" error once the field is blurred with a\n * non-empty, invalid value. Ignored when the consumer drives `error`.\n * @default true\n */\n validateOnBlur?: boolean;\n};\n\n/**\n * Formats the national number as the user types. Norwegian mobile numbers are\n * grouped 3-2-3 (e.g. `400 12 345`), which `libphonenumber-js` doesn't do on its\n * own (it pairs digits as `40 01 23 45`). Every other country keeps the library's\n * standard grouping via `AsYouType`.\n */\nfunction formatNationalNumber(country: CountryCode, input: string): string {\n if (country === \"NO\") {\n const digits = input.replace(/\\D/g, \"\").slice(0, 8);\n return [digits.slice(0, 3), digits.slice(3, 5), digits.slice(5, 8)]\n .filter(Boolean)\n .join(\" \");\n }\n return new AsYouType(country).input(input);\n}\n\nconst usePhoneLabels = createTranslation({\n countryLabel: {\n no: \"Landskode\",\n se: \"Landskod\",\n fi: \"Maakoodi\",\n es: \"Código de país\",\n },\n searchCountry: {\n no: \"Søk etter land\",\n se: \"Sök efter land\",\n fi: \"Hae maata\",\n es: \"Buscar país\",\n },\n noCountries: {\n no: \"Ingen land funnet\",\n se: \"Inga länder hittades\",\n fi: \"Maita ei löytynyt\",\n es: \"No se han encontrado países\",\n },\n invalid: {\n no: \"Ugyldig telefonnummer\",\n se: \"Ogiltigt telefonnummer\",\n fi: \"Virheellinen puhelinnumero\",\n es: \"Número de teléfono no válido\",\n },\n});\n\n/**\n * Renders the `Autocomplete`'s dropdown inline (position static) inside our own\n * popover, so the listbox sits directly under the search box instead of in a\n * second, separately-positioned popper.\n */\nfunction InlineListbox({ children, className }: PopperProps) {\n return (\n <div\n className={className}\n style={{ position: \"static\", width: \"100%\" }}\n >\n {children as ReactNode}\n </div>\n );\n}\n\nconst countryFilter = createFilterOptions<CountryOption>({\n stringify: (option) =>\n `${option.name} ${option.code} ${option.dialCode} +${option.dialCode}`,\n});\n\ninterface CountrySelectProps {\n options: CountryOption[];\n value: CountryCode;\n onChange: (country: CountryCode) => void;\n ariaLabel: string;\n searchLabel: string;\n noOptionsText: string;\n disabled?: boolean;\n /** The input root the popover anchors to and matches in width. */\n anchorRef: RefObject<HTMLDivElement | null>;\n}\n\n/**\n * The compact country trigger in the leading adornment. Clicking it opens a\n * searchable popover backed by MUI's `Autocomplete`, so keyboard navigation,\n * type-ahead and the listbox a11y come for free. The popover anchors to the\n * whole input (`anchorRef`) so it aligns with, and matches the width of, the\n * field rather than the compact trigger.\n */\nfunction CountrySelect({\n options,\n value,\n onChange,\n ariaLabel,\n searchLabel,\n noOptionsText,\n disabled,\n anchorRef,\n}: CountrySelectProps) {\n const triggerRef = useRef<HTMLButtonElement>(null);\n const [open, setOpen] = useState(false);\n const selected = options.find((option) => option.code === value);\n const pinnedCount = options.filter((option) => option.pinned).length;\n\n const closePopover = () => {\n triggerRef.current?.focus();\n setOpen(false);\n };\n\n return (\n <>\n <ButtonBase\n ref={triggerRef}\n type=\"button\"\n disabled={disabled}\n onClick={() => setOpen(true)}\n onKeyDown={(event) => {\n if (event.key === \"ArrowDown\") {\n event.preventDefault();\n setOpen(true);\n }\n }}\n aria-haspopup=\"dialog\"\n aria-expanded={open}\n aria-label={selected ? `${ariaLabel}, ${selected.name}` : ariaLabel}\n sx={countryTriggerSx}\n >\n {selected && (\n <>\n <Box component=\"span\" aria-hidden sx={countryFlagSx}>\n {selected.flag}\n </Box>\n <Box component=\"span\" className=\"LeaPhoneCountryDialTrigger\">\n +{selected.dialCode}\n </Box>\n </>\n )}\n <ChevronDown\n size={16}\n aria-hidden\n className=\"LeaPhoneCountryTriggerChevron\"\n />\n </ButtonBase>\n\n <Popper\n open={open}\n anchorEl={anchorRef.current}\n placement=\"bottom-start\"\n sx={countryPopperSx}\n >\n <ClickAwayListener onClickAway={() => setOpen(false)}>\n <Box sx={countryPopoverSx} style={{ width: anchorRef.current?.offsetWidth }}>\n <Autocomplete<CountryOption>\n open\n disablePortal\n options={options}\n filterOptions={countryFilter}\n getOptionLabel={(option) => option.name}\n isOptionEqualToValue={(option, val) => option.code === val.code}\n noOptionsText={noOptionsText}\n slots={{ popper: InlineListbox }}\n slotProps={{ paper: { sx: countryListPaperSx } }}\n sx={countryAutocompleteSx}\n onClose={(_event, reason) => {\n if (reason === \"escape\") closePopover();\n }}\n onChange={(_event, next) => {\n if (next) {\n onChange(next.code);\n closePopover();\n }\n }}\n renderOption={(props, option, state) => {\n const { key, ...optionProps } = props;\n const showDivider =\n state.inputValue === \"\" &&\n !option.pinned &&\n state.index === pinnedCount &&\n pinnedCount > 0;\n return (\n <Fragment key={key}>\n {showDivider && <Divider component=\"li\" />}\n <Box component=\"li\" {...optionProps} sx={countryOptionSx}>\n <Box component=\"span\" aria-hidden sx={countryFlagSx}>\n {option.flag}\n </Box>\n <span className=\"LeaPhoneCountryName\">{option.name}</span>\n <span className=\"LeaPhoneCountryDial\">\n +{option.dialCode}\n </span>\n </Box>\n </Fragment>\n );\n }}\n renderInput={(params) => (\n <InputBase\n {...params.slotProps.input}\n endAdornment={undefined}\n autoFocus\n fullWidth\n placeholder={searchLabel}\n startAdornment={<Search size={18} aria-hidden />}\n inputProps={{\n ...params.slotProps.htmlInput,\n \"aria-label\": searchLabel,\n }}\n sx={countrySearchSx}\n />\n )}\n />\n </Box>\n </ClickAwayListener>\n </Popper>\n </>\n );\n}\n\ntype PhoneFieldProps = Omit<\n OutlinedInputProps,\n \"value\" | \"onChange\" | \"type\" | \"startAdornment\"\n> & {\n options: CountryOption[];\n country: CountryCode;\n onCountryChange: (country: CountryCode) => void;\n countryAriaLabel: string;\n searchLabel: string;\n noOptionsText: string;\n value: string;\n onInputChange: (event: ChangeEvent<HTMLInputElement>) => void;\n};\n\n/**\n * The bare control: the country trigger in a leading adornment plus the phone\n * text field, wired to the surrounding `FormControl` via context so the control\n * id and `aria-describedby` are set without the consumer touching them.\n */\nfunction PhoneField({\n options,\n country,\n onCountryChange,\n countryAriaLabel,\n searchLabel,\n noOptionsText,\n value,\n onInputChange,\n error,\n required,\n disabled,\n placeholder,\n inputProps,\n sx,\n ...rest\n}: PhoneFieldProps) {\n const ctx = useFormField();\n const inputRootRef = useRef<HTMLDivElement>(null);\n const describedBy = ctx?.hasHelperText\n ? ctx.ids.helperText\n : inputProps?.[\"aria-describedby\"];\n\n const mergedSx: SxProps<Theme> = Array.isArray(sx)\n ? [phoneNumberInputRootSx, ...sx]\n : [phoneNumberInputRootSx, sx];\n\n return (\n <OutlinedInput\n ref={inputRootRef}\n id={ctx?.ids.control}\n type=\"tel\"\n value={value}\n onChange={onInputChange}\n error={error}\n required={required}\n disabled={disabled}\n placeholder={placeholder}\n sx={mergedSx}\n startAdornment={\n <InputAdornment position=\"start\">\n <CountrySelect\n options={options}\n value={country}\n onChange={onCountryChange}\n ariaLabel={countryAriaLabel}\n searchLabel={searchLabel}\n noOptionsText={noOptionsText}\n disabled={disabled}\n anchorRef={inputRootRef}\n />\n </InputAdornment>\n }\n inputProps={{\n inputMode: \"tel\",\n autoComplete: \"tel-national\",\n ...inputProps,\n \"aria-describedby\": describedBy,\n }}\n {...rest}\n />\n );\n}\n\n/**\n * Phone number input with a searchable country-code picker on the left, built\n * on MUI's `OutlinedInput`. The number is formatted as you type and validated\n * with `libphonenumber-js`. Lea Bank's core markets (Finland, Sweden, Norway,\n * Spain) are pinned to the top of the country list; the default country follows\n * the active locale.\n *\n * Works two ways, like `Input`:\n * - **Standalone (all-in-one):** pass `label` / `helperText` and it renders its\n * own `FormControl`, floating label and helper text, wiring all ids.\n * - **Composed:** drop it inside a `FormControl` and it picks up the shared ids.\n *\n * Both country and number can be **controlled** (`country` + `onCountryChange`,\n * `value` + `onChange`) or left **uncontrolled** (`defaultCountry` /\n * `defaultValue`).\n */\nexport function PhoneNumberInput({\n label,\n helperText,\n error,\n required,\n disabled,\n id,\n country,\n defaultCountry,\n onCountryChange,\n value,\n defaultValue,\n onChange,\n onBlur,\n validateOnBlur = true,\n ...rest\n}: PhoneNumberInputProps) {\n const language = useLanguage();\n const t = usePhoneLabels();\n const ctx = useFormField();\n\n const options = useMemo(\n () => getCountryOptions(LANGUAGE_TO_LOCALE[language]),\n [language],\n );\n\n const [countryState, setCountryState] = useState<CountryCode>(\n defaultCountry ?? LANGUAGE_TO_COUNTRY[language],\n );\n const currentCountry = country ?? countryState;\n\n const [valueState, setValueState] = useState<string>(defaultValue ?? \"\");\n const currentValue = value ?? valueState;\n\n const [touched, setTouched] = useState(false);\n\n const meta = useMemo<PhoneNumberMeta>(() => {\n const result = validatePhoneNumber(currentCountry, currentValue);\n return {\n country: currentCountry,\n e164: result.normalized,\n isValid: result.valid,\n };\n }, [currentCountry, currentValue]);\n\n const showValidationError =\n validateOnBlur && touched && currentValue.trim() !== \"\" && !meta.isValid;\n const resolvedError = error ?? showValidationError;\n const resolvedHelper =\n helperText ?? (showValidationError ? t.invalid : undefined);\n\n const emit = (nextValue: string, nextCountry: CountryCode) => {\n const result = validatePhoneNumber(nextCountry, nextValue);\n onChange?.(nextValue, {\n country: nextCountry,\n e164: result.normalized,\n isValid: result.valid,\n });\n };\n\n const handleCountryChange = (next: CountryCode) => {\n if (country === undefined) {\n setCountryState(next);\n }\n onCountryChange?.(next);\n // Re-emit so the consumer's meta (e.g. E.164) reflects the new dial code.\n emit(currentValue, next);\n };\n\n const handleInputChange = (event: ChangeEvent<HTMLInputElement>) => {\n const formatted = formatNationalNumber(currentCountry, event.target.value);\n if (value === undefined) {\n setValueState(formatted);\n }\n emit(formatted, currentCountry);\n };\n\n const handleBlur = (\n event: FocusEvent<HTMLInputElement | HTMLTextAreaElement>,\n ) => {\n setTouched(true);\n onBlur?.(event);\n };\n\n const field = (\n <PhoneField\n {...rest}\n options={options}\n country={currentCountry}\n onCountryChange={handleCountryChange}\n countryAriaLabel={t.countryLabel}\n searchLabel={t.searchCountry}\n noOptionsText={t.noCountries}\n value={currentValue}\n onInputChange={handleInputChange}\n onBlur={handleBlur}\n error={resolvedError}\n required={required}\n disabled={disabled}\n />\n );\n\n if (ctx) {\n return field;\n }\n\n return (\n <FormControl\n id={id}\n error={resolvedError}\n required={required}\n disabled={disabled}\n sx={phoneNumberFormControlSx}\n >\n {label != null && <InputLabel shrink>{label}</InputLabel>}\n {field}\n {resolvedHelper != null && (\n <FormHelperText\n error={resolvedError}\n role={resolvedError ? \"alert\" : undefined}\n >\n {resolvedHelper}\n </FormHelperText>\n )}\n </FormControl>\n );\n}\n","import { Controller, type FieldValues } from \"react-hook-form\";\nimport {\n PhoneNumberInput,\n type PhoneNumberInputProps,\n} from \"../phone-number-input\";\nimport type { BaseFieldProps } from \"./field-types\";\nimport { useResolvedControl } from \"./use-field-control\";\n\nexport type PhoneNumberFieldProps<T extends FieldValues> = BaseFieldProps<T> &\n Omit<\n PhoneNumberInputProps,\n \"name\" | \"value\" | \"defaultValue\" | \"onChange\" | \"error\"\n >;\n\n/**\n * `PhoneNumberInput` connected to react-hook-form via `Controller`. Reads\n * `control` from the nearest `FormProvider` when the prop is omitted. The form\n * value is the formatted national number string; pass `defaultCountry` (or a\n * controlled `country` + `onCountryChange`) to drive the country.\n */\nexport const PhoneNumberField = <T extends FieldValues>({\n name,\n control,\n rules,\n disabled,\n label,\n helperText,\n ...rest\n}: PhoneNumberFieldProps<T>) => {\n const resolved = useResolvedControl(control);\n\n return (\n <Controller\n control={resolved}\n name={name}\n rules={rules}\n render={({ field, fieldState }) => (\n <PhoneNumberInput\n {...rest}\n inputRef={field.ref}\n label={label}\n value={typeof field.value === \"string\" ? field.value : \"\"}\n onChange={(value) => field.onChange(value)}\n onBlur={field.onBlur}\n error={!!fieldState.error}\n helperText={fieldState.error?.message ?? helperText}\n disabled={disabled ?? field.disabled}\n />\n )}\n />\n );\n};\n","import { FormControlLabel } from \"@mui/material\";\nimport type { ReactNode } from \"react\";\nimport { Controller, type FieldValues } from \"react-hook-form\";\nimport { FormControl } from \"../form-control\";\nimport { FormHelperText } from \"../form-control/form-helper-text\";\nimport { FormLabel } from \"../form-control/form-label\";\nimport { Radio, RadioGroup, type RadioGroupProps } from \"../radio\";\nimport type { BaseFieldProps, FieldOption, FieldValueTransform } from \"./field-types\";\nimport { useResolvedControl } from \"./use-field-control\";\n\nexport type RadioFieldProps<T extends FieldValues> = BaseFieldProps<T> &\n FieldValueTransform & {\n label: ReactNode;\n options: FieldOption[];\n } & Omit<RadioGroupProps, \"value\" | \"onChange\" | \"name\" | \"defaultValue\">;\n\nconst defaultFormat = (value: unknown) =>\n value === undefined || value === null ? \"\" : String(value);\n\n/**\n * `RadioGroup` connected to react-hook-form via `Controller`, rendering each\n * option as a `FormControlLabel` + `Radio`. Reads `control` from the nearest\n * `FormProvider` when the prop is omitted.\n *\n * Pass optional `format` / `parse` to coerce values (e.g. boolean <-> string).\n */\nexport const RadioField = <T extends FieldValues>({\n name,\n control,\n rules,\n disabled,\n label,\n options,\n format = defaultFormat,\n parse,\n size,\n ...rest\n}: RadioFieldProps<T>) => {\n const resolved = useResolvedControl(control);\n\n return (\n <Controller\n control={resolved}\n name={name}\n rules={rules}\n render={({ field, fieldState }) => (\n <FormControl error={!!fieldState.error} disabled={disabled}>\n <FormLabel>{label}</FormLabel>\n <RadioGroup\n {...rest}\n {...field}\n size={size}\n value={format(field.value)}\n onChange={(_, value) =>\n field.onChange(parse ? parse(value) : value)\n }\n >\n {options.map((option) => (\n <FormControlLabel\n key={option.value}\n value={option.value}\n control={<Radio />}\n label={option.label}\n disabled={disabled}\n />\n ))}\n </RadioGroup>\n {fieldState.error?.message ? (\n <FormHelperText error>{fieldState.error.message}</FormHelperText>\n ) : null}\n </FormControl>\n )}\n />\n );\n};\n","import { Controller, useFormContext, type FieldValues } from \"react-hook-form\";\nimport { Select, type SelectProps } from \"../select\";\nimport type { BaseFieldProps } from \"./field-types\";\nimport { useResolvedControl } from \"./use-field-control\";\n\nexport type SelectFieldProps<T extends FieldValues> = BaseFieldProps<T> &\n Omit<SelectProps, \"name\" | \"value\" | \"defaultValue\" | \"error\">;\n\nconst resolveSelectValue = (eventOrValue: unknown): string => {\n if (typeof eventOrValue === \"string\") return eventOrValue;\n return (eventOrValue as { target?: { value?: string } })?.target?.value ?? \"\";\n};\n\n/**\n * `Select` connected to react-hook-form via `Controller`. Reads `control` from\n * the nearest `FormProvider` when the prop is omitted.\n */\nexport const SelectField = <T extends FieldValues>({\n name,\n control,\n rules,\n disabled,\n label,\n helperText,\n options,\n children,\n ...rest\n}: SelectFieldProps<T>) => {\n const resolved = useResolvedControl(control);\n const { trigger } = useFormContext();\n\n return (\n <Controller\n control={resolved}\n name={name}\n rules={rules}\n render={({ field, fieldState }) => (\n <Select\n {...rest}\n {...field}\n label={label}\n options={options}\n value={field.value ?? \"\"}\n onChange={(eventOrValue) => {\n field.onChange(resolveSelectValue(eventOrValue));\n field.onBlur();\n void trigger(field.name);\n }}\n error={!!fieldState.error}\n helperText={fieldState.error?.message ?? helperText}\n disabled={disabled ?? field.disabled}\n >\n {children}\n </Select>\n )}\n />\n );\n};\n","import {\n Slider as MuiSlider,\n type SliderProps as MuiSliderProps,\n useFormControl,\n} from \"@mui/material\";\nimport { forwardRef, type ReactNode } from \"react\";\nimport { FormControl, useFormField } from \".\";\nimport { FormHelperText } from \"./form-control/form-helper-text\";\nimport { FormLabel } from \"./form-control/form-label\";\n\nexport type SliderProps = MuiSliderProps & {\n /** Group label shown above the slider and linked via `aria-labelledby`. */\n label?: ReactNode;\n /** Helper / error text shown below the control and linked via `aria-describedby`. */\n helperText?: ReactNode;\n /** Puts wrapper FormControl and helper text into error state. */\n error?: boolean;\n /** Marks wrapper FormControl as required. */\n required?: boolean;\n};\n\nconst SliderControl = forwardRef<HTMLSpanElement, MuiSliderProps>(\n function SliderControl({ disabled, ...rest }, ref) {\n const ctx = useFormField();\n const formControl = useFormControl();\n const describedBy = ctx?.hasHelperText\n ? ctx.ids.helperText\n : rest[\"aria-describedby\"];\n const labelledBy = ctx?.ids.label ?? rest[\"aria-labelledby\"];\n\n return (\n <MuiSlider\n ref={ref}\n disabled={disabled ?? formControl?.disabled}\n aria-labelledby={labelledBy}\n aria-describedby={describedBy}\n {...rest}\n />\n );\n },\n);\n\n/**\n * Slider built on MUI's `Slider`.\n *\n * Works two ways:\n * - **Standalone (all-in-one):** pass `label` / `helperText` and it renders its\n * own `FormControl`, label and helper text, wiring `aria-labelledby` /\n * `aria-describedby` for you.\n * - **Composed:** drop it inside a `FormControl` next to `FormLabel` /\n * `FormHelperText` and it picks up the shared ids from context.\n */\nexport const Slider = forwardRef<HTMLSpanElement, SliderProps>(function Slider(\n { label, helperText, error, required, disabled, id, ...rest },\n ref,\n) {\n const ctx = useFormField();\n\n if (ctx) {\n return <SliderControl ref={ref} disabled={disabled} {...rest} />;\n }\n\n return (\n <FormControl id={id} error={error} required={required} disabled={disabled}>\n {label != null && <FormLabel>{label}</FormLabel>}\n <SliderControl ref={ref} disabled={disabled} {...rest} />\n {helperText != null && (\n <FormHelperText error={error} role={error ? \"alert\" : undefined}>\n {helperText}\n </FormHelperText>\n )}\n </FormControl>\n );\n});","/*\n * Design tokens come from src/theme/tokens.css, generated from src/theme/tokens\n * by `pnpm tokens:css`. It is a plain stylesheet rather than runtime-injected\n * CSS variables, so this component renders correctly without a provider.\n */\n\n.Switch {\n display: inline-flex;\n width: 2.5rem;\n height: 1.5rem;\n flex-shrink: 0;\n align-items: center;\n padding: 0.125rem;\n border: none;\n border-radius: var(--lea-radius-full);\n background-color: var(--lea-color-neutral-200);\n cursor: pointer;\n transition: background-color var(--lea-duration-normal)\n var(--lea-easing-standard);\n}\n\n.Switch[data-checked] {\n background-color: var(--lea-palette-purple-base);\n}\n\n.Switch:focus-visible {\n outline: 2px solid var(--lea-palette-text-base);\n outline-offset: 0.125rem;\n}\n\n.Switch[data-disabled] {\n cursor: not-allowed;\n opacity: 0.5;\n}\n\n.Thumb {\n display: block;\n width: 1.25rem;\n height: 1.25rem;\n border-radius: var(--lea-radius-full);\n background-color: var(--lea-palette-bg-base);\n transition: translate var(--lea-duration-normal) var(--lea-easing-standard);\n}\n\n.Thumb[data-checked] {\n translate: 1rem 0;\n}\n\n@media (prefers-reduced-motion: reduce) {\n .Switch,\n .Thumb {\n transition-duration: 0.01ms;\n }\n}\n","\"use client\";\n\nimport { Switch as BaseSwitch } from \"@base-ui/react/switch\";\n\nimport { mergeClassName } from \"../../utils/merge-class-name\";\nimport styles from \"./switch.module.css\";\n\n/**\n * Requires an accessible name so the switch is never nameless. Provide exactly\n * one of `aria-label` or `aria-labelledby`.\n */\ntype SwitchAccessibleName =\n | { \"aria-label\": string; \"aria-labelledby\"?: never }\n | { \"aria-labelledby\": string; \"aria-label\"?: never };\n\nexport type SwitchProps = Omit<\n BaseSwitch.Root.Props,\n \"children\" | \"aria-label\" | \"aria-labelledby\"\n> &\n SwitchAccessibleName;\n\n/**\n * An on/off toggle built on Base UI's accessible `Switch` primitive.\n *\n * Base UI renders the `switch` role, keeps `aria-checked` in sync and submits\n * a hidden input when `name` is set. The thumb is rendered internally so it\n * can never be left out, and the slide respects `prefers-reduced-motion`.\n *\n * Unlike a checkbox, a switch takes effect immediately — use it for settings\n * that apply on toggle, not for values confirmed by a submit button.\n *\n * ```tsx\n * <Switch\n * aria-label=\"Analyse-informasjonskapsler\"\n * defaultChecked\n * onCheckedChange={(checked) => save(checked)}\n * />\n * ```\n */\nexport function Switch({ className, ...rest }: SwitchProps) {\n return (\n <BaseSwitch.Root\n {...rest}\n className={mergeClassName(styles.Switch, className)}\n >\n <BaseSwitch.Thumb className={styles.Thumb} />\n </BaseSwitch.Root>\n );\n}\n","/*\n * Responsive props arrive as inline `--_<prop>-<breakpoint>` properties, set\n * only for the breakpoints the consumer gave. Each media query falls back\n * through the smaller breakpoints, so `{ base: 1, md: 3 }` holds 1 until `md`.\n */\n.Grid {\n --_columns: var(--_columns-base, 12);\n --_gap: var(--_gap-base, 0);\n\n display: grid;\n min-width: 0;\n gap: calc(var(--lea-spacing) * var(--_gap));\n grid-template-columns: repeat(var(--_columns), minmax(0, 1fr));\n}\n\n/* A `GridItem` given no `span` takes the whole row; plain children take one column. */\n.GridItem {\n --_span: var(--_span-base, 1 / -1);\n\n min-width: 0;\n grid-column: var(--_span);\n}\n\n@media (min-width: 600px) {\n .Grid {\n --_columns: var(--_columns-sm, var(--_columns-base, 12));\n --_gap: var(--_gap-sm, var(--_gap-base, 0));\n }\n\n .GridItem {\n --_span: var(--_span-sm, var(--_span-base, 1 / -1));\n }\n}\n\n@media (min-width: 900px) {\n .Grid {\n --_columns: var(--_columns-md, var(--_columns-sm, var(--_columns-base, 12)));\n --_gap: var(--_gap-md, var(--_gap-sm, var(--_gap-base, 0)));\n }\n\n .GridItem {\n --_span: var(--_span-md, var(--_span-sm, var(--_span-base, 1 / -1)));\n }\n}\n\n@media (min-width: 1200px) {\n .Grid {\n --_columns: var(\n --_columns-lg,\n var(--_columns-md, var(--_columns-sm, var(--_columns-base, 12)))\n );\n --_gap: var(--_gap-lg, var(--_gap-md, var(--_gap-sm, var(--_gap-base, 0))));\n }\n\n .GridItem {\n --_span: var(\n --_span-lg,\n var(--_span-md, var(--_span-sm, var(--_span-base, 1 / -1)))\n );\n }\n}\n\n@media (min-width: 1536px) {\n .Grid {\n --_columns: var(\n --_columns-xl,\n var(\n --_columns-lg,\n var(--_columns-md, var(--_columns-sm, var(--_columns-base, 12)))\n )\n );\n --_gap: var(\n --_gap-xl,\n var(--_gap-lg, var(--_gap-md, var(--_gap-sm, var(--_gap-base, 0))))\n );\n }\n\n .GridItem {\n --_span: var(\n --_span-xl,\n var(\n --_span-lg,\n var(--_span-md, var(--_span-sm, var(--_span-base, 1 / -1)))\n )\n );\n }\n}\n","import type { CSSProperties } from \"react\";\n\nimport type { Breakpoint } from \"../../theme/tokens/breakpoints\";\n\n/** `base` applies from zero width; each other key from its breakpoint up. */\nexport type ResponsiveKey = \"base\" | Exclude<Breakpoint, \"xs\">;\n\n/**\n * A single value, or one per breakpoint, mobile-first. Unset breakpoints keep\n * the value of the nearest smaller one: `{ base: 1, md: 3 }` is 1 below `md`\n * and 3 from `md` up.\n */\nexport type Responsive<T> = T | Partial<Record<ResponsiveKey, T>>;\n\nconst isPerBreakpoint = <T>(\n value: Responsive<T>,\n): value is Partial<Record<ResponsiveKey, T>> =>\n typeof value === \"object\" && value !== null;\n\n/**\n * Writes a responsive prop as inline custom properties — `--_gap-base`,\n * `--_gap-md`, … — which the component's CSS Module picks up in its media\n * queries. Only the breakpoints that are set are written; the stylesheet\n * falls back through the smaller ones.\n *\n * Internal helper — not part of the public API.\n */\nexport function responsiveVars<T>(\n name: string,\n value: Responsive<T> | undefined,\n format: (value: T) => string | number = String,\n): CSSProperties {\n if (value === undefined) return {};\n\n const entries = isPerBreakpoint(value)\n ? Object.entries(value as Record<string, T | undefined>)\n : [[\"base\", value] as const];\n\n const vars: Record<string, string | number> = {};\n for (const [key, entry] of entries) {\n if (entry !== undefined) vars[`--_${name}-${key}`] = format(entry);\n }\n\n return vars as CSSProperties;\n}\n","\"use client\";\n\nimport { useRender } from \"@base-ui/react/use-render\";\n\nimport type { SpacingFactor } from \"../../theme/token-types\";\nimport { mergeClassName } from \"../../utils/merge-class-name\";\nimport styles from \"./grid.module.css\";\nimport { type Responsive, responsiveVars } from \"./responsive\";\n\nexport type GridProps = Omit<useRender.ComponentProps<\"div\">, \"ref\"> & {\n /**\n * Number of equal-width columns.\n * @default 12\n */\n columns?: Responsive<number>;\n /**\n * Space between rows and columns, as a multiple of the spacing step\n * (`spacing(n)`).\n * @default 0\n */\n gap?: Responsive<SpacingFactor>;\n};\n\n/**\n * A grid of equal-width columns. Children fill one column each; wrap them in\n * `GridItem` to span several. Both props take a value per breakpoint,\n * mobile-first:\n *\n * ```tsx\n * <Grid columns={{ base: 1, sm: 2, lg: 3 }} gap={2}>\n * <Card />\n * <Card />\n * <Card />\n * </Grid>\n * ```\n */\nexport function Grid({\n columns,\n gap,\n render,\n className,\n style,\n ...rest\n}: GridProps) {\n return useRender({\n render,\n props: {\n ...rest,\n className: mergeClassName(styles.Grid, className)({}),\n style: {\n ...responsiveVars(\"columns\", columns),\n ...responsiveVars(\"gap\", gap),\n ...style,\n },\n },\n });\n}\n\nexport type GridItemSpan = number | \"full\";\n\nexport type GridItemProps = Omit<useRender.ComponentProps<\"div\">, \"ref\"> & {\n /**\n * How many of the grid's columns the item covers. `\"full\"` covers the whole\n * row whatever the column count.\n * @default \"full\"\n */\n span?: Responsive<GridItemSpan>;\n};\n\nconst spanValue = (span: GridItemSpan) =>\n span === \"full\" ? \"1 / -1\" : `span ${span} / span ${span}`;\n\n/**\n * An item in a `Grid`. It takes the whole row until `span` says otherwise, so\n * layouts stay single-column on small screens by default:\n *\n * ```tsx\n * <Grid gap={3}>\n * <GridItem span={{ md: 8 }}>Main content</GridItem>\n * <GridItem span={{ md: 4 }}>Sidebar</GridItem>\n * </Grid>\n * ```\n */\nexport function GridItem({\n span,\n render,\n className,\n style,\n ...rest\n}: GridItemProps) {\n return useRender({\n render,\n props: {\n ...rest,\n className: mergeClassName(styles.GridItem, className)({}),\n style: { ...responsiveVars(\"span\", span, spanValue), ...style },\n },\n });\n}\n","/*\n * Responsive props arrive as inline `--_<prop>-<breakpoint>` properties, set\n * only for the breakpoints the consumer gave. Each media query falls back\n * through the smaller breakpoints, so `{ base: 1, md: 3 }` holds 1 until `md`.\n */\n.Stack {\n --_direction: var(--_direction-base, column);\n --_gap: var(--_gap-base, 0);\n\n display: flex;\n min-width: 0;\n flex-direction: var(--_direction);\n gap: calc(var(--lea-spacing) * var(--_gap));\n}\n\n@media (min-width: 600px) {\n .Stack {\n --_direction: var(--_direction-sm, var(--_direction-base, column));\n --_gap: var(--_gap-sm, var(--_gap-base, 0));\n }\n}\n\n@media (min-width: 900px) {\n .Stack {\n --_direction: var(\n --_direction-md,\n var(--_direction-sm, var(--_direction-base, column))\n );\n --_gap: var(--_gap-md, var(--_gap-sm, var(--_gap-base, 0)));\n }\n}\n\n@media (min-width: 1200px) {\n .Stack {\n --_direction: var(\n --_direction-lg,\n var(--_direction-md, var(--_direction-sm, var(--_direction-base, column)))\n );\n --_gap: var(--_gap-lg, var(--_gap-md, var(--_gap-sm, var(--_gap-base, 0))));\n }\n}\n\n@media (min-width: 1536px) {\n .Stack {\n --_direction: var(\n --_direction-xl,\n var(\n --_direction-lg,\n var(\n --_direction-md,\n var(--_direction-sm, var(--_direction-base, column))\n )\n )\n );\n --_gap: var(\n --_gap-xl,\n var(--_gap-lg, var(--_gap-md, var(--_gap-sm, var(--_gap-base, 0))))\n );\n }\n}\n\n.Stack[data-align=\"start\"] {\n align-items: flex-start;\n}\n\n.Stack[data-align=\"center\"] {\n align-items: center;\n}\n\n.Stack[data-align=\"end\"] {\n align-items: flex-end;\n}\n\n.Stack[data-align=\"stretch\"] {\n align-items: stretch;\n}\n\n.Stack[data-align=\"baseline\"] {\n align-items: baseline;\n}\n\n.Stack[data-justify=\"start\"] {\n justify-content: flex-start;\n}\n\n.Stack[data-justify=\"center\"] {\n justify-content: center;\n}\n\n.Stack[data-justify=\"end\"] {\n justify-content: flex-end;\n}\n\n.Stack[data-justify=\"between\"] {\n justify-content: space-between;\n}\n\n.Stack[data-justify=\"around\"] {\n justify-content: space-around;\n}\n\n.Stack[data-justify=\"evenly\"] {\n justify-content: space-evenly;\n}\n\n.Stack[data-wrap] {\n flex-wrap: wrap;\n}\n","\"use client\";\n\nimport { useRender } from \"@base-ui/react/use-render\";\n\nimport type { SpacingFactor } from \"../../theme/token-types\";\nimport { mergeClassName } from \"../../utils/merge-class-name\";\nimport { type Responsive, responsiveVars } from \"./responsive\";\nimport styles from \"./stack.module.css\";\n\nexport type StackDirection = \"column\" | \"row\";\nexport type StackAlign = \"start\" | \"center\" | \"end\" | \"stretch\" | \"baseline\";\nexport type StackJustify =\n | \"start\"\n | \"center\"\n | \"end\"\n | \"between\"\n | \"around\"\n | \"evenly\";\n\nexport type StackProps = Omit<useRender.ComponentProps<\"div\">, \"ref\"> & {\n /**\n * Main axis. There is deliberately no reversed direction: it would make the\n * visual order differ from the reading and focus order.\n * @default \"column\"\n */\n direction?: Responsive<StackDirection>;\n /**\n * Space between children, as a multiple of the spacing step (`spacing(n)`).\n * @default 0\n */\n gap?: Responsive<SpacingFactor>;\n /** Cross-axis alignment (`align-items`). Stretches when unset. */\n align?: StackAlign;\n /** Main-axis distribution (`justify-content`). */\n justify?: StackJustify;\n /**\n * Lets children wrap onto new lines.\n * @default false\n */\n wrap?: boolean;\n};\n\n/**\n * Lays its children out in one direction with even, token-based spacing.\n * `direction` and `gap` take a value per breakpoint, mobile-first:\n *\n * ```tsx\n * <Stack direction={{ base: \"column\", md: \"row\" }} gap={{ base: 2, md: 3 }}>\n * <Card />\n * <Card />\n * </Stack>\n * ```\n *\n * Renders a `div`; pass `render` for another element, e.g.\n * `render={<ul />}` with `<li>` children.\n */\nexport function Stack({\n direction,\n gap,\n align,\n justify,\n wrap = false,\n render,\n className,\n style,\n ...rest\n}: StackProps) {\n return useRender({\n render,\n props: {\n ...rest,\n \"data-align\": align,\n \"data-justify\": justify,\n \"data-wrap\": wrap || undefined,\n className: mergeClassName(styles.Stack, className)({}),\n style: {\n ...responsiveVars(\"direction\", direction),\n ...responsiveVars(\"gap\", gap),\n ...style,\n },\n },\n });\n}\n\nexport type HStackProps = Omit<StackProps, \"direction\">;\n\n/**\n * A `Stack` fixed to `direction=\"row\"`. Children stay on one line unless\n * `wrap` is set.\n *\n * ```tsx\n * <HStack gap={1} justify=\"end\">\n * <Button variant=\"outline\">Avbryt</Button>\n * <Button>Lagre</Button>\n * </HStack>\n * ```\n */\nexport function HStack(props: HStackProps) {\n return <Stack {...props} direction=\"row\" />;\n}\n","import { fontSizes, fontWeights, palette } from \"@/theme/tokens\";\nimport { alpha, Box, useTheme } from \"@mui/material\";\nimport {\n animate,\n motion,\n useMotionValue,\n useReducedMotion,\n} from \"motion/react\";\nimport { useEffect } from \"react\";\n\nexport type ProgressCircleColor = \"purple\" | \"teal\";\n\nexport type ProgressCircleProps = {\n /** Current value, e.g. the active step (1-based). Clamped to `0..max`. */\n value: number;\n /** Maximum value, e.g. the total number of steps. */\n max: number;\n /** Ring colour. Defaults to `purple`. */\n color?: ProgressCircleColor;\n /** Rendered diameter in px. Defaults to `48`. */\n size?: number;\n /** Ring thickness in px. Defaults to `4`. */\n strokeWidth?: number;\n /** Show the `value/max` label in the centre. Defaults to `true`. */\n showValue?: boolean;\n /**\n * Accessible name. When provided, the circle is exposed as a\n * `role=\"progressbar\"` (with `aria-valuetext={label}`) so it announces on its\n * own. When omitted, the circle is decorative (`aria-hidden`) — use this when\n * the surrounding component already conveys progress in text (as `FormStepper`\n * does).\n */\n label?: string;\n};\n\n/**\n * An animated circular progress indicator. Not a MUI component: the ring is an\n * SVG whose stroke animates as `value` changes, respecting\n * `prefers-reduced-motion`. Colour is limited to the brand `purple` / `teal`\n * tokens so contrast stays owned by the theme.\n *\n * ```tsx\n * <ProgressCircle value={2} max={5} color=\"teal\" label=\"Step 2 of 5\" />\n * ```\n */\nexport const ProgressCircle = ({\n value,\n max,\n color = \"purple\",\n size = 48,\n strokeWidth = 4,\n showValue = true,\n label,\n}: ProgressCircleProps) => {\n const theme = useTheme();\n const prefersReducedMotion = useReducedMotion();\n\n const radius = (size - strokeWidth) / 2;\n const circumference = 2 * Math.PI * radius;\n const fraction = max > 0 ? Math.min(Math.max(value / max, 0), 1) : 0;\n const dashOffsetFor = (value: number) => circumference * (1 - value);\n\n const offset = useMotionValue(dashOffsetFor(0));\n\n useEffect(() => {\n const target = dashOffsetFor(fraction);\n if (prefersReducedMotion) {\n offset.set(target);\n return;\n }\n\n const controls = animate(offset, target, {\n duration: 0.6,\n ease: \"easeInOut\",\n });\n return () => controls.stop();\n // `circumference` is derived from size/strokeWidth, so it re-runs when those change.\n }, [fraction, circumference, prefersReducedMotion, offset]);\n\n const progressColor = palette[color].base;\n const trackColor = alpha(progressColor, 0.2);\n\n const accessibilityProps = label\n ? ({\n role: \"progressbar\",\n \"aria-label\": label,\n \"aria-valuemin\": 0,\n \"aria-valuemax\": max,\n \"aria-valuenow\": value,\n } as const)\n : ({ \"aria-hidden\": true } as const);\n\n return (\n <Box\n {...accessibilityProps}\n sx={{\n position: \"relative\",\n width: size,\n height: size,\n flexShrink: 0,\n }}\n >\n <svg\n width={size}\n height={size}\n viewBox={`0 0 ${size} ${size}`}\n style={{ transform: \"rotate(-90deg)\", transformOrigin: \"center\" }}\n >\n <circle\n cx={size / 2}\n cy={size / 2}\n r={radius}\n fill=\"none\"\n stroke={trackColor}\n strokeWidth={strokeWidth}\n />\n <motion.circle\n cx={size / 2}\n cy={size / 2}\n r={radius}\n fill=\"none\"\n stroke={progressColor}\n strokeWidth={strokeWidth}\n strokeLinecap=\"round\"\n strokeDasharray={circumference}\n style={{ strokeDashoffset: offset }}\n />\n </svg>\n {showValue && (\n <Box\n component=\"span\"\n sx={{\n position: \"absolute\",\n inset: 0,\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n fontFamily: theme.typography.fontFamily,\n fontWeight: fontWeights.medium,\n fontSize: fontSizes.sm,\n color: progressColor,\n lineHeight: 1,\n }}\n >\n {value}/{max}\n </Box>\n )}\n </Box>\n );\n};\n","import { createTranslation } from \"../../i18n\";\n\n/**\n * Translated labels for `FormStepper`: the back button's accessible name, the\n * \"Next\" subtitle prefix, and the visually-hidden \"step X of Y\" context.\n * Consumers can override any of these per-instance via the `labels` prop.\n */\nexport const useStepperLabels = createTranslation({\n back: { no: \"Tilbake\", se: \"Tillbaka\", fi: \"Takaisin\", es: \"Atrás\" },\n next: { no: \"Neste\", se: \"Nästa\", fi: \"Seuraava\", es: \"Siguiente\" },\n step: { no: \"Trinn\", se: \"Steg\", fi: \"Vaihe\", es: \"Paso\" },\n of: { no: \"av\", se: \"av\", fi: \"/\", es: \"de\" },\n});\n\nexport type StepperLabels = Partial<ReturnType<typeof useStepperLabels>>;\n","import { Box, Divider } from \"@mui/material\";\nimport { ArrowLeft } from \"lucide-react\";\nimport { useId, type ReactNode } from \"react\";\n\nimport { IconButton } from \"../buttons\";\nimport { Text } from \"../typography\";\nimport { ProgressCircle, type ProgressCircleColor } from \"./progress-circle\";\nimport { useStepperLabels, type StepperLabels } from \"./use-stepper-labels\";\n\nconst visuallyHidden = {\n position: \"absolute\",\n width: \"1px\",\n height: \"1px\",\n overflow: \"hidden\",\n clip: \"rect(0 0 0 0)\",\n whiteSpace: \"nowrap\",\n} as const;\n\nexport type FormStepperProps = {\n /** Active step (1-based). */\n currentStep: number;\n /** Total number of steps. */\n totalSteps: number;\n /** Title of the current step. Rendered as a heading by default (see `titleAs`). */\n title: ReactNode;\n /**\n * Name of the next step. When set, a translated `\"{Next}: {nextStep}\"`\n * subtitle is shown. Omit it on the last step.\n */\n nextStep?: ReactNode;\n /**\n * Called when the back button is pressed. The back button only renders when\n * this is provided, so omit it on the first step or in forms without a back\n * flow.\n */\n onBack?: () => void;\n /** Progress circle colour. Defaults to `purple`. */\n color?: ProgressCircleColor;\n /**\n * Render the title as a `heading` (default) or plain `text`. Prefer `heading`\n * so screen-reader users can navigate to it; only use `text` when another\n * heading already labels the view.\n */\n titleAs?: \"heading\" | \"text\";\n /** Heading level when `titleAs=\"heading\"`. Defaults to `h1`. */\n headingLevel?: \"h1\" | \"h2\" | \"h3\";\n /**\n * Id applied to the title. Defaults to a generated id. Use it to move focus to\n * the title when the step changes so the new step is announced.\n */\n titleId?: string;\n /** Override the built-in translated labels per-instance. */\n labels?: StepperLabels;\n /** Show the divider below the header. Defaults to `true`. */\n showDivider?: boolean;\n};\n\n/**\n * Header for a multi-step form. Shows the current step title (as a heading by\n * default), an optional `\"Next: ...\"` subtitle, an optional back button, and an\n * animated `ProgressCircle`.\n *\n * Accessibility is wired internally: the step count (`\"step X of Y\"`) is added\n * to the title as visually-hidden text and the circle is decorative, so the\n * count is announced once. The title carries `tabIndex={-1}`; move focus to it\n * (via `titleId`) whenever the step changes so screen-reader users hear the new\n * step.\n *\n * ```tsx\n * <FormStepper\n * currentStep={2}\n * totalSteps={5}\n * title=\"Civil status\"\n * nextStep=\"Employment\"\n * onBack={() => history.back()}\n * />\n * ```\n */\nexport const FormStepper = ({\n currentStep,\n totalSteps,\n title,\n nextStep,\n onBack,\n color = \"purple\",\n titleAs = \"heading\",\n headingLevel = \"h1\",\n titleId,\n labels,\n showDivider = true,\n}: FormStepperProps) => {\n const t = useStepperLabels();\n const l = { ...t, ...labels };\n const generatedId = useId();\n const resolvedTitleId = titleId ?? generatedId;\n\n const isHeading = titleAs === \"heading\";\n const stepContext = `, ${l.step} ${currentStep} ${l.of} ${totalSteps}`;\n\n return (\n <>\n <Box\n sx={{\n display: \"flex\",\n flexDirection: \"row\",\n alignItems: \"center\",\n justifyContent: \"space-between\",\n gap: 2,\n width: \"100%\",\n }}\n >\n <Box\n sx={{\n display: \"flex\",\n flexDirection: \"row\",\n alignItems: \"center\",\n gap: 2,\n }}\n >\n {onBack && (\n <IconButton\n aria-label={l.back}\n onClick={onBack}\n variant=\"outline\"\n color=\"neutral\"\n >\n <ArrowLeft aria-hidden />\n </IconButton>\n )}\n <Box sx={{ display: \"flex\", flexDirection: \"column\" }}>\n <Text\n id={resolvedTitleId}\n tabIndex={-1}\n component={isHeading ? headingLevel : \"p\"}\n fontSize={isHeading ? \"lg\" : \"md\"}\n fontWeight=\"medium\"\n color=\"text.base\"\n sx={{ margin: 0, outline: \"none\" }}\n >\n {title}\n <Box component=\"span\" sx={visuallyHidden}>\n {stepContext}\n </Box>\n </Text>\n {nextStep != null && (\n <Text fontSize=\"sm\" color=\"text.subtle\">\n {l.next}: {nextStep}\n </Text>\n )}\n </Box>\n </Box>\n <ProgressCircle value={currentStep} max={totalSteps} color={color} />\n </Box>\n {showDivider && <Divider sx={{ my: 1 }} />}\n </>\n );\n};\n","/*\n * Design tokens come from src/theme/tokens.css, generated from src/theme/tokens\n * by `pnpm tokens:css`. It is a plain stylesheet rather than runtime-injected\n * CSS variables, so this component renders correctly without a provider.\n */\n\n.LinearFormStepper {\n --stepper-bar: var(--lea-palette-purple-base);\n --stepper-track: var(--lea-palette-purple-subtle);\n\n display: flex;\n width: 100%;\n flex-direction: column;\n gap: calc(var(--lea-spacing) * 1.5);\n}\n\n.LinearFormStepper[data-color=\"teal\"] {\n --stepper-bar: var(--lea-palette-teal-base);\n --stepper-track: var(--lea-palette-teal-subtle);\n}\n\n.Progress {\n width: 100%;\n}\n\n.Track {\n position: relative;\n overflow: hidden;\n height: calc(var(--lea-spacing) * 0.75);\n border-radius: var(--lea-radius-full);\n background-color: var(--stepper-track);\n}\n\n.Indicator {\n height: 100%;\n border-radius: var(--lea-radius-full);\n background-color: var(--stepper-bar);\n transition: width var(--lea-duration-emphasis) var(--lea-easing-standard);\n}\n\n.Header {\n display: flex;\n align-items: center;\n gap: calc(var(--lea-spacing) * 2);\n}\n\n.Title {\n margin: 0;\n color: var(--lea-palette-text-base);\n font-size: var(--lea-font-size-xl);\n font-weight: var(--lea-font-weight-medium);\n line-height: 1.4;\n outline: none;\n}\n\n.TitleText {\n animation: stepper-title-in var(--lea-duration-normal)\n var(--lea-easing-standard);\n}\n\n@keyframes stepper-title-in {\n from {\n opacity: 0;\n }\n}\n\n@media (prefers-reduced-motion: reduce) {\n .Indicator {\n transition: none;\n }\n\n .TitleText {\n animation: none;\n }\n}\n","\"use client\";\n\nimport { Progress } from \"@base-ui/react/progress\";\nimport { ArrowLeft } from \"lucide-react\";\nimport { useId, type ReactNode } from \"react\";\n\nimport { IconButton } from \"../buttons/icon-button\";\nimport styles from \"./linear-form-stepper.module.css\";\nimport type { ProgressCircleColor } from \"./progress-circle\";\nimport { useStepperLabels, type StepperLabels } from \"./use-stepper-labels\";\n\nexport type LinearFormStepperProps = {\n /** Active step (1-based). */\n currentStep: number;\n /**\n * Total number of steps. May change between renders, e.g. when the next step\n * from the API reveals a different path; the bar animates to the new value.\n */\n totalSteps: number;\n /** Title of the current step. Rendered as a heading and names the progress bar. */\n title: ReactNode;\n /**\n * Called when the back button is pressed. The back button only renders when\n * this is provided, so omit it on the first step or in forms without a back\n * flow.\n */\n onBack?: () => void;\n /**\n * Bar colour.\n * @default \"purple\"\n */\n color?: ProgressCircleColor;\n /**\n * Heading level of the title.\n * @default \"h1\"\n */\n headingLevel?: \"h1\" | \"h2\" | \"h3\";\n /**\n * Id applied to the title. Defaults to a generated id. Use it to move focus to\n * the title when the step changes so the new step is announced. Must be\n * unique in the document.\n */\n titleId?: string;\n /** Override the built-in translated labels per-instance. */\n labels?: StepperLabels;\n};\n\n/**\n * Header for a multi-step form whose steps aren't all known up front: a linear\n * progress bar above the current step's title, with an optional back button.\n * Use `FormStepper` instead when the full step list is known.\n *\n * The bar is a `progressbar` named by the title heading, with the step count\n * (`\"step X of Y\"`) as its value text. The title carries `tabIndex={-1}`; move\n * focus to it (via `titleId`) whenever the step changes so screen-reader users\n * hear the new step.\n *\n * ```tsx\n * <LinearFormStepper\n * currentStep={2}\n * totalSteps={5}\n * title=\"Refinancing\"\n * onBack={() => history.back()}\n * />\n * ```\n */\nexport const LinearFormStepper = ({\n currentStep,\n totalSteps,\n title,\n onBack,\n color = \"purple\",\n headingLevel: Heading = \"h1\",\n titleId,\n labels,\n}: LinearFormStepperProps) => {\n const t = useStepperLabels();\n const l = { ...t, ...labels };\n const generatedId = useId();\n const resolvedTitleId = titleId ?? generatedId;\n\n return (\n <div className={styles.LinearFormStepper} data-color={color}>\n {/*\n * The heading sits outside the progressbar: its children are\n * presentational, so a heading inside it would be hidden from assistive\n * technology.\n */}\n <Progress.Root\n className={styles.Progress}\n value={currentStep}\n max={totalSteps}\n aria-labelledby={resolvedTitleId}\n getAriaValueText={() =>\n `${l.step} ${currentStep} ${l.of} ${totalSteps}`\n }\n >\n <Progress.Track className={styles.Track}>\n <Progress.Indicator className={styles.Indicator} />\n </Progress.Track>\n </Progress.Root>\n <div className={styles.Header}>\n {onBack && (\n <IconButton\n aria-label={l.back}\n onClick={onBack}\n variant=\"outline\"\n color=\"neutral\"\n >\n <ArrowLeft aria-hidden />\n </IconButton>\n )}\n <Heading id={resolvedTitleId} tabIndex={-1} className={styles.Title}>\n <span key={currentStep} className={styles.TitleText}>\n {title}\n </span>\n </Heading>\n </div>\n </div>\n );\n};\n","\"use client\";\n\nimport {\n createContext,\n useContext,\n useEffect,\n useState,\n type Dispatch,\n type ReactNode,\n type SetStateAction,\n} from \"react\";\n\nimport {\n LinearFormStepper,\n type LinearFormStepperProps,\n} from \"./linear-form-stepper\";\n\n/**\n * The step a flow is on, already resolved by the app. The library never\n * defines steps: the app maps its own step (e.g. from the API) to a position\n * and a translated title, then reports it.\n */\nexport type StepProgress = {\n /** Active step (1-based). */\n currentStep: number;\n /** Total number of steps. May change as the flow reveals its path. */\n totalSteps: number;\n /** Translated title of the current step. */\n title: string;\n};\n\nconst StepProgressStateContext = createContext<StepProgress | null>(null);\nconst ReportStepProgressContext = createContext<Dispatch<\n SetStateAction<StepProgress | null>\n> | null>(null);\n\nexport type StepProgressProviderProps = {\n children: ReactNode;\n /**\n * Progress to show on the first render, before any page has reported, e.g.\n * so a server-rendered layout paints the bar straight away.\n */\n initialProgress?: StepProgress;\n};\n\n/**\n * Holds the step a persistent flow header shows. Put it in the flow layout,\n * above the route's loading boundary, so the header survives step navigations\n * instead of remounting with the page, and its bar animates between steps.\n *\n * ```tsx\n * <StepProgressProvider>\n * <StepProgressHeader onBack={router.back} />\n * {children}\n * </StepProgressProvider>\n * ```\n */\nexport const StepProgressProvider = ({\n children,\n initialProgress,\n}: StepProgressProviderProps) => {\n const [progress, setProgress] = useState<StepProgress | null>(\n initialProgress ?? null,\n );\n\n return (\n <ReportStepProgressContext.Provider value={setProgress}>\n <StepProgressStateContext.Provider value={progress}>\n {children}\n </StepProgressStateContext.Provider>\n </ReportStepProgressContext.Provider>\n );\n};\n\n/**\n * The last reported step, or `null` before anything has been reported or\n * outside a `StepProgressProvider`. Use it to render `FormStepper` or a custom\n * header from the same state.\n */\nexport const useStepProgress = () => useContext(StepProgressStateContext);\n\n/**\n * Publishes the current step to the nearest `StepProgressProvider`. Pass\n * `null` while the step isn't resolved yet; nothing is reported then. Never\n * clears on unmount, so the header holds its value while the next route's\n * loading fallback is on screen.\n *\n * ```tsx\n * useReportStepProgress({ currentStep: 2, totalSteps: 5, title: t(\"income\") });\n * ```\n */\nexport const useReportStepProgress = (progress: StepProgress | null) => {\n const report = useContext(ReportStepProgressContext);\n const currentStep = progress?.currentStep;\n const totalSteps = progress?.totalSteps;\n const title = progress?.title;\n\n useEffect(() => {\n if (\n !report ||\n currentStep === undefined ||\n totalSteps === undefined ||\n title === undefined\n ) {\n return;\n }\n report({ currentStep, totalSteps, title });\n }, [report, currentStep, totalSteps, title]);\n};\n\nexport type StepProgressHeaderProps = Omit<\n LinearFormStepperProps,\n \"currentStep\" | \"totalSteps\" | \"title\"\n>;\n\n/**\n * A `LinearFormStepper` driven by the nearest `StepProgressProvider`. Renders\n * nothing until a step has been reported. Everything except the step itself\n * (`onBack`, `color`, `headingLevel`, …) is passed as props.\n */\nexport const StepProgressHeader = (props: StepProgressHeaderProps) => {\n const progress = useStepProgress();\n if (!progress) {\n return null;\n }\n\n return <LinearFormStepper {...props} {...progress} />;\n};\n","import { SxProps, Theme } from \"@mui/material\";\nimport {\n colors,\n durations,\n easings,\n fontSizes,\n fontWeights,\n palette,\n shape,\n transition,\n} from \"../tokens\";\nimport { focusVisibleStyles } from \"../utils\";\n\n/**\n * Styling for the segmented `Tabs` control. Base UI has no MUI slot to override\n * globally, so — like `number-input` — these are exported `sx` objects the\n * component applies, keeping the component lean while the visual tokens live\n * here.\n */\n\n/** The visual variants of the active \"pill\". */\nexport type TabsVariant = \"brand\" | \"greyscale\";\n\n/**\n * The track that holds the tab buttons: a rounded, beige pill container. Scrolls\n * horizontally when the tabs overflow (e.g. on mobile) with the scrollbar\n * hidden, and positions the sliding indicator via `position: relative`.\n */\nexport const tabsListSx: SxProps<Theme> = {\n position: \"relative\",\n display: \"flex\",\n flexDirection: \"row\",\n flexWrap: \"nowrap\",\n alignItems: \"center\",\n gap: 0.5,\n padding: 0.5,\n maxWidth: \"100%\",\n borderRadius: `${shape.full}px`,\n backgroundColor: palette.bg.muted,\n overflowX: \"auto\",\n overflowY: \"hidden\",\n // Keep the row swipeable on touch while hiding the scrollbar chrome.\n scrollbarWidth: \"none\",\n msOverflowStyle: \"none\",\n \"&::-webkit-scrollbar\": { display: \"none\" },\n};\n\n/**\n * A single tab button. Transparent by default with muted text; the active tab\n * sits above the pill indicator (`zIndex: 1`) and flips to contrast text. Icons\n * are laid out inline before the label.\n */\nexport const tabSx: SxProps<Theme> = {\n position: \"relative\",\n zIndex: 1,\n flexShrink: 0,\n display: \"inline-flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n gap: 1,\n margin: 0,\n border: \"none\",\n background: \"none\",\n cursor: \"pointer\",\n whiteSpace: \"nowrap\",\n userSelect: \"none\",\n paddingInline: 2,\n paddingBlock: 1.25,\n borderRadius: `${shape.full}px`,\n fontFamily: \"inherit\",\n fontSize: fontSizes.md,\n fontWeight: fontWeights.medium,\n lineHeight: 1,\n // neutral[600] rather than text.subtle so the inactive label clears WCAG AA\n // (4.5:1) against the beige track.\n color: colors.neutral[600],\n transition: transition([\"color\"]),\n \"& svg\": { flexShrink: 0, display: \"block\" },\n \"&[data-active]\": { color: palette.text.contrast },\n \"&[data-disabled]\": {\n opacity: 0.45,\n cursor: \"not-allowed\",\n pointerEvents: \"none\",\n },\n ...focusVisibleStyles,\n};\n\n/**\n * A tab panel. Base UI makes the panel focusable (`tabIndex={0}`) so keyboard\n * users can reach its content, so it needs a visible focus ring and a little\n * breathing room from the tab list.\n */\nexport const tabPanelSx: SxProps<Theme> = {\n paddingBlockStart: 2,\n outlineOffset: 2,\n ...focusVisibleStyles,\n};\n\nconst indicatorBackground: Record<TabsVariant, string> = {\n brand: palette.purple.base,\n greyscale: colors.neutral[950],\n};\n\n/**\n * The sliding \"pill\" behind the active tab. Base UI exposes the active tab's\n * geometry as CSS variables on this element (`--active-tab-*`); we translate\n * those into position/size. The slide is disabled under\n * `prefers-reduced-motion`.\n */\nexport const tabsIndicatorSx = (variant: TabsVariant): SxProps<Theme> => ({\n position: \"absolute\",\n zIndex: 0,\n top: \"var(--active-tab-top)\",\n left: \"var(--active-tab-left)\",\n width: \"var(--active-tab-width)\",\n height: \"var(--active-tab-height)\",\n borderRadius: `${shape.full}px`,\n backgroundColor: indicatorBackground[variant],\n transition: transition(\n [\"top\", \"left\", \"width\", \"height\"],\n durations.normal,\n easings.standard,\n ),\n \"@media (prefers-reduced-motion: reduce)\": {\n transition: \"none\",\n },\n});\n","\"use client\";\n\nimport { Tabs as BaseTabs } from \"@base-ui/react/tabs\";\nimport { Box } from \"@mui/material\";\nimport { createContext, useContext } from \"react\";\n\nimport {\n tabPanelSx,\n tabSx,\n tabsIndicatorSx,\n tabsListSx,\n type TabsVariant,\n} from \"../../theme/components/tabs.theme\";\n\nconst TabsVariantContext = createContext<TabsVariant>(\"brand\");\n\nexport type { TabsVariant };\n\nexport type TabsProps = BaseTabs.Root.Props & {\n /**\n * Colour of the active-tab \"pill\".\n * - `\"brand\"` — filled with the brand purple (default).\n * - `\"greyscale\"` — filled with near-black, for a neutral surface.\n * @default \"brand\"\n */\n variant?: TabsVariant;\n};\n\n/**\n * A segmented, pill-style tabs control built on Base UI's accessible `Tabs`\n * primitive. Renders a beige track with a sliding pill behind the active tab.\n *\n * Compose it from `TabsList` + `Tab` (the tab bar) and, optionally, `TabPanel`\n * for built-in content. Roles (`tablist`/`tab`/`tabpanel`), roving `tabindex`,\n * arrow-key navigation, `aria-selected` and the `tab`↔`tabpanel` links are all\n * wired by Base UI, so relationships never dangle.\n *\n * The list scrolls horizontally when the tabs overflow (e.g. on mobile) and the\n * pill slide respects `prefers-reduced-motion`.\n *\n * ```tsx\n * <Tabs defaultValue=\"overview\">\n * <TabsList aria-label=\"Account sections\">\n * <Tab value=\"overview\">Overview</Tab>\n * <Tab value=\"activity\">Activity</Tab>\n * </TabsList>\n * <TabPanel value=\"overview\">Workspace stats and activity.</TabPanel>\n * <TabPanel value=\"activity\">Recent activity.</TabPanel>\n * </Tabs>\n * ```\n */\nexport function Tabs({ variant = \"brand\", ...rest }: TabsProps) {\n return (\n <TabsVariantContext.Provider value={variant}>\n <BaseTabs.Root {...rest} />\n </TabsVariantContext.Provider>\n );\n}\n\n/**\n * Requires an accessible name so the underlying `tablist` is never nameless.\n * Provide exactly one of `aria-label` or `aria-labelledby`.\n */\ntype TabsListAccessibleName =\n | { \"aria-label\": string; \"aria-labelledby\"?: never }\n | { \"aria-labelledby\": string; \"aria-label\"?: never };\n\nexport type TabsListProps = Omit<\n BaseTabs.List.Props,\n \"render\" | \"aria-label\" | \"aria-labelledby\"\n> &\n TabsListAccessibleName;\n\n/**\n * Groups the `Tab` buttons into the pill track. The sliding indicator is\n * rendered internally so it can never go missing.\n */\nexport function TabsList({ children, ...rest }: TabsListProps) {\n return (\n <BaseTabs.List {...rest} render={<Box sx={tabsListSx} />}>\n {children}\n <TabsIndicator />\n </BaseTabs.List>\n );\n}\n\nexport type TabProps = Omit<BaseTabs.Tab.Props, \"render\">;\n\n/**\n * An individual tab. Pass an icon and label as children; mark decorative icons\n * with `aria-hidden` so they aren't announced.\n *\n * ```tsx\n * <Tab value=\"transactions\">\n * <Receipt size={18} aria-hidden />\n * Transaksjoner\n * </Tab>\n * ```\n */\nexport function Tab(props: TabProps) {\n return (\n <BaseTabs.Tab\n {...props}\n render={<Box component=\"button\" type=\"button\" sx={tabSx} />}\n />\n );\n}\n\nexport type TabsIndicatorProps = Omit<BaseTabs.Indicator.Props, \"render\">;\n\n/**\n * The sliding pill behind the active tab. `TabsList` already renders one, so\n * you only need this when composing a custom list.\n */\nexport function TabsIndicator(props: TabsIndicatorProps) {\n const variant = useContext(TabsVariantContext);\n return (\n <BaseTabs.Indicator\n {...props}\n render={<Box component=\"span\" sx={tabsIndicatorSx(variant)} />}\n />\n );\n}\n\nexport type TabPanelProps = Omit<BaseTabs.Panel.Props, \"render\">;\n\n/**\n * Content shown when the `Tab` with the matching `value` is active. Optional —\n * omit it to use `Tabs` purely as a bar that toggles content you render\n * elsewhere (drive it with `value`/`onValueChange`).\n */\nexport function TabPanel(props: TabPanelProps) {\n return <BaseTabs.Panel {...props} render={<Box sx={tabPanelSx} />} />;\n}\n","/*\n * Design tokens come from src/theme/tokens.css, generated from src/theme/tokens\n * by `pnpm tokens:css`. It is a plain stylesheet rather than runtime-injected\n * CSS variables, so this component renders correctly without a provider.\n * `--lea-spacing` is the 0.5rem base unit, multiplied to match `spacing(n)`.\n */\n\n/*\n * Each variant overrides the local properties below; the defaults are\n * `outline`. `.Item` and `.Header` only read them, so hover and active states\n * are one rule each rather than one per variant.\n */\n.Root {\n --accordion-gap: var(--lea-spacing);\n --accordion-item-bg: transparent;\n --accordion-item-border: var(--lea-palette-border-subtle);\n --accordion-item-radius: var(--lea-radius-2xl);\n --accordion-header-radius: var(--lea-radius-2xl);\n --accordion-hover-border: var(--lea-palette-border-strong);\n --accordion-hover-bg: transparent;\n --accordion-active-bg: var(--lea-color-purple-50);\n\n display: flex;\n width: 100%;\n flex-direction: column;\n gap: var(--accordion-gap);\n}\n\n.Root[data-variant=\"solid\"] {\n --accordion-item-bg: var(--lea-palette-bg-subtle);\n --accordion-item-border: transparent;\n --accordion-hover-border: transparent;\n --accordion-hover-bg: var(--lea-color-neutral-100);\n --accordion-active-bg: var(--lea-color-neutral-200);\n}\n\n/* No surface of their own, so hover and pressed lighten whatever the accordion\n sits on with translucent white; the hint of text colour keeps them visible\n on white. */\n.Root[data-variant=\"divided\"],\n.Root[data-variant=\"ghost\"] {\n --accordion-highlight: color-mix(\n in srgb,\n var(--lea-color-white) calc(var(--lea-opacity-highlight) * 100%),\n transparent\n );\n --accordion-item-border: transparent;\n --accordion-header-radius: var(--lea-radius-sm);\n --accordion-hover-border: transparent;\n --accordion-hover-bg: color-mix(\n in srgb,\n var(--lea-palette-text-base) calc(var(--lea-opacity-hover) * 100%),\n var(--accordion-highlight)\n );\n --accordion-active-bg: color-mix(\n in srgb,\n var(--lea-palette-text-base) calc(var(--lea-opacity-pressed) * 100%),\n var(--accordion-highlight)\n );\n}\n\n.Root[data-variant=\"divided\"] {\n --accordion-gap: 0;\n --accordion-item-radius: 0;\n}\n\n.Item {\n border: 1px solid var(--accordion-item-border);\n border-radius: var(--accordion-item-radius);\n background-color: var(--accordion-item-bg);\n}\n\n.Root[data-variant=\"divided\"] > .Item:not(:last-child) {\n border-block-end-color: var(--lea-palette-border-subtle);\n}\n\n/*\n * The row lives on the header rather than the trigger so a control rendered\n * beside the trigger (a Switch, say) sits inside the same hover outline.\n */\n.Header {\n display: flex;\n align-items: center;\n gap: calc(var(--lea-spacing) * 2);\n padding: calc(var(--lea-spacing) * 1.7) calc(var(--lea-spacing) * 2);\n border: 1px solid transparent;\n border-radius: var(--accordion-header-radius);\n margin: 0;\n transition: border-color var(--lea-duration-emphasis)\n var(--lea-easing-standard),\n background-color var(--lea-duration-emphasis) var(--lea-easing-standard);\n}\n\n@media (hover: hover) {\n .Header:has(.Trigger:hover:not([data-disabled])) {\n border-color: var(--accordion-hover-border);\n background-color: var(--accordion-hover-bg);\n }\n}\n\n.Header:has(.Trigger:active:not([data-disabled])) {\n background-color: var(--accordion-active-bg);\n}\n\n.Trigger {\n display: flex;\n min-width: 0;\n flex: 1;\n align-items: center;\n justify-content: space-between;\n gap: var(--lea-spacing);\n padding: 0;\n border: none;\n margin: 0;\n background-color: transparent;\n color: var(--lea-palette-text-base);\n cursor: pointer;\n font-family: inherit;\n font-size: var(--lea-font-size-md);\n font-weight: var(--lea-font-weight-medium);\n line-height: 1.5;\n text-align: left;\n}\n\n.Trigger:focus-visible {\n outline: 2px solid var(--lea-palette-text-base);\n outline-offset: 0.125rem;\n}\n\n.Trigger[data-disabled] {\n color: var(--lea-palette-text-muted);\n cursor: not-allowed;\n}\n\n.Label {\n min-width: 0;\n}\n\n.Icon {\n flex-shrink: 0;\n transition: transform var(--lea-duration-emphasis) var(--lea-easing-standard);\n}\n\n.Trigger[data-panel-open] .Icon {\n transform: rotate(180deg);\n}\n\n/* Arrow before the title, so it stays next to the text it belongs to. */\n.Root[data-icon-position=\"start\"] .Trigger {\n justify-content: flex-start;\n}\n\n.Root[data-icon-position=\"start\"] .Icon {\n order: -1;\n}\n\n.Panel {\n height: var(--accordion-panel-height);\n overflow: hidden;\n transition: height var(--lea-duration-emphasis) var(--lea-easing-standard);\n}\n\n.Panel[data-starting-style],\n.Panel[data-ending-style] {\n height: 0;\n}\n\n.Content {\n padding-inline: calc(var(--lea-spacing) * 2);\n padding-block: var(--lea-spacing);\n color: var(--lea-palette-text-base);\n font-size: var(--lea-font-size-md);\n line-height: 1.5;\n}\n\n@media (prefers-reduced-motion: reduce) {\n .Header,\n .Icon,\n .Panel {\n transition-duration: 0.01ms;\n }\n}\n","\"use client\";\n\nimport { Accordion as BaseAccordion } from \"@base-ui/react/accordion\";\nimport { ChevronDown } from \"lucide-react\";\n\nimport { mergeClassName } from \"../../utils/merge-class-name\";\nimport styles from \"./accordion.module.css\";\n\nexport type Variant = \"outline\" | \"solid\" | \"divided\" | \"ghost\";\n\nexport type IconPosition = \"start\" | \"end\";\n\nexport type RootProps = BaseAccordion.Root.Props & {\n /**\n * Surface treatment of each item.\n * - `\"outline\"` — transparent cards with a light `border.subtle` border\n * (default). Hovering outlines the header.\n * - `\"solid\"` — borderless cards filled light grey (`bg.subtle`). Hovering\n * darkens the header instead of outlining it.\n * - `\"divided\"` — a flush list with no cards, items separated by thin lines.\n * Suits long FAQ lists.\n * - `\"ghost\"` — no border or fill; only the hover tint shows. Use it on\n * tinted backgrounds.\n * @default \"outline\"\n */\n variant?: Variant;\n /**\n * Which side of the title the expand arrow sits on. Use `\"start\"` when the\n * header also holds a control (such as a `Switch`), so the arrow stays next\n * to the title it belongs to.\n * @default \"end\"\n */\n iconPosition?: IconPosition;\n};\n\n/**\n * A set of collapsible panels built on Base UI's accessible `Accordion`\n * primitive, styled with Lea's design tokens.\n *\n * Heading semantics, `aria-expanded`, `aria-controls` and the unique ids\n * linking each trigger to its panel are generated by Base UI, so the\n * relationships can never dangle and consumers never supply ids by hand.\n * Only one panel opens at a time unless you pass `multiple`.\n *\n * ```tsx\n * <Accordion.Root defaultValue={[\"shipping\"]}>\n * <Accordion.Item value=\"shipping\">\n * <Accordion.Header>\n * <Accordion.Trigger>How long does shipping take?</Accordion.Trigger>\n * </Accordion.Header>\n * <Accordion.Panel>Three to five business days.</Accordion.Panel>\n * </Accordion.Item>\n * </Accordion.Root>\n * ```\n *\n * For the common title-and-content case, reach for `SimpleAccordion` instead.\n */\nexport function Root({\n variant = \"outline\",\n iconPosition = \"end\",\n className,\n ...rest\n}: RootProps) {\n return (\n <BaseAccordion.Root\n {...rest}\n data-variant={variant}\n data-icon-position={iconPosition}\n className={mergeClassName(styles.Root, className)}\n />\n );\n}\n\nexport type ItemProps = BaseAccordion.Item.Props;\n\n/**\n * One panel of the accordion, pairing a `Header` with a `Panel`. Give it a\n * `value` to open it initially or to control it programmatically.\n */\nexport function Item({ className, ...rest }: ItemProps) {\n return (\n <BaseAccordion.Item\n {...rest}\n className={mergeClassName(styles.Item, className)}\n />\n );\n}\n\nexport type HeaderProps = BaseAccordion.Header.Props;\n\n/**\n * The heading that labels the panel. Renders an `<h3>` and must wrap a\n * `Trigger` so the accordion stays navigable by heading.\n *\n * Anything rendered after the `Trigger` sits on the same row, which is where a\n * per-item control belongs. It must go beside the trigger rather than inside\n * it, because the trigger is a `<button>` and nesting controls is invalid.\n *\n * ```tsx\n * <Accordion.Header>\n * <Accordion.Trigger>Analyse</Accordion.Trigger>\n * <Switch aria-label=\"Analyse-informasjonskapsler\" />\n * </Accordion.Header>\n * ```\n */\nexport function Header({ className, ...rest }: HeaderProps) {\n return (\n <BaseAccordion.Header\n {...rest}\n className={mergeClassName(styles.Header, className)}\n />\n );\n}\n\nexport type TriggerProps = BaseAccordion.Trigger.Props;\n\n/**\n * The button that opens and closes its panel. Pass the question or label as\n * children; the chevron is rendered internally and hidden from assistive\n * technology.\n */\nexport function Trigger({ children, className, ...rest }: TriggerProps) {\n return (\n <BaseAccordion.Trigger\n {...rest}\n className={mergeClassName(styles.Trigger, className)}\n >\n <span className={styles.Label}>{children}</span>\n <ChevronDown className={styles.Icon} size={20} aria-hidden />\n </BaseAccordion.Trigger>\n );\n}\n\nexport type PanelProps = BaseAccordion.Panel.Props;\n\n/**\n * The collapsible content of an item. Padding sits on an inner element so the\n * open/close height animation stays smooth.\n */\nexport function Panel({ children, className, ...rest }: PanelProps) {\n return (\n <BaseAccordion.Panel\n {...rest}\n className={mergeClassName(styles.Panel, className)}\n >\n <div className={styles.Content}>{children}</div>\n </BaseAccordion.Panel>\n );\n}\n","\"use client\";\n\nimport type { ReactNode } from \"react\";\n\nimport * as Accordion from \"./accordion\";\n\nexport type SimpleAccordionItem = {\n /** The heading shown on the row. */\n title: ReactNode;\n /** The collapsible body revealed when the row is opened. */\n content: ReactNode;\n /**\n * A control rendered on the row beside the title, typically a `Switch`.\n * It sits outside the trigger, so operating it doesn't open the panel.\n */\n action?: ReactNode;\n /**\n * Identifies the item for `defaultValue` / `value`. Defaults to the item's\n * position, so only set it when you open or control items programmatically.\n * Only meaningful inside `items`.\n */\n value?: string;\n /** Whether this item can be opened. Only meaningful inside `items`. */\n disabled?: boolean;\n};\n\n/**\n * The single-item form. `value` and `disabled` are left to `Accordion.Root`\n * (they'd otherwise collide with the root's own props of the same name); the\n * lone item always has the value `\"0\"`, so `defaultValue={[\"0\"]}` opens it.\n */\ntype SingleItemProps = Omit<SimpleAccordionItem, \"value\" | \"disabled\"> & {\n items?: never;\n};\n\ntype MultipleItemsProps = {\n items: SimpleAccordionItem[];\n title?: never;\n content?: never;\n action?: never;\n};\n\n// The root props inherit every global HTML attribute, two of which (`title`\n// and the RDFa `content`) share a name with ours and would narrow our\n// `ReactNode` values to `string`. Drop them so our own types win.\nexport type SimpleAccordionProps = Omit<\n Accordion.RootProps,\n \"children\" | \"title\" | \"content\"\n> &\n (SingleItemProps | MultipleItemsProps);\n\n/**\n * The props-driven form of `Accordion` for the common case: a title and some\n * content, with an optional control on the row.\n *\n * Pass `title` and `content` for a single collapsible panel, or `items` for\n * several. Everything `Accordion.Root` accepts — `variant`, `iconPosition`,\n * `multiple`, `defaultValue` — is forwarded. Compose `Accordion.Root` by hand\n * when you need markup the `title` / `content` pair can't express.\n *\n * ```tsx\n * <SimpleAccordion\n * iconPosition=\"start\"\n * title=\"Nødvendige\"\n * content={<Text>Alltid påskrudd.</Text>}\n * action={<Switch aria-label=\"Nødvendige\" checked disabled />}\n * />\n *\n * <SimpleAccordion\n * multiple\n * items={[\n * { title: \"Levering\", content: \"Tre til fem virkedager.\" },\n * { title: \"Retur\", content: \"30 dagers angrerett.\" },\n * ]}\n * />\n * ```\n */\nexport function SimpleAccordion({\n items,\n title,\n content,\n action,\n ...rest\n}: SimpleAccordionProps) {\n const entries: SimpleAccordionItem[] = items ?? [\n { title, content, action } as SimpleAccordionItem,\n ];\n\n return (\n <Accordion.Root {...rest}>\n {entries.map((item, index) => {\n const itemValue = item.value ?? String(index);\n return (\n <Accordion.Item\n key={itemValue}\n value={itemValue}\n disabled={item.disabled}\n >\n <Accordion.Header>\n <Accordion.Trigger>{item.title}</Accordion.Trigger>\n {item.action}\n </Accordion.Header>\n <Accordion.Panel>{item.content}</Accordion.Panel>\n </Accordion.Item>\n );\n })}\n </Accordion.Root>\n );\n}\n",".BrandDivider {\n display: flex;\n width: 100%;\n height: var(--lea-spacing);\n flex-shrink: 0;\n background: linear-gradient(to right,\n var(--lea-palette-status-info-base) 25%,\n var(--lea-palette-teal-base) 25%,\n var(--lea-palette-teal-base) 50%,\n var(--lea-palette-status-warning-base) 50%,\n var(--lea-palette-status-warning-base) 75%,\n var(--lea-palette-purple-base) 75%\n );\n}\n\n.BrandDivider[data-size=\"sm\"] {\n height: calc(var(--lea-spacing) * 0.5);\n}\n\n.BrandDivider[data-size=\"md\"] {\n height: calc(var(--lea-spacing) * 1);\n}\n\n.BrandDivider[data-size=\"lg\"] {\n height: calc(var(--lea-spacing) * 1.5);\n}\n\n","import styles from \"./brand-divider.module.css\";\n\n/**\n *\n * Brand Divider in Lea colors\n *\n */\n\nexport type BrandDividerProps = {\n /**\n * The size of the divider.\n */\n size?: \"sm\" | \"md\" | \"lg\";\n};\n\nexport const BrandDivider = ({ size = \"sm\" }: BrandDividerProps) => {\n return (\n <div aria-hidden=\"true\" className={styles.BrandDivider} data-size={size} />\n );\n};\n",".AppHeader {\n display: flex;\n flex-direction: column;\n width: 100%;\n}\n\n.AppHeader:not([data-brand-divider]) {\n border-bottom: 1px solid var(--lea-palette-border-base);\n}\n\n.AppHeaderContent {\n display: flex;\n align-items: center;\n justify-content: center;\n gap: calc(var(--lea-spacing) * 2);\n padding-block: var(--lea-spacing);\n padding-inline: calc(var(--lea-spacing) * 2);\n}\n\n.AppHeaderContent[data-fluid] {\n max-width: none;\n}\n\n.AppHeader[data-has-children] .AppHeaderContent {\n justify-content: space-between;\n}\n\n.AppHeaderLogo {\n display: flex;\n flex-shrink: 0;\n}\n\n.AppHeaderActions {\n display: flex;\n align-items: center;\n gap: var(--lea-spacing);\n}\n","import { Children, type ReactNode } from \"react\";\n\nimport { Container } from \"../layout/container\";\nimport styles from \"./app-header.module.css\";\nimport { BrandDivider } from \"./brand-divider\";\n\nexport type AppHeaderProps = {\n /**\n * Shows the brand divider under the header. Without it, the header gets a\n * bottom border instead.\n * @default true\n */\n brandDivider?: boolean;\n /**\n * Lets the content span the full width instead of stopping at the `lg`\n * breakpoint. The side padding stays.\n * @default false\n */\n fluid?: boolean;\n /**\n * Content for the right-hand side, e.g. buttons. Without children the logo\n * is centred.\n */\n children?: ReactNode;\n};\n\nexport const AppHeader = ({\n brandDivider = true,\n fluid = false,\n children,\n}: AppHeaderProps) => {\n const hasChildren = Children.toArray(children).length > 0;\n\n return (\n <header\n className={styles.AppHeader}\n data-brand-divider={brandDivider || undefined}\n data-has-children={hasChildren || undefined}\n >\n <Container\n className={styles.AppHeaderContent}\n data-fluid={fluid || undefined}\n >\n <div className={styles.AppHeaderLogo}>\n <img src=\"/leabank-logo.png\" alt=\"Logo\" width={100} />\n </div>\n {hasChildren && (\n <div className={styles.AppHeaderActions}>{children}</div>\n )}\n </Container>\n {brandDivider && <BrandDivider size=\"sm\" />}\n </header>\n );\n};\n","export type Country = \"NO\" | \"SE\" | \"FI\" | \"ES\";\n\nexport type Currency = \"NOK\" | \"SEK\" | \"EUR\";\n\nexport interface CountryConfig {\n country: Country;\n locale: string;\n currency: Currency;\n}\n\nexport const COUNTRIES: Record<Country, CountryConfig> = {\n NO: { country: \"NO\", locale: \"nb-NO\", currency: \"NOK\" },\n SE: { country: \"SE\", locale: \"sv-SE\", currency: \"SEK\" },\n FI: { country: \"FI\", locale: \"fi-FI\", currency: \"EUR\" },\n ES: { country: \"ES\", locale: \"es-ES\", currency: \"EUR\" },\n};\n","import {\n createContext,\n useContext,\n useMemo,\n type ReactNode,\n} from \"react\";\n\nimport { COUNTRIES, type Country, type Currency } from \"./countries\";\n\nexport interface CountryContextValue {\n country: Country;\n locale: string;\n currency: Currency;\n}\n\nconst CountryContext = createContext<CountryContextValue | null>(null);\n\nexport interface CountryProviderProps {\n country: Country;\n children: ReactNode;\n}\n\n/**\n * Supplies the active Lea Bank country to locale-aware formatting hooks.\n */\nexport function CountryProvider({ country, children }: CountryProviderProps) {\n const value = useMemo<CountryContextValue>(() => {\n const config = COUNTRIES[country];\n\n return {\n country: config.country,\n locale: config.locale,\n currency: config.currency,\n };\n }, [country]);\n\n return (\n <CountryContext.Provider value={value}>{children}</CountryContext.Provider>\n );\n}\n\n/**\n * Reads the active country, locale, and default currency from the nearest\n * `CountryProvider`.\n */\nexport function useCountry(): CountryContextValue {\n const context = useContext(CountryContext);\n\n if (!context) {\n throw new Error(\n \"Country hooks must be used within a <CountryProvider>.\",\n );\n }\n\n return context;\n}\n","import { useCallback, useMemo } from \"react\";\n\nimport { type Currency } from \"./country/countries\";\nimport { useCountry } from \"./country/country-context\";\n\nexport type FormatCurrencyOptions = Omit<\n Intl.NumberFormatOptions,\n \"style\" | \"currency\"\n> & {\n currency?: Currency;\n};\n\n/**\n * Returns a locale-aware currency formatter using the active country's locale\n * and default currency. Pass `currency` in options to override per call.\n */\nexport function useFormatCurrency() {\n const { locale, currency: defaultCurrency } = useCountry();\n\n const defaultFormatter = useMemo(\n () =>\n new Intl.NumberFormat(locale, {\n style: \"currency\",\n currency: defaultCurrency,\n }),\n [locale, defaultCurrency],\n );\n\n return useCallback(\n (value: number, options?: FormatCurrencyOptions) => {\n const { currency = defaultCurrency, ...formatOptions } = options ?? {};\n\n if (\n currency === defaultCurrency &&\n Object.keys(formatOptions).length === 0\n ) {\n return defaultFormatter.format(value);\n }\n\n return new Intl.NumberFormat(locale, {\n style: \"currency\",\n currency,\n ...formatOptions,\n }).format(value);\n },\n [defaultCurrency, defaultFormatter, locale],\n );\n}\n","import { useCallback, useMemo } from \"react\";\n\nimport { useCountry } from \"./country/country-context\";\n\nconst DEFAULT_DATE_OPTIONS: Intl.DateTimeFormatOptions = {\n year: \"numeric\",\n month: \"short\",\n day: \"numeric\",\n};\n\nfunction toDate(value: Date | number | string): Date {\n return value instanceof Date ? value : new Date(value);\n}\n\n/**\n * Returns a locale-aware date formatter using the active country's locale.\n */\nexport function useFormatDate() {\n const { locale } = useCountry();\n\n const defaultFormatter = useMemo(\n () => new Intl.DateTimeFormat(locale, DEFAULT_DATE_OPTIONS),\n [locale],\n );\n\n return useCallback(\n (value: Date | number | string, options?: Intl.DateTimeFormatOptions) => {\n const date = toDate(value);\n\n if (!options) {\n return defaultFormatter.format(date);\n }\n\n return new Intl.DateTimeFormat(locale, options).format(date);\n },\n [defaultFormatter, locale],\n );\n}\n","import { useCallback, useMemo } from \"react\";\n\nimport { useCountry } from \"./country/country-context\";\n\n/**\n * Returns a locale-aware plain-number formatter using the active country's\n * locale.\n */\nexport function useFormatNumber() {\n const { locale } = useCountry();\n\n const defaultFormatter = useMemo(\n () => new Intl.NumberFormat(locale),\n [locale],\n );\n\n return useCallback(\n (value: number, options?: Intl.NumberFormatOptions) => {\n if (!options) {\n return defaultFormatter.format(value);\n }\n\n return new Intl.NumberFormat(locale, options).format(value);\n },\n [defaultFormatter, locale],\n );\n}\n\n/**\n * Returns a locale-aware percentage formatter using the active country's\n * locale.\n */\nexport function useFormatPercentage() {\n const { locale } = useCountry();\n\n const defaultFormatter = useMemo(\n () =>\n new Intl.NumberFormat(locale, {\n style: \"percent\",\n minimumFractionDigits: 2,\n maximumFractionDigits: 2,\n }),\n [locale],\n );\n\n return useCallback(\n (value: number, options?: Intl.NumberFormatOptions) => {\n if (!options) {\n return defaultFormatter.format(value);\n }\n\n return new Intl.NumberFormat(locale, {\n style: \"percent\",\n ...options,\n }).format(value);\n },\n [defaultFormatter, locale],\n );\n}\n","import { useCallback } from \"react\";\n\nimport { useCountry } from \"../country/country-context\";\nimport {\n isValidBankAccount,\n isValidNationalId,\n isValidPhoneNumber,\n validateBankAccount,\n validateNationalId,\n validatePhoneNumber,\n type ValidationResult,\n} from \"../../validation\";\n\n/**\n * Returns a national-id validator bound to the active country (from\n * `CountryProvider`). The returned function reports a boolean; use\n * {@link useValidateNationalId}'s `.validate` for the normalized value.\n */\nexport function useValidateNationalId() {\n const { country } = useCountry();\n\n const isValid = useCallback(\n (value: string): boolean => isValidNationalId(country, value),\n [country],\n );\n\n const validate = useCallback(\n (value: string): ValidationResult => validateNationalId(country, value),\n [country],\n );\n\n return Object.assign(isValid, { validate });\n}\n\n/**\n * Returns a phone-number validator bound to the active country.\n */\nexport function useValidatePhoneNumber() {\n const { country } = useCountry();\n\n const isValid = useCallback(\n (value: string): boolean => isValidPhoneNumber(country, value),\n [country],\n );\n\n const validate = useCallback(\n (value: string): ValidationResult => validatePhoneNumber(country, value),\n [country],\n );\n\n return Object.assign(isValid, { validate });\n}\n\n/**\n * Returns a bank-account validator bound to the active country.\n */\nexport function useValidateBankAccount() {\n const { country } = useCountry();\n\n const isValid = useCallback(\n (value: string): boolean => isValidBankAccount(country, value),\n [country],\n );\n\n const validate = useCallback(\n (value: string): ValidationResult => validateBankAccount(country, value),\n [country],\n );\n\n return Object.assign(isValid, { validate });\n}\n","\"use client\";\n\nimport { CssBaseline, ThemeProvider } from \"@mui/material\";\nimport { type ReactNode } from \"react\";\nimport { LanguageContext } from \"../i18n/language-context\";\nimport { DEFAULT_LANGUAGE, type Language } from \"../i18n/languages\";\nimport { theme } from \"../theme\";\n\nexport type LeaProviderProps = {\n /** Language for the library's built-in translations and date locales. @default \"no\" */\n language?: Language;\n /** Skip rendering MUI's `CssBaseline` (e.g. if the host app renders its own). */\n disableCssBaseline?: boolean;\n children: ReactNode;\n};\n\n/**\n * The single provider for consuming the component library. Bundles the Lea Bank\n * MUI theme (so consumers never wire `ThemeProvider` / the theme themselves) and\n * the language context that drives `createTranslation` and locale-aware\n * components. Forward only the `language` prop.\n */\nexport function LeaProvider({\n language = DEFAULT_LANGUAGE,\n disableCssBaseline,\n children,\n}: LeaProviderProps) {\n return (\n <LanguageContext.Provider value={language}>\n <ThemeProvider theme={theme}>\n {!disableCssBaseline && <CssBaseline />}\n {children}\n </ThemeProvider>\n </LanguageContext.Provider>\n );\n}\n","export type FormatDecimals = { value: number; decimalPlaces?: number };\n\n/**\n\n * Formats a number to a fixed number of decimal places (default is 2)\n * by using exponential notation\n *\n * ⚠️ Note: We avoid using `toFixed` for rounding because it can introduce rounding errors.\n * \n * @param value - The number to format.\n * @param decimalPlaces - Number of decimal places to show (default: 2).\n * @returns The number with fixed decimal places.\n */\nexport const fixDecimals = ({ value, decimalPlaces = 2 }: FormatDecimals) => {\n return Number(\n Math.round(parseFloat(value + \"e\" + decimalPlaces)) + \"e-\" + decimalPlaces\n );\n};\n","import { fixDecimals, FormatDecimals } from \"./formatDecimal\";\n\n/**\n * Formats a number to a fixed number of decimal places (default is 2).\n *\n * Ensures that string representation of number always has the set number of decimals (even eg. .00)\n *\n * @param value - The number or string to format.\n * @param decimalPlaces - Number of decimal places to show (default: 2).\n * @returns A string representation of the number with fixed decimal places.\n */\nexport const fixDecimalsToString = ({\n value,\n decimalPlaces = 2,\n}: FormatDecimals) => {\n return fixDecimals({ value, decimalPlaces }).toFixed(decimalPlaces);\n};\nexport const formatDecimalString = ({\n value,\n decimalPlaces = 2,\n}: FormatDecimals): string => {\n return fixDecimals({ value, decimalPlaces }) % 1 === 0\n ? fixDecimalsToString({ value, decimalPlaces: 0 }).replace(\".\", \",\")\n : fixDecimalsToString({ value, decimalPlaces }).replace(\".\", \",\");\n};\n","import { formatDecimalString } from \"./formatDecimalString\";\n\nexport const formatPercentage = (value: number, decimalPlaces: number = 2) => {\n return formatDecimalString({ value, decimalPlaces }) + \"%\";\n};\n","export function parseExpirationDate(expirationDate: string): {\n month: string;\n year: string;\n} {\n const match = expirationDate.match(/^([0-9]{2})([0-9]{2})$/);\n if (!match) return { month: \"\", year: \"\" };\n return { month: match[1], year: match[2] };\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"component-library.es.js","names":[],"sources":["../src/components/animations/animations.module.css","../src/components/animations/shared.tsx","../src/components/animations/spinner.tsx","../src/i18n/languages.ts","../src/i18n/language-context.tsx","../src/i18n/create-translation.ts","../src/components/animations/use-animation-labels.ts","../src/components/animations/icons/status-icon.tsx","../src/theme/tokens/colors.ts","../src/theme/tokens/palette.ts","../src/components/animations/illustrations/check-animation.tsx","../src/components/animations/illustrations/pulse-animation.tsx","../src/components/animations/illustrations/status-animation.tsx","../src/utils/merge-class-name.ts","../src/components/buttons/action-button.module.css","../src/components/buttons/button.module.css","../src/components/buttons/button-base.tsx","../src/components/buttons/action-button.tsx","../src/components/buttons/button.tsx","../src/components/feedback/use-close-label.ts","../src/components/buttons/icon-button.tsx","../src/components/buttons/close-button.tsx","../src/utils/downloadFile.ts","../src/components/buttons/use-download-labels.ts","../src/components/buttons/download-trigger.tsx","../src/components/buttons/skip-link.module.css","../src/components/buttons/skip-link.tsx","../src/theme/tokens/font-sizes.ts","../src/components/typography/text.module.css","../src/components/typography/text.tsx","../src/components/data-display/data-field.module.css","../src/components/data-display/data-field.tsx","../src/components/data-display/card.module.css","../src/components/data-display/card.tsx","../src/components/data-display/chip.module.css","../src/components/data-display/use-chip-labels.ts","../src/components/data-display/chip.tsx","../src/components/data-display/tooltip.module.css","../src/components/data-display/tooltip.tsx","../src/components/feedback/alert.module.css","../src/components/feedback/alert-parts.tsx","../src/components/feedback/alert.tsx","../src/components/feedback/dialog.module.css","../src/components/feedback/dialog.tsx","../src/components/feedback/drawer.module.css","../src/components/feedback/drawer.tsx","../src/components/layout/container.module.css","../src/components/layout/container.tsx","../src/components/feedback/global-alert.tsx","../src/components/feedback/simple-dialog.tsx","../src/components/feedback/simple-drawer.tsx","../src/components/form/amount-slider.module.css","../src/components/form/slider-parts.module.css","../src/components/form/slider-parts.tsx","../src/components/form/amount-slider.tsx","../src/components/form/combo-field.module.css","../src/components/form/field-parts.module.css","../src/components/form/use-tooltip-trigger-labels.ts","../src/components/form/field-parts.tsx","../src/components/form/input.module.css","../src/components/form/option-list.module.css","../src/components/form/use-autocomplete-labels.ts","../src/components/form/use-blur-outside.ts","../src/components/form/combo-field.tsx","../src/components/form/autocomplete.tsx","../src/components/form/checkbox.module.css","../src/components/form/checkbox-box.tsx","../src/components/form/choice-row.module.css","../src/components/form/checkbox.tsx","../src/validation/types.ts","../src/validation/national-id.ts","../src/validation/mobile-patterns.ts","../src/validation/phone.ts","../src/validation/modulo-97.ts","../src/validation/bank-account.ts","../src/validation/reference-number.ts","../src/validation/email.ts","../src/components/typography/link.module.css","../src/components/typography/link.tsx","../src/components/typography/lists.module.css","../src/components/typography/lists.tsx","../src/components/form/email-input.module.css","../src/components/form/email-input.tsx","../src/components/form/input.tsx","../src/components/form/select.module.css","../src/components/form/select-field.tsx","../src/components/form/multi-select.tsx","../src/hooks/country/countries.ts","../src/components/form/number-input-unit.ts","../src/components/form/number-input.module.css","../src/components/form/number-input.tsx","../src/components/form/phone-number-input/countries.ts","../src/components/form/phone-number-input/phone-number-input.module.css","../src/components/form/phone-number-input/phone-number-input.tsx","../src/components/form/radio.module.css","../src/components/form/radio-circle.tsx","../src/components/form/radio-group-root.module.css","../src/components/form/radio-group-root.tsx","../src/components/form/radio.tsx","../src/components/form/radio-card.module.css","../src/components/form/radio-card.tsx","../src/components/form/select.tsx","../src/components/form/slider.module.css","../src/components/form/slider.tsx","../src/components/form/switch.module.css","../src/components/form/switch.tsx","../src/components/layout/grid.module.css","../src/components/layout/responsive.ts","../src/components/layout/grid.tsx","../src/components/layout/stack.module.css","../src/components/layout/stack.tsx","../src/components/navigation/form-stepper.module.css","../src/components/navigation/progress-circle.module.css","../src/components/navigation/progress-circle.tsx","../src/components/navigation/use-stepper-labels.ts","../src/components/navigation/form-stepper.tsx","../src/components/navigation/linear-form-stepper.module.css","../src/components/navigation/linear-form-stepper.tsx","../src/components/navigation/step-progress.tsx","../src/components/navigation/tabs.module.css","../src/components/navigation/tabs.tsx","../src/components/surfaces/accordion.module.css","../src/components/surfaces/accordion.tsx","../src/components/surfaces/simple-accordion.tsx","../src/components/ui/brand-divider.module.css","../src/components/ui/brand-divider.tsx","../src/components/ui/app-header.module.css","../src/components/ui/app-header.tsx","../src/hooks/country/country-context.tsx","../src/hooks/use-format-currency.ts","../src/hooks/use-format-date.ts","../src/hooks/use-format-number.ts","../src/hooks/validation/use-validation.ts","../src/provider/lea-provider.tsx","../src/theme/tokens/breakpoints.ts","../src/utils/formatDecimal.ts","../src/utils/formatDecimalString.ts","../src/utils/formatPercentage.ts","../src/utils/parseExpirationDate.ts"],"sourcesContent":[".StatusIcon,\n.Check,\n.Pulse {\n --animation-base: var(--lea-palette-primary-base);\n --animation-contrast: var(--lea-palette-primary-contrast);\n --animation-shadow: rgba(255, 255, 255, 0.1) 0 1px 1px 0 inset,\n rgba(50, 50, 93, 0.25) 0 30px 60px -20px,\n rgba(0, 0, 0, 0.25) 0 18px 36px -18px;\n}\n\n.StatusIcon[data-color=\"tertiary\"],\n.Check[data-color=\"tertiary\"] {\n --animation-base: var(--lea-palette-tertiary-base);\n --animation-contrast: var(--lea-palette-tertiary-contrast);\n}\n\n.Badge {\n display: flex;\n align-items: center;\n justify-content: center;\n border-radius: var(--lea-radius-full);\n background-color: var(--animation-base);\n color: var(--animation-contrast);\n}\n\n.Spinner {\n display: inline-block;\n animation: animation-spin 1.4s linear infinite;\n}\n\n.SpinnerSvg {\n display: block;\n}\n\n@keyframes animation-spin {\n to {\n transform: rotate(360deg);\n }\n}\n\n/* StatusIcon */\n\n.StatusIcon {\n position: relative;\n display: inline-flex;\n overflow: visible;\n flex-shrink: 0;\n align-items: center;\n justify-content: center;\n color: var(--animation-base);\n}\n\n.State {\n position: absolute;\n display: flex;\n align-items: center;\n justify-content: center;\n inset: 0;\n}\n\n.Ring {\n box-sizing: border-box;\n width: 100%;\n height: 100%;\n border-style: solid;\n border-color: var(--lea-palette-border-base);\n border-radius: var(--lea-radius-full);\n}\n\n/* CheckAnimation */\n\n.Check {\n position: relative;\n display: flex;\n overflow: visible;\n align-items: center;\n justify-content: center;\n}\n\n.Halo {\n position: absolute;\n border-radius: var(--lea-radius-full);\n animation: check-halo 2.6s var(--lea-easing-standard) infinite;\n background-color: var(--animation-base);\n opacity: 0.25;\n}\n\n.CheckBadge {\n animation: check-breathe 2.6s var(--lea-easing-standard) infinite;\n box-shadow: var(--animation-shadow);\n}\n\n@keyframes check-halo {\n 0%,\n 100% {\n opacity: 0.28;\n transform: scale(1);\n }\n\n 50% {\n opacity: 0;\n transform: scale(1.45);\n }\n}\n\n@keyframes check-breathe {\n 0%,\n 100% {\n transform: scale(1);\n }\n\n 50% {\n transform: scale(1.04);\n }\n}\n\n/* PulseAnimation */\n\n.Pulse {\n position: relative;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n\n.PulseRing,\n.PulseCentre {\n position: absolute;\n border-radius: var(--lea-radius-full);\n background-color: var(--animation-base);\n}\n\n.PulseRing {\n animation: pulse-ring 2s var(--lea-easing-standard) infinite;\n opacity: 0.5;\n}\n\n.PulseCentre {\n box-shadow: var(--animation-shadow);\n}\n\n/* Positioned, so it paints above the centre circle whether or not it turns. */\n.PulseSpinner {\n position: relative;\n color: var(--animation-contrast);\n}\n\n@keyframes pulse-ring {\n 0% {\n opacity: 0.6;\n transform: scale(0.4);\n }\n\n 100% {\n opacity: 0;\n transform: scale(1.6);\n }\n}\n\n/* StatusAnimation */\n\n.Status {\n position: relative;\n}\n\n.Layer {\n position: absolute;\n display: flex;\n align-items: center;\n justify-content: center;\n inset: 0;\n}\n\n.SrOnly {\n position: absolute;\n overflow: hidden;\n width: 1px;\n height: 1px;\n padding: 0;\n border: 0;\n margin: -1px;\n clip-path: inset(50%);\n white-space: nowrap;\n}\n\n@media (prefers-reduced-motion: reduce) {\n .Halo {\n animation: none;\n opacity: 0;\n }\n\n .CheckBadge,\n .PulseRing {\n animation: none;\n }\n}\n","import { Check } from \"lucide-react\";\nimport { motion } from \"motion/react\";\nimport { type ReactNode } from \"react\";\n\nimport type { ColorRoles } from \"../color-roles\";\nimport styles from \"./animations.module.css\";\n\nexport type AnimationSize = \"sm\" | \"lg\";\n\nexport type AnimationColor = ColorRoles<\"primary\" | \"tertiary\">;\n\nexport type ConfettiParticle = {\n id: number;\n x: number;\n y: number;\n dotSize: number;\n round: boolean;\n colour?: string;\n spin?: number;\n};\n\ntype BuildParticlesOptions = {\n count: number;\n burst: number;\n distanceAt: (index: number) => number;\n dotSizeAt: (index: number) => number;\n colourAt?: (index: number) => string | undefined;\n withSpin?: boolean;\n};\n\nexport const buildParticles = ({\n count,\n burst,\n distanceAt,\n dotSizeAt,\n colourAt,\n withSpin = false,\n}: BuildParticlesOptions): ConfettiParticle[] =>\n Array.from({ length: count }, (_, i) => {\n const angle = (i / count) * Math.PI * 2;\n const distance = burst * distanceAt(i);\n return {\n id: i,\n x: Math.cos(angle) * distance,\n y: Math.sin(angle) * distance,\n dotSize: dotSizeAt(i),\n round: i % 2 === 0,\n ...(colourAt ? { colour: colourAt(i) } : {}),\n ...(withSpin ? { spin: (i % 2 === 0 ? 1 : -1) * 120 } : {}),\n };\n });\n\ntype ConfettiParticlesProps = {\n particles: ConfettiParticle[];\n /** Illustration confetti drifts down slightly and spins. */\n variant?: \"illustration\" | \"icon\";\n delay?: number;\n duration?: number;\n /** When set, particles use currentColor instead of per-particle colours. */\n useCurrentColor?: boolean;\n};\n\nexport const ConfettiParticles = ({\n particles,\n variant = \"illustration\",\n delay = variant === \"illustration\" ? 0.18 : 0.1,\n duration = variant === \"illustration\" ? 1.1 : 0.8,\n useCurrentColor = variant === \"icon\",\n}: ConfettiParticlesProps) =>\n particles.map((p) => (\n <motion.span\n key={p.id}\n initial={{ x: 0, y: 0, scale: 0, opacity: 0 }}\n animate={\n variant === \"illustration\"\n ? {\n x: [0, p.x],\n y: [0, p.y, p.y + 10],\n scale: [0, 1, 0.7],\n opacity: [0, 1, 0],\n rotate: p.spin != null ? [0, p.spin] : undefined,\n }\n : {\n x: [0, p.x],\n y: [0, p.y],\n scale: [0, 1, 0.6],\n opacity: [0, 1, 0],\n }\n }\n transition={{\n duration,\n ease: \"easeOut\",\n times: variant === \"illustration\" ? [0, 0.25, 1] : [0, 0.3, 1],\n delay,\n }}\n style={{\n position: \"absolute\",\n width: p.dotSize,\n height: p.dotSize,\n borderRadius: p.round ? \"50%\" : 1,\n backgroundColor: useCurrentColor ? \"currentColor\" : p.colour,\n pointerEvents: \"none\",\n }}\n />\n ));\n\ntype AnimationBadgeProps = {\n /** Diameter in px. */\n size: number;\n iconSize: number;\n className?: string;\n children?: ReactNode;\n};\n\nexport const AnimationBadge = ({\n size,\n iconSize,\n className,\n children,\n}: AnimationBadgeProps) => (\n <span\n className={[styles.Badge, className].filter(Boolean).join(\" \")}\n style={{ width: size, height: size }}\n >\n {children ?? <Check size={iconSize} strokeWidth={3} aria-hidden />}\n </span>\n);\n","import styles from \"./animations.module.css\";\n\ntype SpinnerProps = {\n /** Diameter in px. */\n size: number;\n /** Stroke width, in the units of a 44px circle. */\n thickness?: number;\n /**\n * Accessible name. With one, the spinner is a `progressbar`; without, it is\n * hidden from assistive tech and its parent says what is loading.\n */\n label?: string;\n className?: string;\n};\n\nconst BOX = 44;\n\n/**\n * An indeterminate spinner: an arc in the current colour that turns at a\n * constant speed. Internal to the animations.\n */\nexport const Spinner = ({\n size,\n thickness = 3.6,\n label,\n className,\n}: SpinnerProps) => (\n <span\n {...(label != null\n ? { role: \"progressbar\", \"aria-label\": label }\n : { \"aria-hidden\": true })}\n className={[styles.Spinner, className].filter(Boolean).join(\" \")}\n style={{ width: size, height: size }}\n >\n <svg\n className={styles.SpinnerSvg}\n viewBox={`${BOX / 2} ${BOX / 2} ${BOX} ${BOX}`}\n >\n <circle\n cx={BOX}\n cy={BOX}\n r={(BOX - thickness) / 2}\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth={thickness}\n strokeDasharray=\"80 200\"\n />\n </svg>\n </span>\n);\n","/**\n * Languages supported by the component library's built-in translations. The\n * consumer selects one via `LeaProvider`'s `language` prop; components read it\n * with `useLanguage` (usually through `createTranslation`).\n */\nexport const LANGUAGES = [\"no\", \"se\", \"fi\", \"es\"] as const;\n\nexport type Language = (typeof LANGUAGES)[number];\n\n/** Fallback language used when no provider is present or a key is missing. */\nexport const DEFAULT_LANGUAGE = \"no\" satisfies Language;\n","\"use client\";\n\nimport { createContext, useContext } from \"react\";\nimport { DEFAULT_LANGUAGE, type Language } from \"./languages\";\n\n/**\n * Holds the currently selected language. Provided by `LeaProvider` and read by\n * components (typically via `createTranslation`). Defaults to `DEFAULT_LANGUAGE`\n * so components still render sensibly when used without the provider.\n */\nexport const LanguageContext = createContext<Language>(DEFAULT_LANGUAGE);\n\n/** Returns the language from the nearest `LeaProvider`, or `DEFAULT_LANGUAGE`. */\nexport const useLanguage = (): Language => useContext(LanguageContext);\n","\"use client\";\n\nimport { useLanguage } from \"./language-context\";\nimport { DEFAULT_LANGUAGE, type Language } from \"./languages\";\n\n/**\n * Translations for a single string, keyed by language. The `no` key is required\n * so the `DEFAULT_LANGUAGE` fallback always resolves; the others are optional.\n */\nexport type TranslationMap = { no: string } & Partial<Record<Language, string>>;\n\n/** A named set of translatable strings, each keyed by language. */\nexport type TranslationSchema = Record<string, TranslationMap>;\n\n/**\n * Creates a hook that returns co-located strings for the current language,\n * each falling back to `no`. Define the schema at module scope and call the\n * returned hook inside a component:\n *\n * ```tsx\n * const useLabels = createTranslation({\n * increase: { no: \"Øk\", se: \"Öka\", fi: \"Lisää\", es: \"Aumentar\" },\n * decrease: { no: \"Reduser\", se: \"Minska\", fi: \"Vähennä\", es: \"Disminuir\" },\n * });\n *\n * function Stepper() {\n * const t = useLabels();\n * return <button aria-label={t.increase} />;\n * }\n * ```\n */\nexport function createTranslation<T extends TranslationSchema>(schema: T) {\n return function useTranslation(): Record<keyof T, string> {\n const language = useLanguage();\n const result = {} as Record<keyof T, string>;\n (Object.keys(schema) as (keyof T)[]).forEach((key) => {\n const map = schema[key];\n result[key] = map[language] ?? map[DEFAULT_LANGUAGE];\n });\n return result;\n };\n}\n","import { createTranslation } from \"../../i18n\";\n\nexport const useAnimationLabels = createTranslation({\n pending: {\n no: \"Venter\",\n se: \"Väntar\",\n fi: \"Odottaa\",\n es: \"Esperando\",\n },\n loading: {\n no: \"Laster\",\n se: \"Laddar\",\n fi: \"Ladataan\",\n es: \"Cargando\",\n },\n done: { no: \"Ferdig\", se: \"Klart\", fi: \"Valmis\", es: \"Completado\" },\n confirmed: {\n no: \"Bekreftet\",\n se: \"Bekräftat\",\n fi: \"Vahvistettu\",\n es: \"Confirmado\",\n },\n});\n","\"use client\";\n\nimport { AnimatePresence, motion, useReducedMotion } from \"motion/react\";\nimport { useMemo } from \"react\";\n\nimport styles from \"../animations.module.css\";\nimport {\n AnimationBadge,\n type AnimationColor,\n buildParticles,\n ConfettiParticles,\n} from \"../shared\";\nimport { Spinner } from \"../spinner\";\nimport { useAnimationLabels } from \"../use-animation-labels\";\n\ntype StatusIconStatus = \"pending\" | \"loading\" | \"done\";\n\ntype StatusIconProps = {\n status: StatusIconStatus;\n /** Rendered size in px. */\n size?: number;\n /**\n * Colour of the spinner and of the filled check.\n * @default \"primary\"\n */\n color?: AnimationColor;\n /**\n * Accessible name; defaults to the translated label for the current status in\n * the `LeaProvider` language.\n */\n label?: string;\n};\n\nconst CONFETTI_COUNT = 8;\n\n/**\n * A small, inline status icon for step / progress lists. Transitions through\n * `pending` (empty ring) → `loading` (spinner) → `done` (filled check with a\n * one-time confetti pop). One-shot, not infinite. Respects\n * `prefers-reduced-motion`.\n */\nexport const StatusIcon = ({\n status,\n size = 24,\n color = \"primary\",\n label,\n}: StatusIconProps) => {\n const prefersReducedMotion = useReducedMotion();\n const labels = useAnimationLabels();\n\n const ring = Math.max(2, Math.round(size * 0.09));\n const thickness = (ring * 44) / size;\n const checkSize = Math.round(size * 0.6);\n const burst = size;\n\n const particles = useMemo(\n () =>\n buildParticles({\n count: CONFETTI_COUNT,\n burst,\n distanceAt: (i) => 0.7 + (i % 2) * 0.25,\n dotSizeAt: (i) => Math.max(2, Math.round(size * 0.1)) + (i % 2),\n }),\n [burst, size],\n );\n\n const fadeDuration = prefersReducedMotion ? 0 : 0.2;\n\n return (\n <span\n role=\"img\"\n aria-label={label ?? labels[status]}\n className={styles.StatusIcon}\n data-color={color}\n style={{ width: size, height: size }}\n >\n <AnimatePresence mode=\"wait\">\n {status === \"pending\" && (\n <motion.span\n key=\"pending\"\n initial={{ opacity: 0 }}\n animate={{ opacity: 1 }}\n exit={{ opacity: 0 }}\n transition={{ duration: fadeDuration }}\n className={styles.State}\n >\n <span className={styles.Ring} style={{ borderWidth: ring }} />\n </motion.span>\n )}\n\n {status === \"loading\" && (\n <motion.span\n key=\"loading\"\n initial={{ opacity: 0 }}\n animate={{ opacity: 1 }}\n exit={{ opacity: 0 }}\n transition={{ duration: fadeDuration }}\n className={styles.State}\n >\n <Spinner size={size} thickness={thickness} />\n </motion.span>\n )}\n\n {status === \"done\" && (\n <motion.span\n key=\"done\"\n initial={{ opacity: 0 }}\n animate={{ opacity: 1 }}\n exit={{ opacity: 0 }}\n transition={{ duration: fadeDuration }}\n className={styles.State}\n >\n <motion.span\n initial={prefersReducedMotion ? false : { scale: 0 }}\n animate={prefersReducedMotion ? {} : { scale: [0, 1.18, 1] }}\n transition={{\n duration: 0.4,\n ease: \"easeOut\",\n times: [0, 0.6, 1],\n }}\n style={{ display: \"flex\" }}\n >\n <AnimationBadge size={size} iconSize={checkSize} />\n </motion.span>\n </motion.span>\n )}\n </AnimatePresence>\n\n {!prefersReducedMotion && status === \"done\" && (\n <ConfettiParticles particles={particles} variant=\"icon\" />\n )}\n </span>\n );\n};\n","export const colors = {\n purple: {\n 50: \"#FAF7FB\",\n 100: \"#E2D8E4\",\n 200: \"#C5B1CA\",\n 300: \"#C29AC2\",\n 400: \"#9E6DA8\",\n 500: \"#855888\",\n 600: \"#70427B\",\n 700: \"#5A3463\",\n 800: \"#422349\",\n 900: \"#2E1834\",\n 950: \"#1A0E1E\",\n },\n teal: {\n 50: \"#F0FCFA\",\n 100: \"#DAF6F1\",\n 200: \"#CEF3ED\",\n 300: \"#08C2A7\",\n 400: \"#46D1BD\",\n 500: \"#06A892\",\n 600: \"#058F7D\",\n 700: \"#047568\",\n 800: \"#035C53\",\n 900: \"#02433E\",\n 950: \"#012A28\",\n },\n blue: {\n 50: \"#EFF6FF\",\n 100: \"#CBE5FD\",\n 200: \"#93CBFC\",\n 300: \"#4DA8F7\",\n 400: \"#057EF2\",\n 500: \"#0468C9\",\n 600: \"#0354A3\",\n 700: \"#02417D\",\n 800: \"#012E57\",\n 900: \"#011B31\",\n 950: \"#000E19\",\n },\n orange: {\n 50: \"#FFF5F2\",\n 100: \"#FFDFD7\",\n 200: \"#FFC4B5\",\n 300: \"#FF9E87\",\n 400: \"#FE653E\",\n 500: \"#E54E28\",\n 600: \"#C43E1C\",\n 700: \"#A33218\",\n 800: \"#822814\",\n 900: \"#611E0F\",\n 950: \"#401408\",\n },\n amber: {\n 50: \"#FFF9EB\",\n 100: \"#FFEFC7\",\n 200: \"#FFE299\",\n 300: \"#FFCF5C\",\n 400: \"#F7A800\",\n 500: \"#D98F00\",\n 600: \"#B37400\",\n 700: \"#8C5A00\",\n 800: \"#6B4500\",\n 900: \"#4A3000\",\n 950: \"#2E1D00\",\n },\n red: {\n 50: \"#FEF2F2\",\n 100: \"#FCDCDC\",\n 200: \"#F9BBBB\",\n 300: \"#F28888\",\n 400: \"#E85555\",\n 500: \"#D32F2F\",\n 600: \"#AD2121\",\n 700: \"#8A1919\",\n 800: \"#6F1313\",\n 900: \"#4D0E0E\",\n 950: \"#2E0808\",\n },\n beige: {\n 50: \"#FAF7F5\",\n 100: \"#F0E9E5\",\n 200: \"#E0D4CD\",\n 300: \"#C9B8AD\",\n 400: \"#B09A8C\",\n 500: \"#977C6B\",\n 600: \"#7E6556\",\n 700: \"#654F42\",\n 800: \"#4C3A32\",\n 900: \"#332722\",\n 950: \"#1A1411\",\n },\n neutral: {\n 50: \"#F7F7F6\",\n 100: \"#EBEBEB\",\n 200: \"#DBDBDB\",\n 300: \"#C4C4C4\",\n 400: \"#A2A2A2\",\n 500: \"#757575\",\n 600: \"#5E5E5E\",\n 700: \"#454545\",\n 800: \"#2E2E2E\",\n 900: \"#1A1A1A\",\n 950: \"#0F1010\",\n },\n white: \"#FFFFFF\",\n black: \"#0F1010\",\n} as const;\n","import { Palette } from \"../types\";\nimport { colors } from \"./colors\";\n\nconst { purple, teal, blue, amber, red, neutral, white, beige } = colors;\n\n/** A scale colour at an opacity, written `rgba(15, 16, 16, 0.5)`. */\nconst alpha = (hex: string, opacity: number) => {\n const [r, g, b] = [1, 3, 5].map((i) => parseInt(hex.slice(i, i + 2), 16));\n\n return `rgba(${r}, ${g}, ${b}, ${opacity})`;\n};\n\nexport const palette: Palette = {\n bg: {\n base: white,\n subtle: neutral[50],\n muted: beige[100],\n contrast: neutral[950],\n accent: purple[100],\n overlay: alpha(neutral[950], 0.5),\n },\n text: {\n base: neutral[950],\n subtle: neutral[500],\n muted: neutral[400],\n accent: purple[600],\n contrast: white,\n },\n border: {\n base: neutral[200],\n subtle: neutral[100],\n strong: neutral[950],\n accent: purple[600],\n contrast: white,\n },\n primary: {\n base: purple[600],\n hover: purple[700],\n subtle: purple[100],\n contrast: white,\n },\n secondary: {\n base: neutral[950],\n hover: neutral[800],\n subtle: neutral[100],\n contrast: white,\n },\n tertiary: {\n base: teal[300],\n hover: teal[400],\n subtle: teal[100],\n contrast: white,\n },\n status: {\n error: {\n base: red[500],\n subtle: red[100],\n },\n warning: {\n base: amber[400],\n subtle: amber[100],\n },\n info: {\n base: blue[400],\n subtle: blue[100],\n },\n success: {\n base: teal[400],\n subtle: teal[100],\n },\n },\n} as const;\n","\"use client\";\n\nimport { motion, useReducedMotion } from \"motion/react\";\nimport { useMemo } from \"react\";\n\nimport { colors } from \"../../../theme/tokens/colors\";\nimport { palette } from \"../../../theme/tokens/palette\";\nimport styles from \"../animations.module.css\";\nimport {\n AnimationBadge,\n type AnimationColor,\n type AnimationSize,\n buildParticles,\n ConfettiParticles,\n} from \"../shared\";\nimport { useAnimationLabels } from \"../use-animation-labels\";\n\ntype CheckAnimationProps = {\n /**\n * `\"sm\"` is 90px, `\"lg\"` 150px.\n * @default \"lg\"\n */\n size?: AnimationSize;\n /**\n * Colour of the badge and its halo.\n * @default \"primary\"\n */\n color?: AnimationColor;\n /**\n * Accessible name for the illustration; defaults to the translated word for\n * \"confirmed\" in the `LeaProvider` language.\n */\n label?: string;\n};\n\n// Shared square footprint with PulseAnimation: `box` is the rendered square and\n// `badge` matches the pulse centre circle, so both animations line up at a given\n// size. The confetti is free to overflow the square.\nconst sizeMap = {\n sm: { box: 90, badge: 60, icon: 30, burst: 60 },\n lg: { box: 150, badge: 100, icon: 50, burst: 100 },\n};\n\nconst CONFETTI_COUNT = 14;\n\n// The four brand colours. Blue and orange have no semantic token of their own;\n// confetti is not a status, so it does not read `status.info` or\n// `status.warning`.\nconst confettiColours = [\n palette.primary.base,\n palette.tertiary.base,\n colors.blue[400],\n colors.orange[400],\n];\n\nexport const CheckAnimation = ({\n size = \"lg\",\n color = \"primary\",\n label,\n}: CheckAnimationProps) => {\n const prefersReducedMotion = useReducedMotion();\n const labels = useAnimationLabels();\n const { box, badge, icon, burst } = sizeMap[size];\n\n const particles = useMemo(\n () =>\n buildParticles({\n count: CONFETTI_COUNT,\n burst,\n distanceAt: (i) => 0.6 + (i % 3) * 0.15,\n dotSizeAt: (i) => 5 + (i % 3) * 2,\n colourAt: (i) => confettiColours[i % confettiColours.length],\n withSpin: true,\n }),\n [burst],\n );\n\n return (\n <div\n role=\"img\"\n aria-label={label ?? labels.confirmed}\n className={styles.Check}\n data-color={color}\n style={{ width: box, height: box }}\n >\n <span className={styles.Halo} style={{ width: badge, height: badge }} />\n\n {!prefersReducedMotion && (\n <ConfettiParticles particles={particles} variant=\"illustration\" />\n )}\n\n <motion.div\n initial={prefersReducedMotion ? false : { scale: 0, rotate: -25 }}\n animate={\n prefersReducedMotion ? {} : { scale: [0, 1.12, 1], rotate: [-25, 0] }\n }\n transition={{\n duration: 0.55,\n ease: \"easeOut\",\n times: [0, 0.65, 1],\n }}\n style={{ display: \"flex\" }}\n >\n <AnimationBadge\n size={badge}\n iconSize={icon}\n className={styles.CheckBadge}\n />\n </motion.div>\n </div>\n );\n};\n","\"use client\";\n\nimport styles from \"../animations.module.css\";\nimport { type AnimationSize } from \"../shared\";\nimport { Spinner } from \"../spinner\";\nimport { useAnimationLabels } from \"../use-animation-labels\";\n\ntype PulseAnimationProps = {\n /**\n * `\"sm\"` is 90px, `\"lg\"` 150px.\n * @default \"lg\"\n */\n size?: AnimationSize;\n /**\n * Accessible name for the spinner; defaults to the translated word for\n * \"loading\" in the `LeaProvider` language. `StatusAnimation` hides the pulse\n * from assistive tech and announces its own status text instead.\n */\n label?: string;\n};\n\n// Ratios are kept constant across variants so the pulse expands the same\n// amount relative to the centre circle, and the spinner stays proportional.\nconst sizeMap = {\n sm: { container: 90, circle: 60, spinner: 28 },\n lg: { container: 150, circle: 100, spinner: 48 },\n};\n\nexport const PulseAnimation = ({ size = \"lg\", label }: PulseAnimationProps) => {\n const { container, circle, spinner } = sizeMap[size];\n const labels = useAnimationLabels();\n\n const circleSize = { width: circle, height: circle };\n\n return (\n <div\n className={styles.Pulse}\n style={{ width: container, height: container }}\n >\n <span className={styles.PulseRing} style={circleSize} />\n <span\n className={styles.PulseRing}\n style={{ ...circleSize, animationDelay: \"0.4s\" }}\n />\n <span className={styles.PulseCentre} style={circleSize} />\n <Spinner\n size={spinner}\n label={label ?? labels.loading}\n className={styles.PulseSpinner}\n />\n </div>\n );\n};\n","\"use client\";\n\nimport { AnimatePresence, motion, useReducedMotion } from \"motion/react\";\nimport { useEffect, useRef, useState } from \"react\";\n\nimport styles from \"../animations.module.css\";\nimport { type AnimationColor, type AnimationSize } from \"../shared\";\nimport { useAnimationLabels } from \"../use-animation-labels\";\nimport { CheckAnimation } from \"./check-animation\";\nimport { PulseAnimation } from \"./pulse-animation\";\n\ntype StatusAnimationProps = {\n /** While `true`, shows the pulse; when it flips to `false`, transitions to the check. */\n loading: boolean;\n /**\n * `\"sm\"` is 90px, `\"lg\"` 150px.\n * @default \"lg\"\n */\n size?: AnimationSize;\n /**\n * Colour of the resulting check (and its halo).\n * @default \"primary\"\n */\n color?: AnimationColor;\n /**\n * Minimum time (ms) the pulse stays visible once mounted in the loading\n * state, so a very fast response doesn't make the spinner flash. The check\n * appears as soon as `loading` is `false` *and* this minimum has elapsed.\n */\n minLoadingMs?: number;\n /**\n * Visually-hidden status text announced while loading. Defaults to the\n * translated word for \"loading\" in the `LeaProvider` language.\n */\n loadingLabel?: string;\n /**\n * Visually-hidden status text announced once done. Defaults to the translated\n * word for \"done\".\n */\n doneLabel?: string;\n};\n\nconst boxSize = { sm: 90, lg: 150 };\n\n/**\n * A controlled loading → success indicator: shows {@link PulseAnimation} while\n * `loading`, then cross-fades into {@link CheckAnimation} (firing its one-time\n * confetti) once `loading` becomes `false`. Announces state changes politely\n * and respects `prefers-reduced-motion`.\n */\nexport const StatusAnimation = ({\n loading,\n size = \"lg\",\n color = \"primary\",\n minLoadingMs = 0,\n loadingLabel,\n doneLabel,\n}: StatusAnimationProps) => {\n const prefersReducedMotion = useReducedMotion();\n const labels = useAnimationLabels();\n const [done, setDone] = useState(!loading);\n const loadingStart = useRef<number | null>(loading ? Date.now() : null);\n\n useEffect(() => {\n if (loading) {\n loadingStart.current = Date.now();\n setDone(false);\n return;\n }\n\n const elapsed =\n loadingStart.current != null\n ? Date.now() - loadingStart.current\n : minLoadingMs;\n const remaining = Math.max(0, minLoadingMs - elapsed);\n\n if (remaining === 0) {\n setDone(true);\n return;\n }\n\n const timer = window.setTimeout(() => setDone(true), remaining);\n return () => window.clearTimeout(timer);\n }, [loading, minLoadingMs]);\n\n const side = boxSize[size];\n const duration = prefersReducedMotion ? 0 : 0.35;\n\n return (\n <div\n role=\"status\"\n aria-live=\"polite\"\n className={styles.Status}\n style={{ width: side, height: side }}\n >\n <AnimatePresence mode=\"sync\">\n {done ? (\n <motion.div\n key=\"check\"\n aria-hidden\n initial={{ opacity: 0 }}\n animate={{ opacity: 1 }}\n exit={{ opacity: 0 }}\n transition={{ duration }}\n className={styles.Layer}\n >\n <CheckAnimation size={size} color={color} />\n </motion.div>\n ) : (\n <motion.div\n key=\"pulse\"\n aria-hidden\n initial={{ opacity: 0 }}\n animate={{ opacity: 1 }}\n exit={{ opacity: 0 }}\n transition={{ duration }}\n className={styles.Layer}\n >\n <PulseAnimation size={size} />\n </motion.div>\n )}\n </AnimatePresence>\n <span className={styles.SrOnly}>\n {done ? (doneLabel ?? labels.done) : (loadingLabel ?? labels.loading)}\n </span>\n </div>\n );\n};\n","type ClassNameProp<State> =\n | string\n | ((state: State) => string | undefined)\n | undefined;\n\n/**\n * Base UI replaces `className` wholesale, which would drop the module class of\n * a wrapper component. Returning a callback keeps the state argument working\n * for consumers who pass a function.\n *\n * Internal helper — not part of the public API, so it isn't re-exported from\n * `src/utils/index.ts`.\n */\nexport const mergeClassName =\n <State,>(base: string, className: ClassNameProp<State>) =>\n (state: State) =>\n [base, typeof className === \"function\" ? className(state) : className]\n .filter(Boolean)\n .join(\" \");\n",".ActionButton {\n display: inline-flex;\n min-width: calc(var(--lea-spacing) * 8);\n box-sizing: border-box;\n align-items: center;\n justify-content: center;\n padding-block: var(--lea-spacing-0-5);\n padding-inline: calc(var(--lea-spacing) * 3.5) var(--lea-spacing-0-5);\n border: 0;\n border-radius: var(--lea-radius-full);\n background-color: var(--lea-palette-bg-base);\n box-shadow: 0 0 0 1px var(--lea-palette-border-strong);\n color: var(--lea-palette-text-base);\n cursor: pointer;\n font-family: inherit;\n font-size: var(--lea-font-step-2);\n font-weight: var(--lea-font-weight-bold);\n line-height: var(--lea-line-height-tight);\n text-decoration: none;\n text-transform: uppercase;\n user-select: none;\n -webkit-tap-highlight-color: transparent;\n}\n\n.ActionButton:focus-visible {\n outline: 2px solid var(--lea-palette-text-base);\n outline-offset: 0.125rem;\n}\n\n.ActionButton:active:not([data-disabled]) {\n box-shadow: 0 0 0 2px var(--lea-palette-primary-base);\n}\n\n.ActionButton[data-disabled] {\n background-color: var(--lea-palette-bg-subtle);\n color: var(--lea-palette-text-subtle);\n cursor: not-allowed;\n}\n\n.Arrow {\n display: block;\n width: var(--lea-spacing-6);\n height: var(--lea-spacing-6);\n flex-shrink: 0;\n border-radius: var(--lea-radius-full);\n margin-inline-start: var(--lea-spacing-3);\n background-color: var(--lea-palette-bg-contrast);\n color: var(--lea-palette-text-contrast);\n transition: transform var(--lea-duration-emphasis) var(--lea-easing-spring),\n background-color var(--lea-duration-normal) var(--lea-easing-standard);\n}\n\n@media (hover: hover) {\n .ActionButton:hover:not([data-disabled]) .Arrow {\n background-color: var(--lea-palette-primary-base);\n transform: rotate(-45deg) scale(1.08);\n }\n}\n\n@media (prefers-reduced-motion: reduce) {\n .Arrow {\n transition-duration: 0.01ms;\n }\n}\n",".Button {\n --button-solid: var(--lea-palette-primary-base);\n --button-solid-hover: var(--lea-palette-primary-hover);\n --button-on-solid: var(--lea-palette-primary-contrast);\n --button-fg: var(--lea-palette-primary-base);\n --button-border: var(--lea-palette-primary-base);\n --button-tint: color-mix(\n in srgb,\n var(--button-fg) calc(var(--lea-opacity-hover) * 100%),\n color-mix(\n in srgb,\n var(--lea-color-white) calc(var(--lea-opacity-highlight) * 100%),\n transparent\n )\n );\n\n --button-height: 2.75rem;\n --button-icon-size: 1.25rem;\n --button-padding-inline: calc(var(--lea-spacing) * 2.5);\n\n box-sizing: border-box;\n display: inline-flex;\n min-height: var(--button-height);\n flex-shrink: 0;\n align-items: center;\n justify-content: center;\n gap: var(--lea-spacing);\n padding-block: calc(var(--lea-spacing) * 0.5);\n padding-inline: var(--button-padding-inline);\n margin: 0;\n border: 1px solid transparent;\n border-radius: var(--lea-radius-full);\n background-color: transparent;\n color: var(--button-fg);\n font-family: inherit;\n font-size: var(--lea-text-label-lg-font-size);\n font-weight: var(--lea-text-label-lg-font-weight);\n line-height: var(--lea-text-label-lg-line-height);\n letter-spacing: var(--lea-text-label-lg-letter-spacing);\n text-align: center;\n text-decoration: none;\n cursor: pointer;\n user-select: none;\n -webkit-tap-highlight-color: transparent;\n transition: background-color var(--lea-duration-normal)\n var(--lea-easing-standard),\n border-color var(--lea-duration-normal) var(--lea-easing-standard),\n color var(--lea-duration-normal) var(--lea-easing-standard),\n opacity var(--lea-duration-normal) var(--lea-easing-standard);\n}\n\n.Button svg {\n width: var(--button-icon-size);\n height: var(--button-icon-size);\n flex-shrink: 0;\n}\n\n.Button:focus-visible {\n outline: 2px solid var(--lea-palette-text-base);\n outline-offset: 0.125rem;\n}\n\n/* Colours */\n\n.Button[data-color=\"secondary\"] {\n --button-solid: var(--lea-palette-secondary-base);\n --button-solid-hover: var(--lea-palette-secondary-hover);\n --button-on-solid: var(--lea-palette-secondary-contrast);\n --button-fg: var(--lea-palette-secondary-base);\n --button-border: var(--lea-palette-secondary-base);\n}\n\n.Button[data-color=\"error\"] {\n --button-solid: var(--lea-color-red-600);\n --button-solid-hover: var(--lea-color-red-500);\n --button-on-solid: var(--lea-palette-text-contrast);\n --button-fg: var(--lea-color-red-600);\n --button-border: var(--lea-color-red-600);\n}\n\n/* Variants */\n\n.Button[data-variant=\"solid\"] {\n background-color: var(--button-solid);\n color: var(--button-on-solid);\n}\n\n.Button[data-variant=\"outline\"] {\n border-color: var(--button-border);\n}\n\n@media (hover: hover) {\n .Button[data-variant=\"solid\"]:not([data-disabled]):hover {\n background-color: var(--button-solid-hover);\n }\n\n .Button[data-variant=\"outline\"]:not([data-disabled]):hover,\n .Button[data-variant=\"ghost\"]:not([data-disabled]):hover {\n background-color: var(--button-tint);\n }\n}\n\n/* Sizes */\n\n.Button[data-size=\"sm\"] {\n --button-height: 2.25rem;\n --button-icon-size: 1rem;\n --button-padding-inline: calc(var(--lea-spacing) * 2);\n}\n\n.Button[data-size=\"lg\"] {\n --button-height: 3.25rem;\n --button-icon-size: 1.5rem;\n --button-padding-inline: calc(var(--lea-spacing) * 2.5);\n}\n\n.Button[data-start-icon] {\n padding-inline-start: calc(var(--button-padding-inline) - var(--lea-spacing));\n}\n\n.Button[data-end-icon] {\n padding-inline-end: calc(var(--button-padding-inline) - var(--lea-spacing));\n}\n\n.Button.IconButton {\n width: var(--button-height);\n height: var(--button-height);\n padding: 0;\n}\n\n.Button[data-disabled]:not([data-loading]) {\n color: var(--lea-color-neutral-400);\n cursor: not-allowed;\n}\n\n.Button[data-variant=\"solid\"][data-disabled]:not([data-loading]) {\n background-color: var(--lea-color-neutral-200);\n color: var(--lea-color-neutral-600);\n}\n\n.Button[data-variant=\"outline\"][data-disabled]:not([data-loading]) {\n border-color: var(--lea-palette-border-base);\n}\n\n.Button[data-loading] {\n cursor: progress;\n opacity: 0.7;\n}\n\n.Spinner {\n box-sizing: border-box;\n display: inline-block;\n width: var(--button-icon-size);\n height: var(--button-icon-size);\n flex-shrink: 0;\n border: 2px solid currentColor;\n border-inline-end-color: transparent;\n border-radius: var(--lea-radius-full);\n animation: button-spin 0.8s linear infinite;\n}\n\n@keyframes button-spin {\n to {\n rotate: 360deg;\n }\n}\n\n.SrOnly {\n position: absolute;\n width: 1px;\n height: 1px;\n padding: 0;\n margin: -1px;\n overflow: hidden;\n clip-path: inset(50%);\n white-space: nowrap;\n border: 0;\n}\n\n@media (prefers-reduced-motion: reduce) {\n .Button {\n transition-duration: 0.01ms;\n }\n\n .Spinner {\n animation: none;\n }\n}\n","\"use client\";\n\nimport { Button as BaseButton } from \"@base-ui/react/button\";\nimport { useRender } from \"@base-ui/react/use-render\";\nimport {\n isValidElement,\n type MouseEvent,\n type ReactElement,\n type Ref,\n} from \"react\";\n\nimport { mergeClassName } from \"../../utils/merge-class-name\";\nimport type { ColorRoles } from \"../color-roles\";\nimport styles from \"./button.module.css\";\n\nexport type ButtonVariant = \"solid\" | \"outline\" | \"ghost\";\nexport type ButtonColor = ColorRoles<\"primary\" | \"secondary\" | \"error\">;\nexport type ButtonSize = \"sm\" | \"md\" | \"lg\";\n\nexport type ButtonRootProps = Omit<BaseButton.Props, \"color\" | \"ref\"> & {\n /**\n * Shows the busy state: the button is disabled, keeps its colour at reduced\n * opacity and sets `aria-busy`.\n * @default false\n */\n loading?: boolean;\n /** The rendered element: the `<button>`, or the link passed to `render`. */\n ref?: Ref<HTMLElement>;\n};\n\nexport type ButtonBaseProps = ButtonRootProps & {\n /**\n * Visual weight.\n * - `\"solid\"` — filled, for the main action.\n * - `\"outline\"` — bordered, no fill.\n * - `\"ghost\"` — no border or fill until hovered.\n * @default \"solid\"\n */\n variant?: ButtonVariant;\n /**\n * Colour scheme: `\"primary\"` is the brand purple, `\"secondary\"` the\n * near-black, `\"error\"` is for destructive actions.\n * @default \"primary\"\n */\n color?: ButtonColor;\n /**\n * @default \"md\"\n */\n size?: ButtonSize;\n};\n\n/**\n * A `render` element carrying `href` (an `<a>`, Next.js `Link`) or `to`\n * (React Router `Link`) is a link. Base UI's `Button` would give it\n * `role=\"button\"`, so links are rendered without button semantics.\n */\nconst isLinkElement = (\n render: ButtonRootProps[\"render\"],\n): render is ReactElement<{ href?: unknown; to?: unknown }> =>\n isValidElement<{ href?: unknown; to?: unknown }>(render) &&\n (render.props.href != null || render.props.to != null);\n\nconst preventDefault = (event: MouseEvent) => event.preventDefault();\n\n/**\n * A button, or the link passed to `render`, with the disabled and busy states\n * wired. It has no look of its own: the class comes from the caller. Internal\n * — not exported from the package.\n */\nexport function ButtonRoot({\n loading = false,\n disabled,\n className,\n render,\n nativeButton,\n focusableWhenDisabled,\n ref,\n ...rest\n}: ButtonRootProps) {\n const isDisabled = Boolean(disabled || loading);\n const isLink = isLinkElement(render);\n\n const shared = {\n \"aria-busy\": loading || undefined,\n \"data-loading\": loading || undefined,\n };\n\n const link = useRender({\n enabled: isLink,\n render: isLink ? render : undefined,\n ref,\n defaultTagName: \"a\",\n props: {\n ...rest,\n ...shared,\n \"aria-disabled\": isDisabled || undefined,\n \"data-disabled\": isDisabled ? \"\" : undefined,\n className:\n typeof className === \"function\"\n ? className({ disabled: isDisabled })\n : className,\n onClick: isDisabled ? preventDefault : rest.onClick,\n },\n });\n\n if (link) return link;\n\n return (\n <BaseButton\n {...rest}\n {...shared}\n ref={ref}\n render={render}\n nativeButton={nativeButton}\n focusableWhenDisabled={focusableWhenDisabled}\n disabled={isDisabled}\n className={className}\n />\n );\n}\n\n/**\n * The root shared by `Button`, `IconButton`, `CloseButton` and\n * `DownloadTrigger`: `ButtonRoot` with the button look. Internal — not\n * exported from the package.\n */\nexport function ButtonBase({\n variant = \"solid\",\n color = \"primary\",\n size = \"md\",\n className,\n ...rest\n}: ButtonBaseProps) {\n return (\n <ButtonRoot\n {...rest}\n data-variant={variant}\n data-color={color}\n data-size={size}\n className={mergeClassName(styles.Button, className)}\n />\n );\n}\n","\"use client\";\n\nimport { ArrowRight } from \"lucide-react\";\n\nimport { mergeClassName } from \"../../utils/merge-class-name\";\nimport styles from \"./action-button.module.css\";\nimport { ButtonRoot, type ButtonRootProps } from \"./button-base\";\n\nexport type ActionButtonProps = Omit<ButtonRootProps, \"loading\">;\n\n/**\n * A pill-shaped call-to-action button with a built-in arrow icon.\n *\n * Used for primary navigation actions on the website, such as hero sections\n * and landing pages. To render a link, pass it through `render`; an element\n * with `href` or `to` is rendered as a real link, without button semantics:\n *\n * ```tsx\n * <ActionButton render={<a href=\"/lan\" />}>Se våra lån</ActionButton>\n * <ActionButton render={<NextLink href=\"/lan\" />}>Se våra lån</ActionButton>\n * <ActionButton render={<RouterLink to=\"/lan\" />}>Se våra lån</ActionButton>\n * ```\n */\nexport function ActionButton({\n children,\n className,\n ...rest\n}: ActionButtonProps) {\n return (\n <ButtonRoot\n {...rest}\n className={mergeClassName(styles.ActionButton, className)}\n >\n {children}\n <ArrowRight aria-hidden className={styles.Arrow} />\n </ButtonRoot>\n );\n}\n","\"use client\";\n\nimport type { ReactNode } from \"react\";\n\nimport { ButtonBase, type ButtonBaseProps } from \"./button-base\";\nimport styles from \"./button.module.css\";\n\nexport type {\n ButtonColor,\n ButtonSize,\n ButtonVariant,\n} from \"./button-base\";\n\nexport type ButtonProps = ButtonBaseProps & {\n /** Icon before the label. Replaced by the spinner while `loading`. */\n startIcon?: ReactNode;\n /** Icon after the label. */\n endIcon?: ReactNode;\n /**\n * Text announced to screen readers while `loading`, through a\n * visually-hidden `role=\"status\"` region, e.g. \"Saving…\".\n */\n loadingLabel?: string;\n};\n\n/**\n * A button built on Base UI's `Button` primitive and styled with Lea's design\n * tokens. Pick a `variant` (`solid`, `outline`, `ghost`), a `color`\n * (`primary`, `secondary`, `error`) and a `size` (`sm`, `md`, `lg`).\n *\n * ```tsx\n * <Button variant=\"outline\" startIcon={<Plus aria-hidden />}>Add</Button>\n * ```\n *\n * To render a link that looks like a button, pass the link through `render`.\n * An element with `href` or `to` is rendered as a real link, without button\n * semantics:\n *\n * ```tsx\n * <Button render={<a href=\"/about\" />}>About</Button>\n * <Button render={<NextLink href=\"/about\" />}>About</Button>\n * <Button render={<RouterLink to=\"/about\" />}>About</Button>\n * ```\n *\n * For a link inside running text, use `Link` instead.\n */\nexport function Button({\n startIcon,\n endIcon,\n loading = false,\n loadingLabel,\n children,\n ...rest\n}: ButtonProps) {\n return (\n <>\n <ButtonBase\n {...rest}\n loading={loading}\n data-start-icon={loading || startIcon != null || undefined}\n data-end-icon={endIcon != null || undefined}\n >\n {loading ? <span className={styles.Spinner} aria-hidden /> : startIcon}\n {children}\n {endIcon}\n </ButtonBase>\n {loadingLabel != null && (\n <span role=\"status\" className={styles.SrOnly}>\n {loading ? loadingLabel : null}\n </span>\n )}\n </>\n );\n}\n","import { createTranslation } from \"../../i18n\";\n\n/**\n * Translated accessible name for the close (X) button shared by the feedback\n * overlays (`SimpleDialog`, `SimpleDrawer`). Consumers can override per-instance\n * via a `closeLabel` prop.\n */\nexport const useCloseLabel = createTranslation({\n close: {\n no: \"Lukk\",\n se: \"Stäng\",\n fi: \"Sulje\",\n es: \"Cerrar\",\n },\n});\n","\"use client\";\n\nimport type { ReactNode } from \"react\";\n\nimport { mergeClassName } from \"../../utils/merge-class-name\";\nimport { ButtonBase, type ButtonBaseProps } from \"./button-base\";\nimport styles from \"./button.module.css\";\n\n/**\n * Requires an accessible name so the button is never nameless. Provide exactly\n * one of `aria-label` or `aria-labelledby`.\n */\ntype IconButtonAccessibleName =\n | { \"aria-label\": string; \"aria-labelledby\"?: never }\n | { \"aria-labelledby\": string; \"aria-label\"?: never };\n\nexport type IconButtonProps = Omit<\n ButtonBaseProps,\n \"children\" | \"aria-label\" | \"aria-labelledby\"\n> &\n IconButtonAccessibleName & {\n /** The icon. Mark it `aria-hidden` — the name comes from `aria-label`. */\n children: ReactNode;\n };\n\n/**\n * A square, icon-only button with the same variants, colours and sizes as\n * `Button`. Because it has no visible text, TypeScript requires an\n * `aria-label` or `aria-labelledby`.\n *\n * ```tsx\n * <IconButton aria-label=\"Add\" variant=\"outline\">\n * <Plus aria-hidden />\n * </IconButton>\n * ```\n */\nexport function IconButton({\n loading = false,\n className,\n children,\n ...rest\n}: IconButtonProps) {\n return (\n <ButtonBase\n {...rest}\n loading={loading}\n className={mergeClassName(styles.IconButton, className)}\n >\n {loading ? <span className={styles.Spinner} aria-hidden /> : children}\n </ButtonBase>\n );\n}\n","\"use client\";\n\nimport { X } from \"lucide-react\";\n\nimport { useCloseLabel } from \"../feedback/use-close-label\";\nimport type { ButtonBaseProps } from \"./button-base\";\nimport { IconButton } from \"./icon-button\";\n\nexport type CloseButtonProps = Omit<\n ButtonBaseProps,\n \"children\" | \"aria-label\" | \"aria-labelledby\"\n> & {\n /** Accessible name. Defaults to a translated \"Close\". */\n label?: string;\n};\n\n/**\n * An `IconButton` with a built-in X icon. It always has an accessible name —\n * a translated \"Close\" unless you pass `label`.\n *\n * ```tsx\n * <CloseButton onClick={() => setOpen(false)} />\n * ```\n */\nexport function CloseButton({\n label,\n variant = \"ghost\",\n color = \"secondary\",\n ...rest\n}: CloseButtonProps) {\n const t = useCloseLabel();\n\n return (\n <IconButton\n {...rest}\n variant={variant}\n color={color}\n aria-label={label ?? t.close}\n >\n <X aria-hidden />\n </IconButton>\n );\n}\n","export type DownloadableData =\n | string\n | Blob\n | File\n | ArrayBuffer\n | Uint8Array;\n\nexport type DownloadDataSource =\n | DownloadableData\n | (() => DownloadableData | Promise<DownloadableData>);\n\nexport async function resolveDownloadData(\n data: DownloadDataSource,\n): Promise<DownloadableData> {\n return typeof data === \"function\" ? data() : data;\n}\n\nexport function downloadFile(\n data: DownloadableData,\n fileName: string,\n mimeType?: string,\n): void {\n const blob =\n data instanceof Blob\n ? data\n : new Blob([data as BlobPart], mimeType ? { type: mimeType } : undefined);\n\n const url = URL.createObjectURL(blob);\n const anchor = document.createElement(\"a\");\n anchor.href = url;\n anchor.download = fileName;\n anchor.rel = \"noopener\";\n anchor.click();\n URL.revokeObjectURL(url);\n}\n","import { createTranslation } from \"../../i18n\";\n\n/**\n * Translated default copy for `DownloadTrigger`. Consumers can override it by\n * passing `children`.\n */\nexport const useDownloadLabels = createTranslation({\n download: {\n no: \"Last ned\",\n se: \"Ladda ner\",\n fi: \"Lataa\",\n es: \"Descargar\",\n },\n});\n","\"use client\";\n\nimport {\n downloadFile,\n resolveDownloadData,\n type DownloadDataSource,\n} from \"@/utils/downloadFile\";\nimport { useState } from \"react\";\n\nimport { Button, type ButtonProps } from \"./button\";\nimport { useDownloadLabels } from \"./use-download-labels\";\n\ntype DownloadTriggerProps = Omit<ButtonProps, \"onClick\"> & {\n /** File contents, or a function/promise that resolves to them. */\n data: DownloadDataSource;\n /** File name. */\n fileName: string;\n /** MIME type. */\n mimeType?: string;\n /** Callback for when the download starts. */\n onDownload?: () => void;\n /** Callback for when the download fails. */\n onDownloadError?: (error: unknown) => void;\n};\n\n/**\n * A button that triggers a download of a file. Shares `Button`'s variants,\n * colours and sizes, and shows the loading state while `data` resolves.\n *\n * Without `children` the label is the translated word for \"download\" in the\n * `LeaProvider` language.\n */\n\nexport const DownloadTrigger = ({\n data,\n fileName,\n mimeType,\n onDownload,\n onDownloadError,\n loading: loadingProp,\n children,\n ...rest\n}: DownloadTriggerProps) => {\n const labels = useDownloadLabels();\n const [pending, setPending] = useState(false);\n const loading = loadingProp ?? pending;\n\n const handleClick = async () => {\n setPending(true);\n try {\n const resolved = await resolveDownloadData(data);\n downloadFile(resolved, fileName, mimeType);\n onDownload?.();\n } catch (error) {\n onDownloadError?.(error);\n } finally {\n setPending(false);\n }\n };\n\n return (\n <Button {...rest} loading={loading} onClick={handleClick}>\n {children ?? labels.download}\n </Button>\n );\n};\n",".SkipLink {\n position: absolute;\n z-index: 1000;\n inset-block-start: var(--lea-spacing-1);\n inset-inline-start: var(--lea-spacing-1);\n}\n\n.SkipLink:not(:focus) {\n clip-path: inset(50%);\n pointer-events: none;\n}\n","\"use client\";\n\nimport type { ReactNode } from \"react\";\n\nimport { mergeClassName } from \"../../utils/merge-class-name\";\nimport { ButtonBase, type ButtonBaseProps } from \"./button-base\";\nimport styles from \"./skip-link.module.css\";\n\nexport type SkipLinkProps = Pick<ButtonBaseProps, \"className\" | \"style\"> & {\n /** The id of the main content, as a fragment: `#main`. */\n href: string;\n children: ReactNode;\n};\n\n/**\n * A link for keyboard users to jump past the header to the main content. It\n * stays hidden until it receives focus, so place it first in the page and it\n * is the first thing the Tab key reaches:\n *\n * ```tsx\n * <body>\n * <SkipLink href=\"#main\">Hopp til hovedinnhold</SkipLink>\n * <AppHeader />\n * <main id=\"main\" tabIndex={-1}>…</main>\n * </body>\n * ```\n *\n * It is positioned against the page, so no ancestor should be positioned.\n */\nexport function SkipLink({ href, children, className, style }: SkipLinkProps) {\n return (\n <ButtonBase\n render={<a href={href} />}\n color=\"secondary\"\n className={mergeClassName(styles.SkipLink, className)}\n style={style}\n >\n {children}\n </ButtonBase>\n );\n}\n","/**\n * The first font-size scale, from before the text styles.\n *\n * @deprecated Use a text style (`textStyles`, `--lea-text-{role}-{size}-*`,\n * `text-heading-lg`) or, for a size on its own, a step on the type scale\n * (`fontStep`, `--lea-font-step-{n}`). Kept for the components that still use\n * it, and removed in a later major.\n */\nexport const fontSizes = {\n xs: \"0.75rem\",\n sm: \"0.875rem\",\n md: \"1rem\",\n lg: \"1.25rem\",\n xl: \"1.5rem\",\n \"2xl\": \"2rem\",\n \"3xl\": \"2.5rem\",\n \"4xl\": \"3rem\",\n \"5xl\": \"3.5rem\",\n \"6xl\": \"4rem\",\n} as const;\n","/*\n * Design tokens come from src/theme/tokens.css, generated from src/theme/tokens\n * by `pnpm tokens:css`. It is a plain stylesheet rather than runtime-injected\n * CSS variables, so this component renders correctly without a provider.\n */\n\n/* Without a `textStyle`, text is `body-md`. Every Text sets all four\n properties itself, so one nested in another does not take its parent's. */\n.Text {\n margin: 0;\n color: var(--lea-palette-text-base);\n font-size: var(--lea-text-body-md-font-size);\n font-weight: var(--lea-text-body-md-font-weight);\n line-height: var(--lea-text-body-md-line-height);\n letter-spacing: var(--lea-text-body-md-letter-spacing);\n}\n\n/* One rule per text style. tests/tokens.test.ts checks the list against\n src/theme/tokens/text-styles.ts. */\n.Text[data-text-style=\"display-sm\"] {\n font-size: var(--lea-text-display-sm-font-size);\n font-weight: var(--lea-text-display-sm-font-weight);\n line-height: var(--lea-text-display-sm-line-height);\n letter-spacing: var(--lea-text-display-sm-letter-spacing);\n}\n\n.Text[data-text-style=\"display-md\"] {\n font-size: var(--lea-text-display-md-font-size);\n font-weight: var(--lea-text-display-md-font-weight);\n line-height: var(--lea-text-display-md-line-height);\n letter-spacing: var(--lea-text-display-md-letter-spacing);\n}\n\n.Text[data-text-style=\"heading-xs\"] {\n font-size: var(--lea-text-heading-xs-font-size);\n font-weight: var(--lea-text-heading-xs-font-weight);\n line-height: var(--lea-text-heading-xs-line-height);\n letter-spacing: var(--lea-text-heading-xs-letter-spacing);\n}\n\n.Text[data-text-style=\"heading-sm\"] {\n font-size: var(--lea-text-heading-sm-font-size);\n font-weight: var(--lea-text-heading-sm-font-weight);\n line-height: var(--lea-text-heading-sm-line-height);\n letter-spacing: var(--lea-text-heading-sm-letter-spacing);\n}\n\n.Text[data-text-style=\"heading-md\"] {\n font-size: var(--lea-text-heading-md-font-size);\n font-weight: var(--lea-text-heading-md-font-weight);\n line-height: var(--lea-text-heading-md-line-height);\n letter-spacing: var(--lea-text-heading-md-letter-spacing);\n}\n\n.Text[data-text-style=\"heading-lg\"] {\n font-size: var(--lea-text-heading-lg-font-size);\n font-weight: var(--lea-text-heading-lg-font-weight);\n line-height: var(--lea-text-heading-lg-line-height);\n letter-spacing: var(--lea-text-heading-lg-letter-spacing);\n}\n\n.Text[data-text-style=\"heading-xl\"] {\n font-size: var(--lea-text-heading-xl-font-size);\n font-weight: var(--lea-text-heading-xl-font-weight);\n line-height: var(--lea-text-heading-xl-line-height);\n letter-spacing: var(--lea-text-heading-xl-letter-spacing);\n}\n\n.Text[data-text-style=\"body-xs\"] {\n font-size: var(--lea-text-body-xs-font-size);\n font-weight: var(--lea-text-body-xs-font-weight);\n line-height: var(--lea-text-body-xs-line-height);\n letter-spacing: var(--lea-text-body-xs-letter-spacing);\n}\n\n.Text[data-text-style=\"body-sm\"] {\n font-size: var(--lea-text-body-sm-font-size);\n font-weight: var(--lea-text-body-sm-font-weight);\n line-height: var(--lea-text-body-sm-line-height);\n letter-spacing: var(--lea-text-body-sm-letter-spacing);\n}\n\n.Text[data-text-style=\"body-md\"] {\n font-size: var(--lea-text-body-md-font-size);\n font-weight: var(--lea-text-body-md-font-weight);\n line-height: var(--lea-text-body-md-line-height);\n letter-spacing: var(--lea-text-body-md-letter-spacing);\n}\n\n.Text[data-text-style=\"body-lg\"] {\n font-size: var(--lea-text-body-lg-font-size);\n font-weight: var(--lea-text-body-lg-font-weight);\n line-height: var(--lea-text-body-lg-line-height);\n letter-spacing: var(--lea-text-body-lg-letter-spacing);\n}\n\n.Text[data-text-style=\"label-sm\"] {\n font-size: var(--lea-text-label-sm-font-size);\n font-weight: var(--lea-text-label-sm-font-weight);\n line-height: var(--lea-text-label-sm-line-height);\n letter-spacing: var(--lea-text-label-sm-letter-spacing);\n}\n\n.Text[data-text-style=\"label-md\"] {\n font-size: var(--lea-text-label-md-font-size);\n font-weight: var(--lea-text-label-md-font-weight);\n line-height: var(--lea-text-label-md-line-height);\n letter-spacing: var(--lea-text-label-md-letter-spacing);\n}\n\n.Text[data-text-style=\"label-lg\"] {\n font-size: var(--lea-text-label-lg-font-size);\n font-weight: var(--lea-text-label-lg-font-weight);\n line-height: var(--lea-text-label-lg-line-height);\n letter-spacing: var(--lea-text-label-lg-letter-spacing);\n}\n\n/* After the text styles, so a `fontWeight` wins over the style's own. */\n.Text[data-font-weight=\"thin\"] {\n font-weight: var(--lea-font-weight-thin);\n}\n\n.Text[data-font-weight=\"light\"] {\n font-weight: var(--lea-font-weight-light);\n}\n\n.Text[data-font-weight=\"regular\"] {\n font-weight: var(--lea-font-weight-regular);\n}\n\n.Text[data-font-weight=\"medium\"] {\n font-weight: var(--lea-font-weight-medium);\n}\n\n.Text[data-font-weight=\"semibold\"] {\n font-weight: var(--lea-font-weight-semibold);\n}\n\n.Text[data-font-weight=\"bold\"] {\n font-weight: var(--lea-font-weight-bold);\n}\n\n.Text[data-font-weight=\"black\"] {\n font-weight: var(--lea-font-weight-black);\n}\n\n.Text[data-color=\"inherit\"] {\n color: inherit;\n}\n\n.Text[data-align=\"start\"] {\n text-align: start;\n}\n\n.Text[data-align=\"center\"] {\n text-align: center;\n}\n\n.Text[data-align=\"end\"] {\n text-align: end;\n}\n","\"use client\";\n\nimport { useRender } from \"@base-ui/react/use-render\";\nimport type { Ref } from \"react\";\n\nimport type { ColorPath } from \"../../theme/token-types\";\nimport { fontSizes } from \"../../theme/tokens/font-sizes\";\nimport type { fontWeights } from \"../../theme/tokens/font-weights\";\nimport type { TextStyleToken } from \"../../theme/tokens/text-styles\";\nimport { mergeClassName } from \"../../utils/merge-class-name\";\nimport styles from \"./text.module.css\";\n\ntype FontSizeToken = keyof typeof fontSizes;\ntype FontWeightToken = keyof typeof fontWeights;\n\n/** A palette token such as `text.subtle`, or `inherit` for the parent's colour. */\nexport type TextColor = ColorPath | \"inherit\";\nexport type TextAlign = \"start\" | \"center\" | \"end\";\n\nexport type TextProps = Omit<useRender.ComponentProps<\"p\">, \"ref\" | \"color\"> & {\n /**\n * A text style such as `heading-lg` or `body-sm`: size, weight, line height\n * and letter spacing as one token. It says how the text looks, not which\n * element it is, so pick the element with `render` from the page hierarchy.\n * @default \"body-md\"\n */\n textStyle?: TextStyleToken;\n /** A font weight token, when the text style's own weight does not fit. */\n fontWeight?: FontWeightToken;\n /**\n * A colour token from the palette, written as its path. Use `inherit` to\n * take the colour of the surrounding text.\n * @default \"text.base\"\n */\n color?: TextColor;\n /** Text alignment, following the reading direction. */\n align?: TextAlign;\n /**\n * @deprecated Use `textStyle`. The `fontSize` scale (`xs` to `6xl`) is from\n * before the text styles and is removed in a later major.\n */\n fontSize?: FontSizeToken;\n /** The rendered element: the `<p>`, or the element passed to `render`. */\n ref?: Ref<HTMLElement>;\n};\n\nconst paletteVariable = (path: ColorPath) =>\n `var(--lea-palette-${path.replaceAll(\".\", \"-\")})`;\n\n/**\n * Text set in one of Lea's text styles. Renders a `p` with no margin; pass\n * `render` for another element:\n *\n * ```tsx\n * <Text>Vi svarer innen to virkedager.</Text>\n * <Text render={<h1 />} textStyle=\"heading-lg\">Mine lån</Text>\n * <Text render={<span />} textStyle=\"body-sm\" color=\"text.subtle\">\n * Sist oppdatert i dag\n * </Text>\n * ```\n *\n * Spacing around the text belongs to the layout: use `Stack` and its `gap`, or\n * `className` and `style`.\n */\nexport function Text({\n textStyle,\n fontWeight,\n color,\n align,\n fontSize,\n render,\n ref,\n className,\n style,\n ...rest\n}: TextProps) {\n return useRender({\n render,\n ref,\n defaultTagName: \"p\",\n props: {\n ...rest,\n \"data-text-style\": textStyle,\n \"data-font-weight\": fontWeight,\n \"data-align\": align,\n \"data-color\": color === \"inherit\" ? color : undefined,\n className: mergeClassName(styles.Text, className)({}),\n style: {\n ...(color != null && color !== \"inherit\"\n ? { color: paletteVariable(color) }\n : undefined),\n ...(fontSize != null ? { fontSize: fontSizes[fontSize] } : undefined),\n ...style,\n },\n },\n });\n}\n",".DataField {\n box-sizing: border-box;\n display: flex;\n width: 100%;\n align-items: center;\n justify-content: space-between;\n gap: var(--lea-spacing-2);\n padding-block: calc(var(--lea-spacing) * 1.75);\n padding-inline: var(--lea-spacing-1);\n}\n\n.DataField[data-divider] {\n border-block-end: 1px solid var(--lea-palette-border-base);\n}\n\n.Label {\n min-width: 0;\n flex: 1;\n}\n\n.Value {\n min-width: 0;\n text-align: end;\n}\n","import type { ComponentProps, ReactNode } from \"react\";\n\nimport { Text } from \"../typography/text\";\nimport styles from \"./data-field.module.css\";\n\nexport type DataFieldProps = Omit<ComponentProps<\"div\">, \"children\"> & {\n label: ReactNode;\n value: ReactNode;\n /**\n * Draws a line under the row, for stacking several into a summary.\n * @default true\n */\n divider?: boolean;\n};\n\nconst isText = (content: ReactNode) =>\n typeof content === \"string\" || typeof content === \"number\";\n\n/**\n * A single label/value row for presenting read-only details, with an optional\n * bottom divider so several fields can be stacked into a summary list.\n *\n * ```tsx\n * <DataField label=\"Lånebeløp\" value=\"150 000 kr\" />\n * <DataField label=\"Månedsbeløp\" value=\"1 316 kr\" divider={false} />\n * ```\n *\n * Text passed as `label` or `value` is set in the label and value styles. Any\n * other element is rendered as it is, for a side that needs richer content.\n */\nexport const DataField = ({\n label,\n value,\n divider = true,\n className,\n ...rest\n}: DataFieldProps) => (\n <div\n {...rest}\n className={[styles.DataField, className].filter(Boolean).join(\" \")}\n data-divider={divider || undefined}\n >\n <div className={styles.Label}>\n {isText(label) ? (\n <Text render={<span />} color=\"text.subtle\">\n {label}\n </Text>\n ) : (\n label\n )}\n </div>\n <div className={styles.Value}>\n {isText(value) ? (\n <Text render={<span />} fontWeight=\"medium\">\n {value}\n </Text>\n ) : (\n value\n )}\n </div>\n </div>\n);\n","/*\n * `--card-tint` is the fill and `--card-line` the border of the `outlined`\n * variant. The colours read the same values as `Chip`.\n */\n.Card {\n --card-tint: var(--lea-palette-bg-base);\n --card-line: var(--lea-palette-border-base);\n\n box-sizing: border-box;\n overflow: hidden;\n border: 1px solid var(--card-line);\n border-radius: var(--lea-radius-4xl);\n background-color: var(--card-tint);\n color: var(--lea-palette-text-base);\n}\n\n/* The border stays, transparent, so both variants take the same room. */\n.Card[data-variant=\"filled\"] {\n border-color: transparent;\n}\n\n.Card[data-color=\"primary\"] {\n --card-tint: var(--lea-palette-primary-subtle);\n --card-line: var(--lea-color-purple-600);\n}\n\n.Card[data-color=\"tertiary\"] {\n --card-tint: var(--lea-palette-tertiary-subtle);\n --card-line: var(--lea-color-teal-700);\n}\n\n.Card[data-color=\"neutral\"] {\n --card-tint: var(--lea-color-neutral-100);\n --card-line: var(--lea-color-neutral-400);\n}\n\n.Card[data-color=\"success\"] {\n --card-tint: var(--lea-palette-status-success-subtle);\n --card-line: var(--lea-color-teal-700);\n}\n\n.Card[data-color=\"info\"] {\n --card-tint: var(--lea-palette-status-info-subtle);\n --card-line: var(--lea-color-blue-600);\n}\n\n.Card[data-color=\"warning\"] {\n --card-tint: var(--lea-palette-status-warning-subtle);\n --card-line: var(--lea-color-amber-700);\n}\n\n.Card[data-color=\"error\"] {\n --card-tint: var(--lea-palette-status-error-subtle);\n --card-line: var(--lea-color-red-600);\n}\n\n.Content {\n box-sizing: border-box;\n padding: var(--lea-spacing-2);\n}\n","\"use client\";\n\nimport { useRender } from \"@base-ui/react/use-render\";\nimport type { Ref } from \"react\";\n\nimport { mergeClassName } from \"../../utils/merge-class-name\";\nimport type { ColorRoles } from \"../color-roles\";\nimport styles from \"./card.module.css\";\n\nexport type CardColor = ColorRoles<\n \"primary\" | \"tertiary\" | \"neutral\" | \"success\" | \"info\" | \"warning\" | \"error\"\n>;\nexport type CardVariant = \"outlined\" | \"filled\";\n\nexport type CardProps = Omit<\n useRender.ComponentProps<\"div\">,\n \"ref\" | \"color\"\n> & {\n /** The rendered element: the `<div>`, or the element passed to `render`. */\n ref?: Ref<HTMLElement>;\n /**\n * A tint for the card. Left out, the card is white.\n * - A brand tint: `\"primary\"` (purple), `\"tertiary\"` (teal) or `\"neutral\"`\n * (grey).\n * - A status: `\"success\"` (teal), `\"info\"` (blue), `\"warning\"` (amber) or\n * `\"error\"` (red).\n */\n color?: CardColor;\n /**\n * With a 1px border, or without one. The card keeps its size either way, so\n * the two line up in a row.\n * @default \"outlined\"\n */\n variant?: CardVariant;\n};\n\n/**\n * A flat surface that groups related content: white, with a 1px border and\n * rounded corners. It has no padding of its own, so an image or a divider can\n * run edge to edge; put text in `CardContent`.\n *\n * Set `color` for a tint, and `variant=\"filled\"` to drop the border:\n *\n * ```tsx\n * <Card color=\"primary\" variant=\"filled\">…</Card>\n * ```\n *\n * ```tsx\n * <Card>\n * <CardContent>\n * <Text textStyle=\"heading-sm\">Forbrukslån</Text>\n * <Text color=\"text.subtle\">150 000 kr over 10 år</Text>\n * </CardContent>\n * </Card>\n * ```\n *\n * Renders a `div`; pass `render` for another element, e.g.\n * `render={<section />}` or `render={<li />}`.\n */\nexport function Card({\n render,\n ref,\n className,\n color,\n variant = \"outlined\",\n ...rest\n}: CardProps) {\n return useRender({\n render,\n ref,\n props: {\n ...rest,\n \"data-color\": color,\n \"data-variant\": variant,\n className: mergeClassName(styles.Card, className)({}),\n },\n });\n}\n\nexport type CardContentProps = Omit<useRender.ComponentProps<\"div\">, \"ref\"> & {\n /** The rendered element: the `<div>`, or the element passed to `render`. */\n ref?: Ref<HTMLElement>;\n};\n\n/**\n * The padded area of a `Card`. A card can hold several, separated by whatever\n * sits between them.\n */\nexport function CardContent({\n render,\n ref,\n className,\n ...rest\n}: CardContentProps) {\n return useRender({\n render,\n ref,\n props: {\n ...rest,\n className: mergeClassName(styles.Content, className)({}),\n },\n });\n}\n",".Chip {\n --chip-tint: var(--lea-palette-primary-subtle);\n --chip-shade: var(--lea-color-purple-800);\n --chip-line: var(--lea-color-purple-600);\n --chip-ink: var(--lea-color-purple-600);\n --chip-outlined-disc: var(--chip-ink);\n --chip-outlined-cross: var(--chip-tint);\n\n --chip-edge: calc(var(--lea-spacing) * 0.75);\n --chip-gap: calc(var(--lea-spacing) * 0.75);\n --chip-label-edge: calc(var(--lea-spacing) * 1.75);\n --chip-padding-block: calc(var(--lea-spacing) * 0.25);\n --chip-delete-size: 1.25rem;\n\n display: inline-flex;\n max-width: 100%;\n box-sizing: border-box;\n align-items: center;\n padding-block: var(--chip-padding-block);\n border: 1px solid transparent;\n border-radius: var(--lea-radius-full);\n background-color: var(--chip-tint);\n color: var(--chip-shade);\n font-size: var(--lea-text-label-md-font-size);\n font-weight: var(--lea-text-label-md-font-weight);\n gap: var(--chip-gap);\n letter-spacing: var(--lea-text-label-md-letter-spacing);\n line-height: var(--lea-line-height-normal);\n vertical-align: middle;\n white-space: nowrap;\n}\n\n.Chip[data-size=\"sm\"] {\n --chip-edge: var(--lea-spacing-0-5);\n --chip-gap: var(--lea-spacing-0-5);\n --chip-label-edge: var(--lea-spacing-1);\n --chip-padding-block: 0px;\n --chip-delete-size: 1.125rem;\n}\n\n.Chip[data-color=\"tertiary\"] {\n --chip-tint: var(--lea-palette-tertiary-subtle);\n --chip-shade: var(--lea-color-teal-800);\n --chip-line: var(--lea-color-teal-700);\n --chip-ink: var(--lea-color-teal-700);\n}\n\n.Chip[data-color=\"neutral\"] {\n --chip-tint: var(--lea-color-neutral-100);\n --chip-shade: var(--lea-color-neutral-800);\n --chip-line: var(--lea-color-neutral-400);\n --chip-ink: var(--lea-color-neutral-700);\n}\n\n.Chip[data-color=\"success\"] {\n --chip-tint: var(--lea-palette-status-success-subtle);\n --chip-shade: var(--lea-color-teal-800);\n --chip-line: var(--lea-color-teal-700);\n --chip-ink: var(--lea-color-teal-700);\n}\n\n.Chip[data-color=\"info\"] {\n --chip-tint: var(--lea-palette-status-info-subtle);\n --chip-shade: var(--lea-color-blue-800);\n --chip-line: var(--lea-color-blue-600);\n --chip-ink: var(--lea-color-blue-600);\n --chip-outlined-disc: var(--lea-color-white);\n --chip-outlined-cross: var(--lea-color-blue-600);\n}\n\n.Chip[data-color=\"warning\"] {\n --chip-tint: var(--lea-palette-status-warning-subtle);\n --chip-shade: var(--lea-color-amber-800);\n --chip-line: var(--lea-color-amber-700);\n --chip-ink: var(--lea-color-amber-700);\n}\n\n.Chip[data-color=\"error\"] {\n --chip-tint: var(--lea-palette-status-error-subtle);\n --chip-shade: var(--lea-color-red-800);\n --chip-line: var(--lea-color-red-600);\n --chip-ink: var(--lea-color-red-600);\n}\n\n.Chip[data-variant=\"outlined\"] {\n border-color: var(--chip-line);\n background-color: transparent;\n color: var(--chip-ink);\n}\n\n.Chip[data-disabled] {\n opacity: 0.38;\n}\n\n.Chip:focus-visible {\n outline: 2px solid var(--lea-palette-text-base);\n outline-offset: 0.125rem;\n}\n\n.Label {\n overflow: hidden;\n min-width: 0;\n padding-inline: var(--chip-label-edge);\n text-overflow: ellipsis;\n}\n\n.Icon + .Label {\n padding-inline-start: 0;\n}\n\n.Label:has(+ .Delete) {\n padding-inline-end: 0;\n}\n\n.Icon {\n display: inline-flex;\n flex-shrink: 0;\n margin-inline-start: var(--chip-edge);\n}\n\n.Icon svg {\n display: block;\n}\n\n.Delete {\n display: inline-flex;\n width: var(--chip-delete-size);\n height: var(--chip-delete-size);\n flex-shrink: 0;\n align-items: center;\n justify-content: center;\n padding: 0;\n border: 0;\n border-radius: var(--lea-radius-full);\n margin-inline-end: var(--chip-edge);\n background: none;\n color: var(--chip-shade);\n cursor: pointer;\n transition: opacity var(--lea-duration-normal) var(--lea-easing-standard);\n}\n\n.Delete svg {\n display: block;\n width: 100%;\n height: 100%;\n fill: var(--chip-tint);\n scale: calc(24 / 22);\n}\n\n.Chip[data-variant=\"outlined\"] .Delete {\n color: var(--chip-outlined-cross);\n}\n\n.Chip[data-variant=\"outlined\"] .Delete svg {\n fill: var(--chip-outlined-disc);\n}\n\n.Delete:disabled {\n cursor: not-allowed;\n}\n\n.Delete:focus-visible {\n outline: 2px solid var(--lea-palette-text-base);\n outline-offset: 0.125rem;\n}\n\n@media (hover: hover) {\n .Delete:hover:not(:disabled) {\n opacity: 0.85;\n }\n}\n\n@media (prefers-reduced-motion: reduce) {\n .Delete {\n transition-duration: 0.01ms;\n }\n}\n","import { createTranslation } from \"../../i18n\";\n\n/**\n * Translated accessible name for `Chip`'s delete affordance, which MUI renders\n * as an unlabelled icon. Consumers can override it by passing their own\n * `deleteIcon`.\n */\nexport const useChipLabels = createTranslation({\n remove: { no: \"Fjern\", se: \"Ta bort\", fi: \"Poista\", es: \"Eliminar\" },\n});\n","\"use client\";\n\nimport { CircleX } from \"lucide-react\";\nimport type { ComponentProps, MouseEvent, ReactNode } from \"react\";\n\nimport type { ColorRoles } from \"../color-roles\";\nimport styles from \"./chip.module.css\";\nimport { useChipLabels } from \"./use-chip-labels\";\n\nexport type ChipColor = ColorRoles<\n \"primary\" | \"tertiary\" | \"neutral\" | \"success\" | \"info\" | \"warning\" | \"error\"\n>;\nexport type ChipVariant = \"filled\" | \"outlined\";\nexport type ChipSize = \"sm\" | \"md\";\n\nexport type ChipProps = Omit<ComponentProps<\"span\">, \"children\" | \"color\"> & {\n /** The text of the chip. */\n label: ReactNode;\n /**\n * What the chip stands for.\n * - A tag without a status: `\"primary\"` (purple), `\"tertiary\"` (teal) or\n * `\"neutral\"` (grey).\n * - A status: `\"success\"` (teal), `\"info\"` (blue), `\"warning\"` (amber) or\n * `\"error\"` (red).\n * @default \"primary\"\n */\n color?: ChipColor;\n /**\n * Tinted fill, or a border on a transparent background.\n * @default \"filled\"\n */\n variant?: ChipVariant;\n /**\n * @default \"md\"\n */\n size?: ChipSize;\n /** Icon before the label. Mark a decorative icon `aria-hidden`. */\n icon?: ReactNode;\n /**\n * Shows a remove button after the label and is called when it is pressed.\n * The button is named in the `LeaProvider` language and includes the label,\n * so a row of chips reads unambiguously: \"Fjern Medlånetaker\".\n */\n onDelete?: (event: MouseEvent<HTMLButtonElement>) => void;\n /** Accessible name of the remove button, when the default does not fit. */\n deleteLabel?: string;\n /** Dims the chip and disables its remove button. */\n disabled?: boolean;\n};\n\n/**\n * A compact label for tags, statuses, or filter selections.\n *\n * ```tsx\n * <Chip label=\"Medlånetaker\" />\n * <Chip label=\"Verifisert\" color=\"success\" icon={<CircleCheck size={16} aria-hidden />} />\n * <Chip label=\"Oslo\" variant=\"outlined\" onDelete={() => remove(\"oslo\")} />\n * ```\n *\n * The chip itself is not interactive; only its remove button is. Inside a\n * widget that moves focus itself, `tabIndex={-1}` takes the chip and its\n * remove button out of the tab order.\n */\nexport function Chip({\n label,\n color = \"primary\",\n variant = \"filled\",\n size = \"md\",\n icon,\n onDelete,\n deleteLabel,\n disabled = false,\n className,\n tabIndex,\n ...rest\n}: ChipProps) {\n const labels = useChipLabels();\n\n const deleteName =\n deleteLabel ??\n (typeof label === \"string\" ? `${labels.remove} ${label}` : labels.remove);\n\n return (\n <span\n {...rest}\n tabIndex={tabIndex}\n className={[styles.Chip, className].filter(Boolean).join(\" \")}\n data-color={color}\n data-variant={variant}\n data-size={size}\n data-disabled={disabled ? \"\" : undefined}\n >\n {icon != null && <span className={styles.Icon}>{icon}</span>}\n <span className={styles.Label}>{label}</span>\n {onDelete && (\n <button\n type=\"button\"\n aria-label={deleteName}\n className={styles.Delete}\n disabled={disabled}\n tabIndex={tabIndex === -1 ? -1 : undefined}\n onClick={onDelete}\n >\n <CircleX aria-hidden />\n </button>\n )}\n </span>\n );\n}\n",".Positioner {\n z-index: 1500;\n}\n\n.Popup {\n --tooltip-bg: var(--lea-palette-bg-base);\n --tooltip-fg: var(--lea-palette-text-base);\n\n box-sizing: border-box;\n max-width: 18.75rem;\n padding: var(--lea-spacing-1);\n border-radius: var(--lea-radius-sm);\n background-color: var(--tooltip-bg);\n box-shadow: var(--lea-shadow-md);\n color: var(--tooltip-fg);\n font-size: var(--lea-text-body-sm-font-size);\n font-weight: var(--lea-text-body-sm-font-weight);\n letter-spacing: var(--lea-text-body-sm-letter-spacing);\n line-height: var(--lea-text-body-sm-line-height);\n outline: none;\n overflow-wrap: break-word;\n transform-origin: var(--transform-origin);\n transition: opacity var(--lea-duration-fast) var(--lea-easing-standard),\n scale var(--lea-duration-fast) var(--lea-easing-standard);\n}\n\n.Popup[data-surface=\"dark\"] {\n --tooltip-bg: var(--lea-palette-bg-contrast);\n --tooltip-fg: var(--lea-palette-text-contrast);\n}\n\n.Popup[data-starting-style],\n.Popup[data-ending-style] {\n opacity: 0;\n scale: 0.95;\n}\n\n/* A square turned on its corner, half of it behind the edge of the bubble. */\n.Arrow {\n width: 0.625rem;\n height: 0.625rem;\n background-color: var(--tooltip-bg);\n rotate: 45deg;\n}\n\n.Arrow[data-side=\"top\"] {\n bottom: -0.3125rem;\n}\n\n.Arrow[data-side=\"bottom\"] {\n top: -0.3125rem;\n}\n\n.Arrow[data-side=\"left\"] {\n right: -0.3125rem;\n}\n\n.Arrow[data-side=\"right\"] {\n left: -0.3125rem;\n}\n\n/* The built-in trigger */\n\n.TriggerBox {\n display: inline-flex;\n}\n\n/*\n * A 44px target around a 16px icon. The negative margin gives the extra\n * 14px on each side back, so the button takes the room of the icon alone and\n * lines up with the text next to it.\n */\n.Trigger {\n display: inline-flex;\n width: calc(var(--lea-spacing) * 5.5);\n height: calc(var(--lea-spacing) * 5.5);\n box-sizing: border-box;\n flex-shrink: 0;\n align-items: center;\n justify-content: center;\n padding: 0;\n border: 0;\n border-radius: var(--lea-radius-full);\n margin: calc(var(--lea-spacing) * -1.75);\n background-color: transparent;\n color: var(--lea-palette-primary-base);\n cursor: pointer;\n line-height: 0;\n transition: color var(--lea-duration-fast) var(--lea-easing-standard);\n}\n\n.Trigger[data-variant=\"filled\"] {\n color: var(--lea-palette-primary-contrast);\n}\n\n.Trigger[data-variant=\"outlined\"] {\n color: var(--lea-palette-text-base);\n}\n\n.Trigger:focus-visible {\n outline: 2px solid var(--lea-palette-text-base);\n outline-offset: 0.125rem;\n}\n\n@media (hover: hover) {\n .Trigger:hover {\n color: var(--lea-palette-primary-hover);\n }\n\n .Trigger[data-variant=\"filled\"]:hover {\n color: var(--lea-palette-primary-contrast);\n }\n\n .Trigger[data-variant=\"outlined\"]:hover {\n color: var(--lea-palette-primary-base);\n }\n\n .Trigger[data-variant=\"filled\"]:hover .Mark {\n background-color: var(--lea-palette-primary-hover);\n }\n}\n\n/* The default icon: an \"i\" in a circle, drawn from two bars. */\n.Mark {\n position: relative;\n display: inline-flex;\n width: var(--lea-spacing-2);\n height: var(--lea-spacing-2);\n box-sizing: border-box;\n flex-shrink: 0;\n border: 1px solid var(--lea-palette-primary-base);\n border-radius: var(--lea-radius-full);\n color: var(--lea-palette-primary-base);\n transition: background-color var(--lea-duration-fast)\n var(--lea-easing-standard);\n}\n\n.Mark::before,\n.Mark::after {\n position: absolute;\n width: calc(var(--lea-spacing) * 0.25);\n border-radius: var(--lea-radius-full);\n background-color: currentColor;\n content: \"\";\n inset: 50% auto auto 50%;\n}\n\n/* The stem and the dot, placed by eye around the centre of the circle. */\n.Mark::before {\n height: calc(var(--lea-spacing) * 0.625);\n translate: -50% -8%;\n}\n\n.Mark::after {\n height: calc(var(--lea-spacing) * 0.25);\n translate: -50% -190%;\n}\n\n.Trigger[data-variant=\"filled\"] .Mark {\n border-color: transparent;\n background-color: var(--lea-palette-primary-base);\n color: var(--lea-palette-primary-contrast);\n}\n\n.Trigger[data-variant=\"outlined\"] .Mark {\n width: calc(var(--lea-spacing) * 2.25);\n height: calc(var(--lea-spacing) * 2.25);\n border-color: var(--lea-palette-border-strong);\n background-color: var(--lea-palette-bg-base);\n color: var(--lea-palette-text-base);\n}\n\n@media (prefers-reduced-motion: reduce) {\n .Popup,\n .Trigger,\n .Mark {\n transition-duration: 0.01ms;\n }\n}\n","\"use client\";\n\nimport { Popover } from \"@base-ui/react/popover\";\nimport { Tooltip as BaseTooltip } from \"@base-ui/react/tooltip\";\nimport {\n useId,\n useState,\n type CSSProperties,\n type KeyboardEvent,\n type ReactElement,\n type ReactNode,\n} from \"react\";\n\nimport styles from \"./tooltip.module.css\";\n\nexport type TooltipTriggerVariant = \"icon\" | \"filled\" | \"outlined\";\nexport type TooltipSurfaceVariant = \"light\" | \"dark\";\nexport type TooltipOpenOn = \"hover\" | \"click\";\n\ntype Side = \"top\" | \"bottom\" | \"left\" | \"right\";\nexport type TooltipPlacement = Side | `${Side}-start` | `${Side}-end`;\n\ntype SharedProps = {\n /** What the tooltip says. Nothing is shown while it is empty. */\n title: ReactNode;\n /**\n * How the tooltip opens.\n * - `\"hover\"`: on mouse hover and on keyboard focus. It does not open on\n * touch, so use it for a hint the control works without.\n * - `\"click\"`: on click, tap, Enter or Space, and on mouse hover too. It\n * stays open until dismissed, so use it for information people need.\n *\n * Defaults to `\"hover\"` around `children` and to `\"click\"` for the\n * built-in trigger.\n */\n openOn?: TooltipOpenOn;\n /**\n * Where the tooltip sits against its trigger. It moves to another side when\n * there is no room.\n * @default \"top\"\n */\n placement?: TooltipPlacement;\n /**\n * Colours of the bubble: black text on white, or white text on black.\n * @default \"light\"\n */\n surfaceVariant?: TooltipSurfaceVariant;\n};\n\ntype WrappedTooltipProps = SharedProps & {\n /**\n * The trigger: one element that takes a `ref` and spreads its props, such\n * as a `Button`. It needs an accessible name of its own.\n */\n children: ReactElement<TriggerElementProps>;\n ariaLabel?: never;\n triggerIcon?: never;\n triggerVariant?: never;\n className?: never;\n style?: never;\n};\n\ntype TriggerTooltipProps = SharedProps & {\n children?: never;\n /** Accessible name for the built-in trigger button. */\n ariaLabel: string;\n /** Trigger icon or content. Defaults to an \"i\" in a circle. */\n triggerIcon?: ReactNode;\n /**\n * Visual style of the built-in trigger button.\n * @default \"icon\"\n */\n triggerVariant?: TooltipTriggerVariant;\n /** Class on the built-in trigger button. */\n className?: string;\n /** Inline style on the built-in trigger button. */\n style?: CSSProperties;\n};\n\nexport type TooltipProps = WrappedTooltipProps | TriggerTooltipProps;\n\ntype TriggerElementProps = {\n id?: string;\n \"aria-describedby\"?: string;\n};\n\n/** MUI showed nothing for these either, so an optional text needs no branch. */\nconst isEmpty = (title: ReactNode) =>\n title == null || title === false || title === \"\";\n\nconst position = (placement: TooltipPlacement) => {\n const [side, align = \"center\"] = placement.split(\"-\") as [\n Side,\n (\"start\" | \"end\")?,\n ];\n return { side, align, sideOffset: OFFSET } as const;\n};\n\nconst TABBABLE =\n 'a[href], button:not([disabled]), input, select, textarea, [tabindex]:not([tabindex=\"-1\"])';\n\n// The distance from the trigger to the bubble; the arrow fills half of it.\nconst OFFSET = 14;\n// Short enough to feel immediate, long enough not to flash while the pointer\n// crosses the trigger on its way elsewhere.\nconst HOVER_DELAY = 100;\n\n/**\n * A small bubble of text anchored to a trigger, on Base UI's `Tooltip` and\n * `Popover`.\n *\n * Use it two ways:\n * - **Around a child:** pass `children` to add a hint to a control you already\n * have. It opens on hover and keyboard focus and describes the control.\n * - **Built-in trigger:** omit `children` and pass `ariaLabel`; a small info\n * button is rendered for you. It opens on click, so it works on touch.\n *\n * ```tsx\n * <Tooltip title=\"Kopier kontonummer\">\n * <IconButton aria-label=\"Kopier\">…</IconButton>\n * </Tooltip>\n *\n * <Tooltip title=\"Beløpet du betaler hver måned.\" ariaLabel=\"Mer informasjon\" />\n * ```\n *\n * `openOn` switches either one: `openOn=\"click\"` around a button makes it a\n * disclosure, and `openOn=\"hover\"` makes the info button a plain hint. On\n * hover the trigger must work without the tooltip, since touch never shows it.\n */\nexport function Tooltip({\n title,\n openOn,\n placement = \"top\",\n surfaceVariant = \"light\",\n children,\n ariaLabel,\n triggerIcon,\n triggerVariant = \"icon\",\n className,\n style,\n}: TooltipProps) {\n const [open, setOpen] = useState(false);\n const generatedId = useId();\n const popupId = useId();\n\n const builtInTrigger = (\n <button\n type=\"button\"\n aria-label={ariaLabel}\n className={[styles.Trigger, className].filter(Boolean).join(\" \")}\n style={style}\n data-variant={triggerVariant}\n >\n {triggerIcon ?? <span aria-hidden className={styles.Mark} />}\n </button>\n );\n\n const trigger = children ?? builtInTrigger;\n // The negative margin of the built-in trigger needs a box of its own to pull\n // against, so it takes the room of the icon wherever it is placed.\n const wrap = (node: ReactNode) =>\n children ? node : <span className={styles.TriggerBox}>{node}</span>;\n\n if (isEmpty(title)) return wrap(trigger);\n\n const resolvedOpenOn = openOn ?? (children ? \"hover\" : \"click\");\n\n if (resolvedOpenOn === \"click\") {\n const triggerId = children?.props.id ?? generatedId;\n\n // Tab past the end of the bubble closes it, which puts focus back on the\n // trigger. Left to Base UI 1.6, focus is passed between its focus guards\n // without end when nothing on the page can take focus after the trigger.\n const closeOnTabOut = (event: KeyboardEvent<HTMLDivElement>) => {\n if (event.key !== \"Tab\" || event.shiftKey) return;\n const tabbable = event.currentTarget.querySelectorAll(TABBABLE);\n const last = tabbable[tabbable.length - 1];\n if (last == null || event.target === last) {\n event.preventDefault();\n setOpen(false);\n }\n };\n\n return (\n <Popover.Root open={open} onOpenChange={setOpen}>\n {wrap(\n <Popover.Trigger\n render={trigger}\n id={triggerId}\n openOnHover\n delay={HOVER_DELAY}\n />,\n )}\n <Popover.Portal>\n <Popover.Positioner\n {...position(placement)}\n className={styles.Positioner}\n >\n <Popover.Popup\n // Named by its trigger: \"Mer informasjon\", then the text.\n aria-labelledby={triggerId}\n onKeyDown={closeOnTabOut}\n className={styles.Popup}\n data-surface={surfaceVariant}\n >\n <Popover.Arrow className={styles.Arrow} />\n <Popover.Description render={<div />}>\n {title}\n </Popover.Description>\n </Popover.Popup>\n </Popover.Positioner>\n </Popover.Portal>\n </Popover.Root>\n );\n }\n\n const describedBy =\n [children?.props[\"aria-describedby\"], open && popupId]\n .filter(Boolean)\n .join(\" \") || undefined;\n\n return (\n <BaseTooltip.Root open={open} onOpenChange={setOpen}>\n {wrap(\n <BaseTooltip.Trigger\n render={trigger}\n delay={HOVER_DELAY}\n // Base UI leaves the tooltip out of the accessibility tree; this\n // makes it the description of its trigger while it shows.\n aria-describedby={describedBy}\n />,\n )}\n <BaseTooltip.Portal>\n <BaseTooltip.Positioner\n {...position(placement)}\n className={styles.Positioner}\n >\n <BaseTooltip.Popup\n id={popupId}\n role=\"tooltip\"\n className={styles.Popup}\n data-surface={surfaceVariant}\n >\n <BaseTooltip.Arrow className={styles.Arrow} />\n {title}\n </BaseTooltip.Popup>\n </BaseTooltip.Positioner>\n </BaseTooltip.Portal>\n </BaseTooltip.Root>\n );\n}\n","/*\n * Shared by Alert and GlobalAlert. Design tokens come from src/theme/tokens.css,\n * so these render styled without a provider.\n *\n * Each colour sets local properties that the variants read, which keeps the\n * variant x colour matrix to one rule per cell.\n */\n\n.Alert {\n --alert-base: var(--lea-palette-status-success-base);\n --alert-subtle: var(--lea-palette-status-success-subtle);\n /* Text and icons on the solid fill of the `filled` variant. */\n --alert-on-base: var(--lea-palette-text-contrast);\n\n /* The height of one line of text, so the icon centres on the first line. */\n --alert-line: calc(\n var(--lea-text-body-md-font-size) * var(--lea-text-body-md-line-height)\n );\n --alert-message-padding: calc(var(--lea-spacing) * 0.7);\n\n box-sizing: border-box;\n padding: var(--lea-spacing) calc(var(--lea-spacing) * 2);\n border-radius: var(--lea-radius-xl);\n color: var(--lea-palette-text-base);\n font-size: var(--lea-text-body-md-font-size);\n font-weight: var(--lea-text-body-md-font-weight);\n line-height: var(--lea-text-body-md-line-height);\n letter-spacing: var(--lea-text-body-md-letter-spacing);\n}\n\n.Layout {\n display: flex;\n align-items: flex-start;\n gap: calc(var(--lea-spacing) * 1.5);\n}\n\n.Icon {\n box-sizing: content-box;\n display: flex;\n height: var(--alert-line);\n flex-shrink: 0;\n align-items: center;\n padding-block: var(--alert-message-padding);\n color: var(--alert-base);\n /* The icon's size: it is drawn at 1em. */\n font-size: var(--lea-font-step-2);\n}\n\n.Message {\n display: flex;\n min-width: 0;\n flex: 1;\n flex-direction: column;\n padding-block: var(--alert-message-padding);\n overflow-wrap: anywhere;\n}\n\n.Title {\n font-weight: var(--lea-font-weight-medium);\n}\n\n.Action {\n display: flex;\n flex-shrink: 0;\n align-items: center;\n margin-inline-start: auto;\n}\n\n/* Colours */\n\n.Alert[data-color=\"info\"] {\n --alert-base: var(--lea-palette-status-info-base);\n --alert-subtle: var(--lea-palette-status-info-subtle);\n}\n\n.Alert[data-color=\"warning\"] {\n --alert-base: var(--lea-palette-status-warning-base);\n --alert-subtle: var(--lea-palette-status-warning-subtle);\n /* White does not read on amber. */\n --alert-on-base: var(--lea-palette-text-base);\n}\n\n.Alert[data-color=\"error\"] {\n --alert-base: var(--lea-palette-status-error-base);\n --alert-subtle: var(--lea-palette-status-error-subtle);\n}\n\n.Alert[data-color=\"primary\"] {\n --alert-base: var(--lea-palette-primary-base);\n --alert-subtle: var(--lea-palette-primary-subtle);\n}\n\n.Alert[data-color=\"neutral\"] {\n --alert-base: var(--lea-color-neutral-700);\n --alert-subtle: var(--lea-color-neutral-100);\n}\n\n/* Variants */\n\n.Alert[data-variant=\"standard\"] {\n background-color: var(--alert-subtle);\n}\n\n.Alert[data-variant=\"filled\"] {\n background-color: var(--alert-base);\n color: var(--alert-on-base);\n}\n\n.Alert[data-variant=\"filled\"] .Icon,\n.Alert[data-variant=\"filled\"] .Close {\n color: var(--alert-on-base);\n}\n\n.Alert[data-variant=\"outlined\"] {\n border: 1px solid var(--alert-base);\n background-color: transparent;\n}\n\n/* Sizes */\n\n.Alert[data-size=\"sm\"] {\n --alert-line: calc(\n var(--lea-text-body-sm-font-size) * var(--lea-text-body-sm-line-height)\n );\n\n padding: calc(var(--lea-spacing) * 0.5) calc(var(--lea-spacing) * 1.5);\n font-size: var(--lea-text-body-sm-font-size);\n font-weight: var(--lea-text-body-sm-font-weight);\n line-height: var(--lea-text-body-sm-line-height);\n letter-spacing: var(--lea-text-body-sm-letter-spacing);\n}\n\n.Alert[data-size=\"sm\"] .Layout,\n.Alert[data-size=\"sm\"].Layout {\n gap: var(--lea-spacing);\n}\n\n.Alert[data-size=\"sm\"] .Action {\n margin-block: calc(var(--lea-spacing) * -0.25);\n}\n\n/*\n * GlobalAlert: edge to edge, with the side padding coming from the inner\n * Container so the content lines up with the page.\n */\n\n.Alert[data-global] {\n width: 100%;\n padding-inline: 0;\n border-radius: 0;\n}\n\n.Alert[data-global][data-variant=\"outlined\"] {\n border-inline: 0;\n}\n\n.Layout[data-fluid] {\n max-width: none;\n}\n","\"use client\";\n\nimport { CircleAlert, CircleCheck, Info, TriangleAlert } from \"lucide-react\";\nimport type {\n ComponentPropsWithRef,\n ReactNode,\n SyntheticEvent,\n} from \"react\";\n\nimport { CloseButton } from \"../buttons/close-button\";\nimport type { ColorRoles } from \"../color-roles\";\nimport styles from \"./alert.module.css\";\n\nexport type AlertSeverity = ColorRoles<\n \"success\" | \"info\" | \"warning\" | \"error\"\n>;\nexport type AlertColor = AlertSeverity | ColorRoles<\"primary\" | \"neutral\">;\nexport type AlertVariant = \"standard\" | \"filled\" | \"outlined\";\nexport type AlertSize = \"sm\" | \"lg\";\n\nexport type AlertProps = Omit<ComponentPropsWithRef<\"div\">, \"color\"> & {\n /**\n * Semantic meaning — picks the icon and how screen readers announce it.\n * @default \"success\", or \"info\" with a brand `color`\n */\n severity?: AlertSeverity;\n /**\n * Colour scheme. Defaults to the colour of `severity`. `\"primary\"` (the\n * brand purple) and `\"neutral\"` (grey) carry no status meaning.\n */\n color?: AlertColor;\n /**\n * `\"standard\"` is a tinted fill, `\"filled\"` a solid one, `\"outlined\"` a\n * border only.\n * @default \"standard\"\n */\n variant?: AlertVariant;\n /**\n * `\"sm\"` for tighter padding and smaller text.\n * @default \"lg\"\n */\n size?: AlertSize;\n /** Replaces the severity icon. Pass `false` to hide it. */\n icon?: ReactNode | false;\n /** Content for the end of the alert, e.g. a button. Replaces the close button. */\n action?: ReactNode;\n /** Renders a close button that calls this when pressed. */\n onClose?: (event: SyntheticEvent) => void;\n /** Accessible name of the close button. Defaults to a translated \"Close\". */\n closeLabel?: string;\n};\n\nconst brandColours: AlertColor[] = [\"primary\", \"neutral\"];\n\nconst alertIcons: Record<AlertSeverity, ReactNode> = {\n success: <CircleCheck size=\"1em\" aria-hidden />,\n info: <Info size=\"1em\" aria-hidden />,\n warning: <TriangleAlert size=\"1em\" aria-hidden />,\n error: <CircleAlert size=\"1em\" aria-hidden />,\n};\n\n/**\n * Resolves the props shared by `Alert` and `GlobalAlert` into the root's\n * attributes and its inner markup. Internal — not exported from the package.\n */\nexport function resolveAlert({\n severity,\n color,\n variant = \"standard\",\n size = \"lg\",\n icon,\n action,\n onClose,\n closeLabel,\n role,\n children,\n ...rest\n}: AlertProps) {\n const resolvedSeverity: AlertSeverity =\n severity ?? (color && brandColours.includes(color) ? \"info\" : \"success\");\n\n const rootProps = {\n ...rest,\n role:\n role ??\n (resolvedSeverity === \"error\" || resolvedSeverity === \"warning\"\n ? \"alert\"\n : \"status\"),\n \"data-color\": color ?? resolvedSeverity,\n \"data-variant\": variant,\n \"data-size\": size,\n };\n\n const resolvedIcon = icon === undefined ? alertIcons[resolvedSeverity] : icon;\n const resolvedAction =\n action ??\n (onClose && (\n <CloseButton\n size=\"sm\"\n label={closeLabel}\n onClick={onClose}\n className={styles.Close}\n />\n ));\n\n const content = (\n <>\n {resolvedIcon !== false && resolvedIcon != null && (\n <div className={styles.Icon}>{resolvedIcon}</div>\n )}\n <div className={styles.Message}>{children}</div>\n {resolvedAction && <div className={styles.Action}>{resolvedAction}</div>}\n </>\n );\n\n return { rootProps, content };\n}\n","\"use client\";\n\nimport type { ComponentPropsWithRef } from \"react\";\n\nimport { type AlertProps, resolveAlert } from \"./alert-parts\";\nimport styles from \"./alert.module.css\";\n\nexport type {\n AlertColor,\n AlertProps,\n AlertSeverity,\n AlertSize,\n AlertVariant,\n} from \"./alert-parts\";\n\n/**\n * A message with Lea Bank's status colours. The ARIA `role` is derived from\n * `severity`: `error` / `warning` announce assertively (`role=\"alert\"`) while\n * `info` / `success` announce politely (`role=\"status\"`). Pass an explicit\n * `role` to override.\n *\n * With `onClose`, a close button is rendered with a translated accessible\n * name — override it per-instance with `closeLabel`.\n *\n * ```tsx\n * <Alert color=\"primary\" size=\"sm\">\n * Lånet forutsetter at du løser skulder for totalt 80 000 kr.\n * </Alert>\n * ```\n */\nexport function Alert({ className, ...props }: AlertProps) {\n const { rootProps, content } = resolveAlert(props);\n\n return (\n <div\n {...rootProps}\n className={[styles.Alert, styles.Layout, className]\n .filter(Boolean)\n .join(\" \")}\n >\n {content}\n </div>\n );\n}\n\nexport type AlertTitleProps = ComponentPropsWithRef<\"div\">;\n\n/** A heading above the alert's message. */\nexport function AlertTitle({ className, ...rest }: AlertTitleProps) {\n return (\n <div\n {...rest}\n className={[styles.Title, className].filter(Boolean).join(\" \")}\n />\n );\n}\n","/*\n * Design tokens come from src/theme/tokens.css, generated from src/theme/tokens\n * by `pnpm tokens:css`. It is a plain stylesheet rather than runtime-injected\n * CSS variables, so this component renders correctly without a provider.\n * `--lea-spacing` is the 0.5rem base unit, multiplied to match `spacing(n)`.\n */\n\n.Backdrop {\n position: fixed;\n z-index: 1300;\n background-color: var(--lea-palette-bg-overlay);\n inset: 0;\n opacity: 1;\n transition: opacity var(--lea-duration-normal) var(--lea-easing-standard);\n}\n\n.Backdrop[data-starting-style],\n.Backdrop[data-ending-style] {\n opacity: 0;\n}\n\n.Viewport {\n position: fixed;\n z-index: 1300;\n display: flex;\n align-items: center;\n justify-content: center;\n padding: calc(var(--lea-spacing) * 2);\n inset: 0;\n /*\n * The viewport covers the window so the popup can be centred, but only the\n * popup should swallow clicks — presses that land here are outside presses\n * and must dismiss the dialog.\n */\n pointer-events: none;\n}\n\n.Popup {\n display: flex;\n overflow: hidden;\n width: 100%;\n max-height: 100%;\n flex-direction: column;\n border-radius: var(--lea-radius-4xl);\n background-color: var(--lea-palette-bg-base);\n box-shadow: var(--lea-shadow-xl);\n color: var(--lea-palette-text-base);\n opacity: 1;\n pointer-events: auto;\n transform: scale(1);\n transition:\n opacity var(--lea-duration-normal) var(--lea-easing-standard),\n transform var(--lea-duration-normal) var(--lea-easing-standard);\n}\n\n.Popup[data-starting-style],\n.Popup[data-ending-style] {\n opacity: 0;\n transform: scale(0.95);\n}\n\n.Popup[data-size=\"xs\"] {\n max-width: 27.75rem;\n}\n\n.Popup[data-size=\"sm\"] {\n max-width: 37.5rem;\n}\n\n.Popup[data-size=\"md\"] {\n max-width: 56.25rem;\n}\n\n.Popup[data-size=\"lg\"] {\n max-width: 75rem;\n}\n\n.Header {\n display: flex;\n flex-shrink: 0;\n align-items: flex-start;\n justify-content: space-between;\n gap: var(--lea-spacing);\n padding: calc(var(--lea-spacing) * 3) calc(var(--lea-spacing) * 3)\n calc(var(--lea-spacing) * 2);\n}\n\n.Title {\n margin: 0;\n color: var(--lea-palette-text-base);\n font-size: var(--lea-text-heading-sm-font-size);\n font-weight: var(--lea-text-heading-sm-font-weight);\n line-height: var(--lea-text-heading-sm-line-height);\n letter-spacing: var(--lea-text-heading-sm-letter-spacing);\n}\n\n.Description {\n margin: 0 0 calc(var(--lea-spacing) * 2);\n color: var(--lea-palette-text-subtle);\n}\n\n/*\n * Set when the description is the last thing in the body. A `:last-child`\n * selector would not do: body content is often a bare string, and text nodes\n * don't count as children.\n */\n.Description[data-last] {\n margin-bottom: 0;\n}\n\n.Content {\n overflow-y: auto;\n flex: 1;\n padding: 0 calc(var(--lea-spacing) * 3) calc(var(--lea-spacing) * 3);\n color: var(--lea-palette-text-base);\n}\n\n/* The footer's top padding takes over the gap, mirroring the header. */\n.Content:has(+ .Footer) {\n padding-bottom: 0;\n}\n\n.Footer {\n display: flex;\n flex-shrink: 0;\n flex-wrap: wrap;\n align-items: center;\n justify-content: flex-end;\n gap: var(--lea-spacing);\n padding: calc(var(--lea-spacing) * 2) calc(var(--lea-spacing) * 3)\n calc(var(--lea-spacing) * 2);\n background-color: var(--lea-palette-bg-base);\n}\n\n.CloseButton {\n display: inline-flex;\n width: 2.5rem;\n height: 2.5rem;\n flex-shrink: 0;\n align-items: center;\n justify-content: center;\n padding: 0;\n border: 2px solid var(--lea-palette-border-base);\n border-radius: var(--lea-radius-full);\n margin-inline-end: calc(var(--lea-spacing) * -0.5);\n background-color: transparent;\n color: var(--lea-palette-text-base);\n cursor: pointer;\n transition:\n border-color var(--lea-duration-emphasis) var(--lea-easing-spring),\n background-color var(--lea-duration-emphasis) var(--lea-easing-spring),\n color var(--lea-duration-emphasis) var(--lea-easing-spring);\n}\n\n@media (hover: hover) {\n .CloseButton:hover {\n border-color: var(--lea-palette-primary-base);\n background-color: var(--lea-palette-primary-base);\n color: var(--lea-palette-primary-contrast);\n }\n}\n\n.CloseButton:focus-visible {\n outline: 2px solid var(--lea-palette-text-base);\n outline-offset: 0.125rem;\n}\n\n/*\n * Fills the screen rather than floating as a card. `100dvh` follows the mobile\n * browser chrome as it collapses, and the safe-area inset keeps the content\n * clear of the home indicator.\n */\n@media (max-width: 599.95px) {\n .Viewport:has(.Popup[data-full-screen-on-mobile]) {\n padding: 0;\n }\n\n .Popup[data-full-screen-on-mobile] {\n width: 100vw;\n max-width: none;\n height: 100dvh;\n max-height: none;\n border-radius: 0;\n }\n\n .Popup[data-full-screen-on-mobile] .Content {\n padding-bottom: calc(\n var(--lea-spacing) * 3 + env(safe-area-inset-bottom)\n );\n }\n\n .Popup[data-full-screen-on-mobile] .Content:has(+ .Footer) {\n padding-bottom: 0;\n }\n\n .Popup[data-full-screen-on-mobile] .Footer {\n padding-bottom: calc(\n var(--lea-spacing) * 3 + env(safe-area-inset-bottom)\n );\n }\n}\n\n@media (prefers-reduced-motion: reduce) {\n .Backdrop,\n .Popup,\n .CloseButton {\n transition-duration: 0.01ms;\n }\n}\n","\"use client\";\n\nimport { Dialog as BaseDialog } from \"@base-ui/react/dialog\";\nimport { X } from \"lucide-react\";\nimport type { ComponentPropsWithRef } from \"react\";\n\nimport { mergeClassName } from \"../../utils/merge-class-name\";\nimport styles from \"./dialog.module.css\";\nimport { useCloseLabel } from \"./use-close-label\";\n\n/**\n * Maximum width of the popup. The names match the breakpoint scale the library\n * used before, so `size=\"xs\"` is still the compact confirm dialog.\n */\nexport type Size = \"xs\" | \"sm\" | \"md\" | \"lg\";\n\n/**\n * Groups all parts of the dialog and owns the open state. Renders no element\n * of its own. Control it with `open` + `onOpenChange`, or leave both off and\n * let a `Dialog.Trigger` drive it.\n */\nexport const Root = BaseDialog.Root;\nexport type RootProps<Payload = unknown> = BaseDialog.Root.Props<Payload>;\n\n/**\n * Opens the dialog. Renders a bare `<button>`, so pass a styled control\n * through `render` — `<Dialog.Trigger render={<Button />}>Open</Dialog.Trigger>`.\n */\nexport const Trigger = BaseDialog.Trigger;\nexport type TriggerProps<Payload = unknown> = BaseDialog.Trigger.Props<Payload>;\n\n/** Moves the backdrop and popup to the end of `<body>`. */\nexport const Portal = BaseDialog.Portal;\nexport type PortalProps = BaseDialog.Portal.Props;\n\nexport type BackdropProps = BaseDialog.Backdrop.Props;\n\n/** The dimmed overlay behind the popup. */\nexport function Backdrop({ className, ...rest }: BackdropProps) {\n return (\n <BaseDialog.Backdrop\n {...rest}\n className={mergeClassName(styles.Backdrop, className)}\n />\n );\n}\n\nexport type ViewportProps = BaseDialog.Viewport.Props;\n\n/** Centres the popup in the window and keeps a gutter at the screen edges. */\nexport function Viewport({ className, ...rest }: ViewportProps) {\n return (\n <BaseDialog.Viewport\n {...rest}\n className={mergeClassName(styles.Viewport, className)}\n />\n );\n}\n\nexport type PopupProps = BaseDialog.Popup.Props & {\n /**\n * Maximum width of the surface.\n * @default \"sm\"\n */\n size?: Size;\n /**\n * Fills the screen on narrow viewports (below 600px) instead of floating as\n * a card. Use it for flows that need the whole screen, such as a multi-step\n * form or a long consent list.\n */\n fullScreenOnMobile?: boolean;\n};\n\n/**\n * The dialog surface. Lays its children out in a column so a `Dialog.Content`\n * can scroll while the header stays put.\n */\nexport function Popup({\n size = \"sm\",\n fullScreenOnMobile,\n className,\n ...rest\n}: PopupProps) {\n return (\n <BaseDialog.Popup\n {...rest}\n data-size={size}\n data-full-screen-on-mobile={fullScreenOnMobile || undefined}\n className={mergeClassName(styles.Popup, className)}\n />\n );\n}\n\nexport type HeaderProps = ComponentPropsWithRef<\"div\">;\n\n/**\n * The title row. Anything after the `Dialog.Title` sits on the same line,\n * which is where `Dialog.CloseButton` belongs. Stays fixed while\n * `Dialog.Content` scrolls.\n */\nexport function Header({ className, ...rest }: HeaderProps) {\n return (\n <div\n {...rest}\n className={[styles.Header, className].filter(Boolean).join(\" \")}\n />\n );\n}\n\nexport type TitleProps = BaseDialog.Title.Props;\n\n/**\n * The heading. Base UI links it to the popup as the accessible name, so no id\n * wiring is needed.\n */\nexport function Title({ className, ...rest }: TitleProps) {\n return (\n <BaseDialog.Title\n {...rest}\n className={mergeClassName(styles.Title, className)}\n />\n );\n}\n\nexport type DescriptionProps = BaseDialog.Description.Props;\n\n/** Supporting text, linked to the popup as its accessible description. */\nexport function Description({ className, ...rest }: DescriptionProps) {\n return (\n <BaseDialog.Description\n {...rest}\n className={mergeClassName(styles.Description, className)}\n />\n );\n}\n\nexport type ContentProps = ComponentPropsWithRef<\"div\">;\n\n/** The body. Scrolls on its own once the popup runs out of height. */\nexport function Content({ className, ...rest }: ContentProps) {\n return (\n <div\n {...rest}\n className={[styles.Content, className].filter(Boolean).join(\" \")}\n />\n );\n}\n\nexport type FooterProps = ComponentPropsWithRef<\"div\">;\n\n/**\n * The action row, placed after `Dialog.Content`. Stays pinned to the bottom of\n * the popup while `Dialog.Content` scrolls, and lines its children up at the\n * end.\n */\nexport function Footer({ className, ...rest }: FooterProps) {\n return (\n <div\n {...rest}\n className={[styles.Footer, className].filter(Boolean).join(\" \")}\n />\n );\n}\n\n/**\n * Closes the dialog. Renders a bare `<button>` for text actions — use\n * `render` for a styled one: `<Dialog.Close render={<Button />}>Cancel</Dialog.Close>`.\n * For the X in the header corner, use `Dialog.CloseButton`.\n */\nexport const Close = BaseDialog.Close;\nexport type CloseProps = BaseDialog.Close.Props;\n\nexport type CloseButtonProps = Omit<\n BaseDialog.Close.Props,\n \"children\" | \"aria-label\"\n> & {\n /** Accessible name. Defaults to a translated \"Close\". */\n label?: string;\n};\n\n/**\n * The round X in the header corner. It renders its own icon and always has an\n * accessible name, so it cannot be built without one.\n */\nexport function CloseButton({ label, className, ...rest }: CloseButtonProps) {\n const t = useCloseLabel();\n\n return (\n <BaseDialog.Close\n {...rest}\n aria-label={label ?? t.close}\n className={mergeClassName(styles.CloseButton, className)}\n >\n <X size={20} aria-hidden />\n </BaseDialog.Close>\n );\n}\n","/*\n * Design tokens come from src/theme/tokens.css, generated from src/theme/tokens\n * by `pnpm tokens:css`. It is a plain stylesheet rather than runtime-injected\n * CSS variables, so this component renders correctly without a provider.\n * `--lea-spacing` is the 0.5rem base unit, multiplied to match `spacing(n)`.\n *\n * Positioning keys off `data-swipe-direction`, which Base UI sets on the popup\n * from the root's `swipeDirection` — the same value `Drawer.Root` derives from\n * `side`, so the panel can never sit on one edge and swipe towards another.\n */\n\n.Backdrop {\n position: fixed;\n z-index: 1300;\n background-color: var(--lea-palette-bg-overlay);\n inset: 0;\n /* Fades in step with the swipe, so the panel feels attached to the finger. */\n opacity: calc(1 - var(--drawer-swipe-progress, 0));\n transition: opacity var(--lea-duration-normal) var(--lea-easing-standard);\n}\n\n.Backdrop[data-starting-style],\n.Backdrop[data-ending-style] {\n opacity: 0;\n}\n\n.Viewport {\n position: fixed;\n z-index: 1300;\n inset: 0;\n /* Only the panel should swallow clicks; presses elsewhere dismiss it. */\n pointer-events: none;\n}\n\n.Popup {\n position: absolute;\n display: flex;\n flex-direction: column;\n background-color: var(--lea-palette-bg-base);\n box-shadow: var(--lea-shadow-xl);\n color: var(--lea-palette-text-base);\n pointer-events: auto;\n transition: transform var(--lea-duration-normal) var(--lea-easing-standard);\n}\n\n.Popup[data-swipe-direction=\"left\"],\n.Popup[data-swipe-direction=\"right\"] {\n top: 0;\n width: min(var(--drawer-size, 22.5rem), 100vw);\n height: 100%;\n transform: translateX(var(--drawer-swipe-movement-x, 0px));\n}\n\n.Popup[data-swipe-direction=\"left\"] {\n left: 0;\n}\n\n.Popup[data-swipe-direction=\"right\"] {\n right: 0;\n}\n\n.Popup[data-swipe-direction=\"up\"],\n.Popup[data-swipe-direction=\"down\"] {\n left: 0;\n width: 100%;\n /* Sheets size to their content; `--drawer-size` caps them lower if needed. */\n max-height: var(--drawer-size, 90dvh);\n transform: translateY(\n calc(var(--drawer-snap-point-offset, 0px) + var(--drawer-swipe-movement-y, 0px))\n );\n}\n\n/* Sheets round the edge that faces the content, the way a card would. */\n.Popup[data-swipe-direction=\"up\"] {\n top: 0;\n border-radius: 0 0 var(--drawer-radius, var(--lea-radius-4xl))\n var(--drawer-radius, var(--lea-radius-4xl));\n}\n\n.Popup[data-swipe-direction=\"down\"] {\n bottom: 0;\n border-radius: var(--drawer-radius, var(--lea-radius-4xl))\n var(--drawer-radius, var(--lea-radius-4xl)) 0 0;\n padding-bottom: env(safe-area-inset-bottom);\n}\n\n.Popup[data-starting-style][data-swipe-direction=\"left\"],\n.Popup[data-ending-style][data-swipe-direction=\"left\"] {\n transform: translateX(-100%);\n}\n\n.Popup[data-starting-style][data-swipe-direction=\"right\"],\n.Popup[data-ending-style][data-swipe-direction=\"right\"] {\n transform: translateX(100%);\n}\n\n.Popup[data-starting-style][data-swipe-direction=\"up\"],\n.Popup[data-ending-style][data-swipe-direction=\"up\"] {\n transform: translateY(-100%);\n}\n\n.Popup[data-starting-style][data-swipe-direction=\"down\"],\n.Popup[data-ending-style][data-swipe-direction=\"down\"] {\n transform: translateY(100%);\n}\n\n/* A flick should settle faster than a slow drag; a live drag must not lag. */\n.Popup[data-ending-style],\n.Backdrop[data-ending-style] {\n transition-duration: calc(\n var(--drawer-swipe-strength, 1) * var(--lea-duration-normal)\n );\n}\n\n.Popup[data-swiping],\n.Backdrop[data-swiping] {\n transition-duration: 0ms;\n}\n\n.Handle {\n width: calc(var(--lea-spacing) * 5);\n height: calc(var(--lea-spacing) * 0.5);\n flex-shrink: 0;\n border-radius: var(--lea-radius-sm);\n margin: calc(var(--lea-spacing) * 1.5) auto calc(var(--lea-spacing) * 0.5);\n background-color: var(--lea-palette-border-base);\n}\n\n/* A top sheet is dragged upwards, so its handle belongs on the bottom edge. */\n.Popup[data-swipe-direction=\"up\"] .Handle {\n margin: calc(var(--lea-spacing) * 0.5) auto calc(var(--lea-spacing) * 1.5);\n}\n\n.Header {\n display: flex;\n flex-shrink: 0;\n align-items: flex-start;\n justify-content: space-between;\n gap: var(--lea-spacing);\n padding: calc(var(--lea-spacing) * 3) calc(var(--lea-spacing) * 3)\n calc(var(--lea-spacing) * 2);\n}\n\n.Title {\n margin: 0;\n color: var(--lea-palette-text-base);\n font-size: var(--lea-text-heading-sm-font-size);\n font-weight: var(--lea-text-heading-sm-font-weight);\n line-height: var(--lea-text-heading-sm-line-height);\n letter-spacing: var(--lea-text-heading-sm-letter-spacing);\n}\n\n.Description {\n margin: 0 0 calc(var(--lea-spacing) * 2);\n color: var(--lea-palette-text-subtle);\n}\n\n/*\n * Set when the description is the last thing in the body. A `:last-child`\n * selector would not do: body content is often a bare string, and text nodes\n * don't count as children.\n */\n.Description[data-last] {\n margin-bottom: 0;\n}\n\n.Content {\n overflow-y: auto;\n flex: 1;\n padding: 0 calc(var(--lea-spacing) * 3) calc(var(--lea-spacing) * 3);\n color: var(--lea-palette-text-base);\n}\n\n.CloseButton {\n display: inline-flex;\n width: 2.5rem;\n height: 2.5rem;\n flex-shrink: 0;\n align-items: center;\n justify-content: center;\n padding: 0;\n border: 2px solid var(--lea-palette-border-base);\n border-radius: var(--lea-radius-full);\n margin-inline-end: calc(var(--lea-spacing) * -0.5);\n background-color: transparent;\n color: var(--lea-palette-text-base);\n cursor: pointer;\n transition:\n border-color var(--lea-duration-emphasis) var(--lea-easing-spring),\n background-color var(--lea-duration-emphasis) var(--lea-easing-spring),\n color var(--lea-duration-emphasis) var(--lea-easing-spring);\n}\n\n@media (hover: hover) {\n .CloseButton:hover {\n border-color: var(--lea-palette-primary-base);\n background-color: var(--lea-palette-primary-base);\n color: var(--lea-palette-primary-contrast);\n }\n}\n\n.CloseButton:focus-visible {\n outline: 2px solid var(--lea-palette-text-base);\n outline-offset: 0.125rem;\n}\n\n@media (prefers-reduced-motion: reduce) {\n .Backdrop,\n .Popup,\n .CloseButton {\n transition-duration: 0.01ms;\n }\n}\n","\"use client\";\n\nimport { Drawer as BaseDrawer } from \"@base-ui/react/drawer\";\nimport { X } from \"lucide-react\";\nimport type { ComponentPropsWithRef } from \"react\";\n\nimport { mergeClassName } from \"../../utils/merge-class-name\";\nimport styles from \"./drawer.module.css\";\nimport { useCloseLabel } from \"./use-close-label\";\n\n/** Screen edge the panel slides in from. */\nexport type Side = \"left\" | \"right\" | \"top\" | \"bottom\";\n\n/**\n * The panel is dismissed by swiping it back towards the edge it came from, so\n * the gesture direction follows from the side.\n */\nconst SWIPE_DIRECTION = {\n left: \"left\",\n right: \"right\",\n top: \"up\",\n bottom: \"down\",\n} as const;\n\nexport type RootProps<Payload = unknown> = Omit<\n BaseDrawer.Root.Props<Payload>,\n \"swipeDirection\"\n> & {\n /**\n * Screen edge the panel slides in from. Also sets the swipe-to-dismiss\n * direction, so the two can never disagree.\n * @default \"right\"\n */\n side?: Side;\n};\n\n/**\n * Groups all parts of the drawer and owns the open state. Renders no element\n * of its own. Control it with `open` + `onOpenChange`, or leave both off and\n * let a `Drawer.Trigger` drive it.\n */\nexport function Root<Payload = unknown>({\n side = \"right\",\n ...rest\n}: RootProps<Payload>) {\n return <BaseDrawer.Root {...rest} swipeDirection={SWIPE_DIRECTION[side]} />;\n}\n\n/**\n * Opens the drawer. Renders a bare `<button>`, so pass a styled control\n * through `render` — `<Drawer.Trigger render={<Button />}>Open</Drawer.Trigger>`.\n */\nexport const Trigger = BaseDrawer.Trigger;\nexport type TriggerProps<Payload = unknown> = BaseDrawer.Trigger.Props<Payload>;\n\n/** Moves the backdrop and popup to the end of `<body>`. */\nexport const Portal = BaseDrawer.Portal;\nexport type PortalProps = BaseDrawer.Portal.Props;\n\nexport type BackdropProps = BaseDrawer.Backdrop.Props;\n\n/** The dimmed overlay behind the panel. Fades out as the panel is swiped away. */\nexport function Backdrop({ className, ...rest }: BackdropProps) {\n return (\n <BaseDrawer.Backdrop\n {...rest}\n className={mergeClassName(styles.Backdrop, className)}\n />\n );\n}\n\nexport type ViewportProps = BaseDrawer.Viewport.Props;\n\n/**\n * Positioning container for the panel. Also the element Base UI offsets when\n * the on-screen keyboard appears.\n */\nexport function Viewport({ className, ...rest }: ViewportProps) {\n return (\n <BaseDrawer.Viewport\n {...rest}\n className={mergeClassName(styles.Viewport, className)}\n />\n );\n}\n\nexport type PopupProps = BaseDrawer.Popup.Props;\n\n/**\n * The panel surface, pinned to the edge given by `side` on `Drawer.Root`.\n * Side panels are `min(22.5rem, 100vw)` wide and sheets are at most 90% of the\n * screen height; override either with the `--drawer-size` custom property.\n */\nexport function Popup({ className, ...rest }: PopupProps) {\n return (\n <BaseDrawer.Popup\n {...rest}\n className={mergeClassName(styles.Popup, className)}\n />\n );\n}\n\nexport type HandleProps = ComponentPropsWithRef<\"div\">;\n\n/**\n * The grab bar at the top of a bottom sheet. Decorative — the panel is\n * swipe-dismissable anywhere, so this is a hint rather than a control.\n */\nexport function Handle({ className, ...rest }: HandleProps) {\n return (\n <div\n {...rest}\n aria-hidden\n className={[styles.Handle, className].filter(Boolean).join(\" \")}\n />\n );\n}\n\nexport type HeaderProps = ComponentPropsWithRef<\"div\">;\n\n/**\n * The title row. Anything after the `Drawer.Title` sits on the same line,\n * which is where `Drawer.CloseButton` belongs. Stays fixed while\n * `Drawer.Content` scrolls.\n */\nexport function Header({ className, ...rest }: HeaderProps) {\n return (\n <div\n {...rest}\n className={[styles.Header, className].filter(Boolean).join(\" \")}\n />\n );\n}\n\nexport type TitleProps = BaseDrawer.Title.Props;\n\n/**\n * The heading. Base UI links it to the panel as the accessible name, so no id\n * wiring is needed.\n */\nexport function Title({ className, ...rest }: TitleProps) {\n return (\n <BaseDrawer.Title\n {...rest}\n className={mergeClassName(styles.Title, className)}\n />\n );\n}\n\nexport type DescriptionProps = BaseDrawer.Description.Props;\n\n/** Supporting text, linked to the panel as its accessible description. */\nexport function Description({ className, ...rest }: DescriptionProps) {\n return (\n <BaseDrawer.Description\n {...rest}\n className={mergeClassName(styles.Description, className)}\n />\n );\n}\n\nexport type ContentProps = BaseDrawer.Content.Props;\n\n/**\n * The body. Scrolls on its own once the panel runs out of height, and lets a\n * mouse select text inside it without starting a swipe.\n */\nexport function Content({ className, ...rest }: ContentProps) {\n return (\n <BaseDrawer.Content\n {...rest}\n className={mergeClassName(styles.Content, className)}\n />\n );\n}\n\n/**\n * Closes the drawer. Renders a bare `<button>` for text actions — use\n * `render` for a styled one: `<Drawer.Close render={<Button />}>Cancel</Drawer.Close>`.\n * For the X in the header corner, use `Drawer.CloseButton`.\n */\nexport const Close = BaseDrawer.Close;\nexport type CloseProps = BaseDrawer.Close.Props;\n\nexport type CloseButtonProps = Omit<\n BaseDrawer.Close.Props,\n \"children\" | \"aria-label\"\n> & {\n /** Accessible name. Defaults to a translated \"Close\". */\n label?: string;\n};\n\n/**\n * The round X in the header corner. It renders its own icon and always has an\n * accessible name, so it cannot be built without one.\n */\nexport function CloseButton({ label, className, ...rest }: CloseButtonProps) {\n const t = useCloseLabel();\n\n return (\n <BaseDrawer.Close\n {...rest}\n aria-label={label ?? t.close}\n className={mergeClassName(styles.CloseButton, className)}\n >\n <X size={20} aria-hidden />\n </BaseDrawer.Close>\n );\n}\n",".Container {\n box-sizing: border-box;\n width: 100%;\n max-width: var(--lea-breakpoint-lg);\n padding-inline: calc(var(--lea-spacing) * 2);\n margin-inline: auto;\n}\n\n.Container[data-size=\"sm\"] {\n max-width: var(--lea-breakpoint-sm);\n}\n\n.Container[data-size=\"md\"] {\n max-width: var(--lea-breakpoint-md);\n}\n\n.Container[data-size=\"xl\"] {\n max-width: var(--lea-breakpoint-xl);\n}\n\n@media (min-width: 600px) {\n .Container {\n padding-inline: calc(var(--lea-spacing) * 3);\n }\n}\n\n@media (min-width: 900px) {\n .Container {\n padding-inline: calc(var(--lea-spacing) * 4);\n }\n}\n","\"use client\";\n\nimport { useRender } from \"@base-ui/react/use-render\";\n\nimport type { Breakpoint } from \"../../theme/tokens/breakpoints\";\nimport { mergeClassName } from \"../../utils/merge-class-name\";\nimport styles from \"./container.module.css\";\n\nexport type ContainerSize = Exclude<Breakpoint, \"xs\">;\n\nexport type ContainerProps = Omit<useRender.ComponentProps<\"div\">, \"ref\"> & {\n /**\n * Maximum width, named after the breakpoint it matches: `\"md\"` stops\n * growing at the `md` breakpoint width.\n * @default \"lg\"\n */\n size?: ContainerSize;\n};\n\n/**\n * Centres page content, caps its width and keeps it clear of the screen edge.\n * The side padding grows with the viewport: `spacing(2)` on phones,\n * `spacing(3)` from `sm` and `spacing(4)` from `md`.\n *\n * ```tsx\n * <Container render={<main />}>\n * <Text variant=\"h1\">Mine lån</Text>\n * </Container>\n * ```\n */\nexport function Container({\n size = \"lg\",\n render,\n className,\n ...rest\n}: ContainerProps) {\n return useRender({\n render,\n props: {\n ...rest,\n \"data-size\": size,\n className: mergeClassName(styles.Container, className)({}),\n },\n });\n}\n","\"use client\";\n\nimport { Container } from \"../layout/container\";\nimport { type AlertProps, resolveAlert } from \"./alert-parts\";\nimport styles from \"./alert.module.css\";\n\nexport type GlobalAlertProps = AlertProps & {\n /**\n * Lets the content span the full width instead of stopping at the `lg`\n * breakpoint. The side padding stays.\n * @default false\n */\n fluid?: boolean;\n};\n\n/**\n * An `Alert` that spans the whole page width, for messages about the whole\n * page or session. Place it directly above or below `AppHeader`. It takes the\n * same props and styling as `Alert`, without the rounded corners, and its\n * content follows the `Container` breakpoints and side padding.\n *\n * ```tsx\n * <AppHeader />\n * <GlobalAlert severity=\"warning\" onClose={dismiss}>\n * <AlertTitle>Planned maintenance</AlertTitle>\n * Online banking is unavailable tonight from 22:00 to 23:00.\n * </GlobalAlert>\n * ```\n */\nexport function GlobalAlert({\n fluid = false,\n className,\n ...props\n}: GlobalAlertProps) {\n const { rootProps, content } = resolveAlert(props);\n\n return (\n <div\n {...rootProps}\n data-global=\"\"\n className={[styles.Alert, className].filter(Boolean).join(\" \")}\n >\n <Container className={styles.Layout} data-fluid={fluid || undefined}>\n {content}\n </Container>\n </div>\n );\n}\n","\"use client\";\n\nimport type { ReactNode } from \"react\";\n\nimport * as Dialog from \"./dialog\";\n\nexport type SimpleDialogProps = Omit<Dialog.RootProps, \"children\"> & {\n /** Heading. Becomes the dialog's accessible name. */\n title: ReactNode;\n /** Optional supporting text. Becomes the accessible description. */\n description?: ReactNode;\n /** Body content rendered below the title / description. */\n children?: ReactNode;\n /** Accessible name for the close button. Defaults to a translated \"Close\". */\n closeLabel?: string;\n /**\n * Maximum width of the surface.\n * @default \"sm\"\n */\n size?: Dialog.Size;\n /** Fills the screen below 600px instead of floating as a card. */\n fullScreenOnMobile?: boolean;\n /** Hide close button. */\n hideCloseButton?: boolean;\n};\n\n/**\n * The ready-made modal: pass `title`, an optional `description` and\n * `children`, and it renders the Lea chrome — a white, large-radius surface\n * over a dark overlay, a title row with a close button, and a scrollable body.\n *\n * Reach for `Dialog` (the parts) when you need a different layout.\n *\n * ```tsx\n * <SimpleDialog\n * open={open}\n * onOpenChange={setOpen}\n * title=\"Update your details\"\n * description=\"Keep your contact information up to date.\"\n * >\n * <Input label=\"Phone\" />\n * </SimpleDialog>\n * ```\n */\nexport function SimpleDialog({\n title,\n description,\n children,\n closeLabel,\n size,\n fullScreenOnMobile,\n hideCloseButton,\n ...rest\n}: SimpleDialogProps) {\n return (\n <Dialog.Root {...rest}>\n <Dialog.Portal>\n <Dialog.Backdrop />\n <Dialog.Viewport>\n <Dialog.Popup size={size} fullScreenOnMobile={fullScreenOnMobile}>\n <Dialog.Header>\n <Dialog.Title>{title}</Dialog.Title>\n {!hideCloseButton && <Dialog.CloseButton label={closeLabel} />}\n </Dialog.Header>\n <Dialog.Content>\n {description != null && (\n <Dialog.Description data-last={children == null || undefined}>\n {description}\n </Dialog.Description>\n )}\n {children}\n </Dialog.Content>\n </Dialog.Popup>\n </Dialog.Viewport>\n </Dialog.Portal>\n </Dialog.Root>\n );\n}\n","\"use client\";\n\nimport type { ReactNode } from \"react\";\n\nimport * as Drawer from \"./drawer\";\n\nexport type SimpleDrawerProps = Omit<Drawer.RootProps, \"children\"> & {\n /** Heading. Becomes the drawer's accessible name. */\n title: ReactNode;\n /** Optional supporting text. Becomes the accessible description. */\n description?: ReactNode;\n /** Body content rendered below the title / description. */\n children?: ReactNode;\n /** Accessible name for the close button. Defaults to a translated \"Close\". */\n closeLabel?: string;\n};\n\n/**\n * The ready-made side panel: pass `title`, an optional `description` and\n * `children`, and it renders the Lea chrome — a white surface that slides in\n * from the edge over a dark overlay, a header row with a close button, and a\n * scrollable body. Swipe-to-dismiss comes for free, towards `side`.\n *\n * Bottom and top sheets (`side=\"bottom\"` / `\"top\"`) get a grab handle and\n * round the edge that faces the content.\n *\n * Reach for `Drawer` (the parts) when you need a different layout.\n *\n * ```tsx\n * <SimpleDrawer open={open} onOpenChange={setOpen} title=\"Filters\">\n * <FilterForm />\n * </SimpleDrawer>\n * ```\n */\nexport function SimpleDrawer({\n title,\n description,\n children,\n closeLabel,\n side = \"right\",\n ...rest\n}: SimpleDrawerProps) {\n return (\n <Drawer.Root {...rest} side={side}>\n <Drawer.Portal>\n <Drawer.Backdrop />\n <Drawer.Viewport>\n <Drawer.Popup>\n {/* The handle sits on the edge the sheet is dragged towards. */}\n {side === \"bottom\" && <Drawer.Handle />}\n <Drawer.Header>\n <Drawer.Title>{title}</Drawer.Title>\n <Drawer.CloseButton label={closeLabel} />\n </Drawer.Header>\n <Drawer.Content>\n {description != null && (\n <Drawer.Description data-last={children == null || undefined}>\n {description}\n </Drawer.Description>\n )}\n {children}\n </Drawer.Content>\n {side === \"top\" && <Drawer.Handle />}\n </Drawer.Popup>\n </Drawer.Viewport>\n </Drawer.Portal>\n </Drawer.Root>\n );\n}\n","/*\n * Design tokens come from src/theme/tokens.css, generated from src/theme/tokens\n * by `pnpm tokens:css`. It is a plain stylesheet rather than runtime-injected\n * CSS variables, so this component renders correctly without a provider.\n *\n * The track, the min / max row and the helper text are styled in\n * slider-parts.module.css, which `Slider` shares.\n */\n\n.AmountSlider {\n display: flex;\n width: 100%;\n flex-direction: column;\n color: var(--lea-palette-text-base);\n font-size: var(--lea-text-body-md-font-size);\n font-weight: var(--lea-text-body-md-font-weight);\n line-height: var(--lea-text-body-md-line-height);\n letter-spacing: var(--lea-text-body-md-letter-spacing);\n}\n\n.Label {\n margin-block-end: calc(var(--lea-spacing) * 1.5);\n font-size: var(--lea-text-heading-md-font-size);\n font-weight: var(--lea-text-heading-md-font-weight);\n line-height: var(--lea-text-heading-md-line-height);\n letter-spacing: var(--lea-text-heading-md-letter-spacing);\n text-align: center;\n}\n\n/* The same box as the library's other fields: their height, radius and border. */\n.Input {\n width: 100%;\n /* 54px, the height of every other single-line field. */\n height: calc(var(--lea-spacing) * 7);\n box-sizing: border-box;\n padding-block: 0;\n padding-inline: calc(var(--lea-spacing) * 2);\n border: 1px solid transparent;\n border-radius: var(--lea-radius-xl);\n margin: 0;\n background-color: transparent;\n color: var(--lea-palette-primary-base);\n font-family: inherit;\n /* No text style has this size at medium weight, so the size alone. */\n font-size: var(--lea-font-step-8);\n font-variant-numeric: tabular-nums;\n font-weight: var(--lea-font-weight-medium);\n text-align: center;\n}\n\n/*\n * The 2px border of a state is drawn as an inset outline over the 1px one, so\n * the field never changes size between states.\n */\n@media (hover: hover) {\n .Input:hover:not(:focus, [data-disabled], [data-invalid]) {\n outline: 2px solid var(--lea-palette-border-strong);\n outline-offset: -2px;\n }\n}\n\n.Input:focus {\n outline: 2px solid var(--lea-palette-border-accent);\n outline-offset: -2px;\n}\n\n.Input:active {\n outline: 2px solid var(--lea-palette-border-accent);\n outline-offset: -2px;\n background-color: var(--lea-color-purple-50);\n}\n\n.Input[data-invalid] {\n outline: 2px solid var(--lea-palette-status-error-base);\n outline-offset: -2px;\n}\n\n.Input[data-disabled] {\n cursor: not-allowed;\n opacity: 0.5;\n}\n\n.Slider {\n display: flex;\n flex-direction: column;\n margin-block-start: var(--lea-spacing);\n}\n","/*\n * Design tokens come from src/theme/tokens.css, generated from src/theme/tokens\n * by `pnpm tokens:css`. It is a plain stylesheet rather than runtime-injected\n * CSS variables, so these parts render correctly without a provider.\n */\n\n.Control {\n --slider-thumb-size: calc(var(--lea-spacing) * 3);\n /* The same thickness as the LinearFormStepper bar. */\n --slider-track-size: calc(var(--lea-spacing) * 0.75);\n /*\n * Base UI centres the thumb on the value, so at min and max half of it\n * hangs past the control. The control is inset by that half to keep the\n * thumb inside the slider's own box.\n */\n --slider-inset: calc(var(--slider-thumb-size) / 2);\n --slider-thumb-hover: color-mix(\n in srgb,\n var(--lea-palette-primary-base) calc(var(--lea-opacity-hover) * 100%),\n var(--lea-palette-bg-base)\n );\n --slider-thumb-pressed: color-mix(\n in srgb,\n var(--lea-palette-primary-base) calc(var(--lea-opacity-pressed) * 100%),\n var(--lea-palette-bg-base)\n );\n\n position: relative;\n display: flex;\n /* Taller than the thumb, so the touch target is 44px. */\n height: calc(var(--lea-spacing) * 5.5);\n align-items: center;\n margin-inline: var(--slider-inset);\n cursor: pointer;\n touch-action: none;\n}\n\n/* Keeps the rounded ends of the track, which sit in the inset, clickable. */\n.Control::before {\n position: absolute;\n content: \"\";\n inset-block: 0;\n inset-inline: calc(var(--slider-inset) * -1);\n}\n\n.Control[data-disabled] {\n cursor: not-allowed;\n opacity: 0.5;\n}\n\n.Track {\n position: relative;\n width: 100%;\n height: var(--slider-track-size);\n}\n\n/*\n * The visible rail runs the full width of the slider, past the control.\n * purple-200 rather than purple-subtle, which is the same colour as the\n * bg-accent surface and would make the rail disappear on it.\n */\n.Track::before {\n position: absolute;\n border-radius: var(--lea-radius-full);\n background-color: var(--lea-color-purple-200);\n content: \"\";\n inset-block: 0;\n inset-inline: calc(var(--slider-inset) * -1);\n}\n\n.Indicator {\n background-color: var(--lea-palette-primary-base);\n}\n\n/* Fills the rounded start of the rail, which lies before the control. */\n.Indicator::before {\n position: absolute;\n width: var(--slider-inset);\n background-color: inherit;\n border-end-start-radius: var(--lea-radius-full);\n border-start-start-radius: var(--lea-radius-full);\n content: \"\";\n inset-block: 0;\n inset-inline-end: 100%;\n}\n\n.Thumb {\n width: var(--slider-thumb-size);\n height: var(--slider-thumb-size);\n box-sizing: border-box;\n border: 2px solid var(--lea-palette-primary-base);\n border-radius: var(--lea-radius-full);\n background-color: var(--lea-palette-bg-base);\n transition: background-color var(--lea-duration-normal)\n var(--lea-easing-standard);\n}\n\n@media (hover: hover) {\n .Thumb:not([data-disabled]):hover {\n background-color: var(--slider-thumb-hover);\n }\n}\n\n.Thumb[data-dragging]:not([data-disabled]) {\n background-color: var(--slider-thumb-pressed);\n}\n\n/* Focus lands on the visually hidden range input inside the thumb. */\n.Thumb:has(:focus-visible) {\n outline: 2px solid var(--lea-palette-text-base);\n outline-offset: 0.125rem;\n}\n\n/*\n * neutral-600 rather than text-subtle for the secondary text: a slider has no\n * background of its own, and text-subtle falls below 4.5:1 on the tinted\n * surfaces it can sit on.\n */\n.Range {\n display: flex;\n justify-content: space-between;\n gap: calc(var(--lea-spacing) * 2);\n color: var(--lea-color-neutral-600);\n font-size: var(--lea-text-body-sm-font-size);\n font-weight: var(--lea-text-body-sm-font-weight);\n line-height: var(--lea-text-body-sm-line-height);\n letter-spacing: var(--lea-text-body-sm-letter-spacing);\n font-variant-numeric: tabular-nums;\n}\n\n.HelperText {\n margin: 0;\n margin-block-start: var(--lea-spacing);\n color: var(--lea-color-neutral-600);\n font-size: var(--lea-text-body-sm-font-size);\n font-weight: var(--lea-text-body-sm-font-weight);\n line-height: var(--lea-text-body-sm-line-height);\n letter-spacing: var(--lea-text-body-sm-letter-spacing);\n}\n\n.HelperText[data-invalid] {\n color: var(--lea-palette-status-error-base);\n}\n\n@media (prefers-reduced-motion: reduce) {\n .Thumb {\n transition-duration: 0.01ms;\n }\n}\n","\"use client\";\n\nimport { Field } from \"@base-ui/react/field\";\nimport { Slider as BaseSlider } from \"@base-ui/react/slider\";\nimport { useMemo, type ReactNode } from \"react\";\n\nimport styles from \"./slider-parts.module.css\";\n\n/*\n * Internal parts shared by `Slider` and `AmountSlider`, so the track, the\n * min / max row and the helper text look and behave the same in both. Not\n * part of the public API, so this file isn't re-exported from `index.ts`.\n */\n\n/**\n * `render` for a `Field.Root` that is only there to hand a control its\n * validity state, which is how Base UI puts `aria-invalid` on the slider's\n * nested range input. It makes the field render no element of its own.\n */\nexport const renderWithoutElement: Field.Root.Props[\"render\"] = (props) => (\n <>{props.children}</>\n);\n\ntype SliderTrackProps = {\n \"aria-label\"?: string;\n \"aria-describedby\"?: string;\n};\n\n/**\n * The clickable control with its track, fill and thumb. The thumb is rendered\n * here so it can never be left out. Must sit inside a Base UI `Slider.Root`.\n */\nexport function SliderTrack({\n \"aria-label\": ariaLabel,\n \"aria-describedby\": ariaDescribedBy,\n}: SliderTrackProps) {\n return (\n <BaseSlider.Control className={styles.Control}>\n <BaseSlider.Track className={styles.Track}>\n <BaseSlider.Indicator className={styles.Indicator} />\n <BaseSlider.Thumb\n className={styles.Thumb}\n aria-label={ariaLabel}\n aria-describedby={ariaDescribedBy}\n />\n </BaseSlider.Track>\n </BaseSlider.Control>\n );\n}\n\ntype SliderRangeProps = {\n min: number;\n max: number;\n format?: Intl.NumberFormatOptions;\n locale?: Intl.LocalesArgument;\n};\n\n/** `min` and `max` under each end of the track, written like the value. */\nexport function SliderRange({ min, max, format, locale }: SliderRangeProps) {\n const formatter = useMemo(\n () => new Intl.NumberFormat(locale, format),\n [locale, format],\n );\n\n return (\n // The range input already exposes its bounds, so these are visual only.\n <div className={styles.Range} aria-hidden>\n <span>{formatter.format(min)}</span>\n <span>{formatter.format(max)}</span>\n </div>\n );\n}\n\ntype SliderHelperTextProps = {\n /** Id the controls point at with `aria-describedby`. */\n id: string;\n error: boolean;\n children: ReactNode;\n};\n\n/** Helper text below the slider. Announced as an alert while in error. */\nexport function SliderHelperText({\n id,\n error,\n children,\n}: SliderHelperTextProps) {\n return (\n <p\n id={id}\n className={styles.HelperText}\n data-invalid={error ? \"\" : undefined}\n role={error ? \"alert\" : undefined}\n >\n {children}\n </p>\n );\n}\n","\"use client\";\n\nimport { Field } from \"@base-ui/react/field\";\nimport { NumberField } from \"@base-ui/react/number-field\";\nimport { Slider as BaseSlider } from \"@base-ui/react/slider\";\nimport {\n useId,\n useState,\n type ComponentPropsWithRef,\n type ReactNode,\n} from \"react\";\n\nimport styles from \"./amount-slider.module.css\";\nimport {\n renderWithoutElement,\n SliderHelperText,\n SliderRange,\n SliderTrack,\n} from \"./slider-parts\";\n\nexport type AmountSliderProps = Omit<\n ComponentPropsWithRef<\"div\">,\n \"children\" | \"defaultValue\" | \"onChange\"\n> & {\n /**\n * The question above the amount, e.g. \"Hur mycket vill du låna?\". It labels\n * the amount field and names the slider, so it is required.\n */\n label: ReactNode;\n /** The lowest amount that can be chosen. */\n min: number;\n /** The highest amount that can be chosen. */\n max: number;\n /**\n * How far the slider, and the arrow keys in the amount field, move the\n * amount. A typed amount is kept as typed, also between two steps.\n * @default 1\n */\n step?: number;\n /** The amount. Use with `onValueChange` to control the component. */\n value?: number;\n /**\n * The amount when first rendered, for uncontrolled use.\n * @default min\n */\n defaultValue?: number;\n /**\n * Called with the new amount when the slider moves, and when an amount\n * within `min` and `max` is typed.\n */\n onValueChange?: (value: number) => void;\n /** How the amount, `min` and `max` are written, e.g. as a currency. */\n format?: Intl.NumberFormatOptions;\n /** The locale the amount is written and typed in. Defaults to the runtime locale. */\n locale?: Intl.LocalesArgument;\n /** Submits the amount under this name when inside a form. */\n name?: string;\n /** Disables both the amount field and the slider. */\n disabled?: boolean;\n /** Helper / error text shown below the slider and linked via `aria-describedby`. */\n helperText?: ReactNode;\n /** Puts the amount field, the slider and the helper text into the error state. */\n error?: boolean;\n};\n\n/**\n * An amount chosen by dragging a slider or by typing it, for questions like\n * \"how much do you want to borrow?\". The amount field and the slider share one\n * value: moving the slider rewrites the amount, and typing moves the thumb.\n *\n * The `label` is a real `<label>` for the amount field and also names the\n * slider, and the helper text describes both. A typed amount outside `min`\n * and `max` is brought back into range when the field loses focus, and an\n * emptied field goes back to the last amount.\n *\n * Use `Slider` instead when the value does not need to be typed.\n *\n * ```tsx\n * <AmountSlider\n * label=\"Hur mycket vill du låna?\"\n * min={20000}\n * max={600000}\n * step={5000}\n * defaultValue={200000}\n * locale=\"sv-SE\"\n * format={{ style: \"currency\", currency: \"SEK\", maximumFractionDigits: 0 }}\n * onValueChange={(amount) => setAmount(amount)}\n * />\n * ```\n */\nexport function AmountSlider({\n label,\n min,\n max,\n step = 1,\n value: valueProp,\n defaultValue,\n onValueChange,\n format,\n locale,\n name,\n disabled = false,\n helperText,\n error = false,\n className,\n ...rest\n}: AmountSliderProps) {\n const labelId = useId();\n const inputId = useId();\n const helperTextId = useId();\n const describedBy = helperText != null ? helperTextId : undefined;\n\n const [uncontrolledValue, setUncontrolledValue] = useState(\n defaultValue ?? min,\n );\n const value = valueProp ?? uncontrolledValue;\n\n // What the amount field holds while it differs from the amount: nothing, or\n // a number outside the range that hasn't been brought back in yet.\n // `undefined` means the field simply shows the amount.\n const [draft, setDraft] = useState<number | null>();\n\n const commit = (next: number) => {\n setDraft(undefined);\n if (valueProp === undefined) setUncontrolledValue(next);\n if (next !== value) onValueChange?.(next);\n };\n\n return (\n <div\n {...rest}\n className={[styles.AmountSlider, className].filter(Boolean).join(\" \")}\n >\n <label id={labelId} htmlFor={inputId} className={styles.Label}>\n {label}\n </label>\n {/*\n * The number field stays outside the slider's `Field.Root`: inside one,\n * Base UI gives the input the field's own id until after mount, which\n * leaves the label pointing at nothing on the server.\n */}\n <NumberField.Root\n id={inputId}\n name={name}\n value={draft !== undefined ? draft : value}\n // Base UI would otherwise clamp on every keystroke, sending the\n // slider to `min` on the first digit of a longer amount. The amount\n // is clamped here instead, once the field loses focus.\n allowOutOfRange\n onValueChange={(next) => {\n if (next != null && next >= min && next <= max) commit(next);\n else setDraft(next);\n }}\n onValueCommitted={(next) => {\n if (next == null) setDraft(undefined);\n else commit(Math.min(Math.max(next, min), max));\n }}\n min={min}\n max={max}\n step={step}\n format={format}\n locale={locale}\n disabled={disabled}\n >\n <NumberField.Input\n className={styles.Input}\n aria-describedby={describedBy}\n aria-invalid={error || undefined}\n data-invalid={error ? \"\" : undefined}\n />\n </NumberField.Root>\n <Field.Root invalid={error} render={renderWithoutElement}>\n <BaseSlider.Root\n value={value}\n onValueChange={commit}\n min={min}\n max={max}\n step={step}\n format={format}\n locale={locale}\n disabled={disabled}\n aria-labelledby={labelId}\n className={styles.Slider}\n >\n <SliderTrack aria-describedby={describedBy} />\n <SliderRange min={min} max={max} format={format} locale={locale} />\n </BaseSlider.Root>\n </Field.Root>\n {helperText != null && (\n <SliderHelperText id={helperTextId} error={error}>\n {helperText}\n </SliderHelperText>\n )}\n </div>\n );\n}\n","/*\n * Design tokens come from src/theme/tokens.css, generated from src/theme/tokens\n * by `pnpm tokens:css`. It is a plain stylesheet rather than runtime-injected\n * CSS variables, so this component renders correctly without a provider.\n *\n * Shared by Autocomplete and EmailInput. The box, its border states, the\n * label and the text field come from input.module.css, and the list from\n * option-list.module.css; this file adds the buttons at the end of the field\n * and the chips of a multiple control.\n */\n\n/*\n * `.Field` in front of a selector lifts it over the rules of input.module.css\n * for the same element, whichever of the two stylesheets loads last.\n */\n.Field .Box {\n /* White, where Input shows the surface it sits on. As it always was. */\n background-color: var(--lea-palette-bg-base);\n}\n\n/* The field and its open list read as one shape: square where they meet. */\n.Box[data-popup-side=\"bottom\"] {\n border-end-end-radius: 0;\n border-end-start-radius: 0;\n}\n\n.Box[data-popup-side=\"top\"] {\n border-start-end-radius: 0;\n border-start-start-radius: 0;\n}\n\n/* The buttons follow the text, so it runs up to them. */\n.Field .Inner:not(:last-child) .Control {\n padding-inline-end: var(--lea-spacing-0-5);\n}\n\n/* A multiple control has a value when it has chips, whatever the input holds. */\n.Field .Box[data-filled] .Label {\n max-width: calc(\n (100% - var(--input-inset-start) - var(--input-padding-inline)) / 0.75\n );\n scale: 0.75;\n translate: 0 calc(var(--lea-spacing) * 0.75);\n}\n\n.Buttons {\n display: flex;\n flex-shrink: 0;\n align-items: center;\n align-self: center;\n /* The arrow itself ends 14px from the edge, where the text of a field starts. */\n margin-inline-end: calc(var(--lea-spacing) * 1.25);\n}\n\n.Button {\n display: inline-flex;\n width: 1.75rem;\n height: 1.75rem;\n align-items: center;\n justify-content: center;\n padding: 0;\n border: 0;\n border-radius: var(--lea-radius-full);\n background: none;\n color: var(--lea-palette-text-base);\n cursor: pointer;\n font: inherit;\n}\n\n.Button:disabled,\n.Button[data-disabled] {\n color: var(--lea-palette-text-muted);\n cursor: not-allowed;\n}\n\n/* Out of the tab order, so only reachable by a script; shown all the same. */\n.Button:focus-visible {\n outline: 2px solid var(--lea-palette-text-base);\n outline-offset: 0.125rem;\n}\n\n.Trigger svg {\n width: 1.25rem;\n height: 1.25rem;\n transition: rotate var(--lea-duration-normal) var(--lea-easing-standard);\n}\n\n.Trigger[data-popup-open] svg {\n rotate: 180deg;\n}\n\n.Clear svg {\n width: 1.125rem;\n height: 1.125rem;\n}\n\n/*\n * With a mouse, the clear button waits for the pointer or for focus, so a\n * form at rest is not a column of crosses. A touch screen has neither, and\n * shows it whenever there is something to clear.\n */\n@media (pointer: fine) {\n .Box:not(:hover, :focus-within) .Clear {\n visibility: hidden;\n }\n}\n\n.Box[data-disabled] .Clear {\n display: none;\n}\n\n/* The chips of a multiple control, and its input after them. */\n.Chips {\n display: flex;\n min-width: 0;\n flex: 1;\n flex-wrap: wrap;\n align-items: center;\n padding-inline: var(--input-inset-start) var(--lea-spacing-0-5);\n padding-block: var(--input-padding-top) calc(var(--lea-spacing) * 0.75);\n gap: var(--lea-spacing-0-5);\n}\n\n.ChipInput {\n /* Shares the last line of chips while 4rem is left on it, then takes a line of its own. */\n min-width: 4rem;\n flex: 1;\n padding: 0;\n padding-inline-start: var(--lea-spacing-0-5);\n border: 0;\n margin: 0;\n background: none;\n color: inherit;\n font: inherit;\n letter-spacing: inherit;\n outline: none;\n}\n\n.ChipInput:disabled {\n cursor: not-allowed;\n opacity: 1;\n /* Safari dims disabled text on top of the colour set here. */\n -webkit-text-fill-color: currentcolor;\n}\n\n.ChipInput::placeholder {\n color: var(--lea-palette-text-muted);\n opacity: 1;\n}\n\n/* While the label rests over the field the placeholder is hidden, so the two never overlap. */\n.Box[data-has-label]:not(:focus-within, [data-filled]) .ChipInput::placeholder {\n color: transparent;\n}\n\n/*\n * The list fades in, and goes at once. While a list is on its way out, Base UI\n * keeps showing the options of the text it was closed with; a key pressed in\n * that time brought the list back with those, not with what was typed.\n */\n.Popup[data-ending-style] {\n transition: none;\n}\n\n@media (prefers-reduced-motion: reduce) {\n .Trigger svg {\n transition-duration: 0.01ms;\n }\n}\n","/*\n * Design tokens come from src/theme/tokens.css, generated from src/theme/tokens\n * by `pnpm tokens:css`. It is a plain stylesheet rather than runtime-injected\n * CSS variables, so these parts render correctly without a provider.\n *\n * The sizes and distances match the label and helper text of the fields that\n * are still built on MUI, so the two sit side by side in a form without a\n * visible seam.\n */\n\n.GroupLabel {\n display: inline-flex;\n width: fit-content;\n align-items: center;\n padding-block-end: var(--lea-spacing-1-5);\n margin: 0;\n color: var(--lea-palette-text-base);\n font-size: var(--lea-text-label-lg-font-size);\n font-weight: var(--lea-text-label-lg-font-weight);\n gap: var(--lea-spacing-1);\n letter-spacing: var(--lea-text-label-lg-letter-spacing);\n line-height: var(--lea-text-label-lg-line-height);\n}\n\n.GroupLabel[data-invalid] {\n color: var(--lea-palette-status-error-base);\n}\n\n.GroupLabel[data-disabled] {\n color: var(--lea-palette-text-muted);\n}\n\n.HelperText {\n /* 14px, where the text inside a field starts. */\n margin-inline: calc(var(--lea-spacing) * 1.75);\n margin-block: var(--lea-spacing-0-5) 0;\n /*\n * neutral-600 rather than text-subtle: these controls have no background of\n * their own, and text-subtle falls below 4.5:1 on the tinted surfaces they\n * can sit on.\n */\n color: var(--lea-color-neutral-600);\n font-size: var(--lea-text-body-sm-font-size);\n font-weight: var(--lea-text-body-sm-font-weight);\n letter-spacing: var(--lea-text-body-sm-letter-spacing);\n line-height: var(--lea-text-body-sm-line-height);\n}\n\n.HelperText[data-invalid] {\n color: var(--lea-palette-status-error-base);\n}\n\n/*\n * A value that is allowed but unusual. amber-700, not the warning base, which\n * is 2:1 on white: amber-700 is 5.9:1. It colours the text only; the field\n * keeps its border, because the value is valid.\n */\n.HelperText[data-warning] {\n color: var(--lea-color-amber-700);\n}\n","import { createTranslation } from \"../../i18n\";\n\n/**\n * Translated accessible name for the info trigger a control renders next to\n * its label when given a `tooltip`.\n */\nexport const useTooltipTriggerLabels = createTranslation({\n moreInformation: {\n no: \"Mer informasjon\",\n se: \"Mer information\",\n fi: \"Lisätietoja\",\n es: \"Más información\",\n },\n});\n","\"use client\";\n\nimport { InfoIcon } from \"lucide-react\";\nimport type { ReactNode } from \"react\";\n\nimport { Tooltip } from \"../data-display\";\nimport styles from \"./field-parts.module.css\";\nimport { useTooltipTriggerLabels } from \"./use-tooltip-trigger-labels\";\n\n/*\n * Internal parts shared by the form controls that no longer wrap MUI\n * (`Input`, `Checkbox`, the radio groups), so their label, asterisk and helper\n * text look and behave the same. Not part of the public API, so this file\n * isn't re-exported from `index.ts`.\n *\n * Each control generates its own ids with `useId` and hands them to these\n * parts, so every link (`aria-labelledby`, `aria-describedby`) is already in\n * the markup the server sends.\n */\n\n/** The ` *` after the label of a required control. Decorative: `required` is on the control. */\nexport const RequiredAsterisk = ({ className }: { className?: string }) => (\n <span aria-hidden className={className}>\n {\"\\u2009*\"}\n </span>\n);\n\ntype FieldHelperTextProps = {\n /** Id the control points at with `aria-describedby`. */\n id: string;\n error: boolean;\n /** The text is a warning: amber, and announced politely. */\n warning?: boolean;\n children: ReactNode;\n};\n\n/**\n * Helper text below a control. Announced as an alert while in error, and as a\n * status while it is a warning.\n */\nexport function FieldHelperText({\n id,\n error,\n warning = false,\n children,\n}: FieldHelperTextProps) {\n return (\n <p\n id={id}\n className={styles.HelperText}\n data-invalid={error ? \"\" : undefined}\n data-warning={warning && !error ? \"\" : undefined}\n role={error ? \"alert\" : warning ? \"status\" : undefined}\n >\n {children}\n </p>\n );\n}\n\n/**\n * What the line below a control shows: the warning while there is one,\n * otherwise the helper text. An error wins over a warning, so with `error`\n * the line is the helper text (where a form puts its error message).\n */\nexport function fieldMessage(\n helperText: ReactNode,\n warning: ReactNode,\n error: boolean,\n): { content: ReactNode; warning: boolean } {\n const showWarning =\n !error && warning != null && warning !== false && warning !== \"\";\n return { content: showWarning ? warning : helperText, warning: showWarning };\n}\n\ntype FieldGroupLabelProps = {\n /** Id the group points at with `aria-labelledby`. It sits on the text alone. */\n id: string;\n /**\n * Id of a single control this labels. The text is then a real `<label>`, so\n * a click on it moves focus to the control.\n */\n htmlFor?: string;\n /** Help text behind an info button next to the label. */\n tooltip?: ReactNode;\n required?: boolean;\n error?: boolean;\n disabled?: boolean;\n children: ReactNode;\n};\n\n/**\n * The label above a group of choices, or above a field whose label sits\n * outside it. The element is not a `<label>`: it names its control through\n * `aria-labelledby`, and a `<label>` around the info button would pass clicks\n * on the text to that button. With `htmlFor`, the text alone is a `<label>`.\n */\nexport function FieldGroupLabel({\n id,\n htmlFor,\n tooltip,\n required,\n error,\n disabled,\n children,\n}: FieldGroupLabelProps) {\n const labels = useTooltipTriggerLabels();\n const hasTooltip = tooltip != null && tooltip !== false;\n\n return (\n <div\n className={styles.GroupLabel}\n data-invalid={error ? \"\" : undefined}\n data-disabled={disabled ? \"\" : undefined}\n >\n {/* One part of the row, so the asterisk follows the text by its own\n thin space and stays on the last line when the text wraps. */}\n <span>\n {htmlFor != null ? (\n <label id={id} htmlFor={htmlFor}>\n {children}\n </label>\n ) : (\n <span id={id}>{children}</span>\n )}\n {required && <RequiredAsterisk />}\n </span>\n {hasTooltip && (\n <Tooltip\n title={tooltip}\n ariaLabel={labels.moreInformation}\n triggerIcon={<InfoIcon size={16} aria-hidden />}\n // The colour of the label, in every state of the button.\n style={{ color: \"inherit\" }}\n />\n )}\n </div>\n );\n}\n","/*\n * Design tokens come from src/theme/tokens.css, generated from src/theme/tokens\n * by `pnpm tokens:css`. It is a plain stylesheet rather than runtime-injected\n * CSS variables, so this component renders correctly without a provider.\n *\n * The box, the floating label and the distances match the fields that are\n * still built on MUI (`Select`, `Autocomplete`, the date picker), so an\n * `Input` next to one of them lines up.\n */\n\n.Field {\n position: relative;\n display: flex;\n width: 100%;\n min-width: 0;\n flex-direction: column;\n}\n\n.Box {\n /* 54px, the height of every single-line field. */\n --input-height: calc(var(--lea-spacing) * 6.75);\n /* 14px, where the other fields start their text. */\n --input-padding-inline: calc(var(--lea-spacing) * 1.75);\n /* Room above the value for the floated label. */\n --input-padding-top: var(--lea-spacing-3);\n --input-border-color: var(--lea-color-neutral-300);\n --input-border-width: 1px;\n\n position: relative;\n display: flex;\n min-height: var(--input-height);\n box-sizing: border-box;\n border-radius: var(--lea-radius-xl);\n color: var(--lea-palette-text-base);\n cursor: text;\n font-size: var(--lea-text-body-md-font-size);\n font-weight: var(--lea-text-body-md-font-weight);\n letter-spacing: var(--lea-text-body-md-letter-spacing);\n line-height: var(--lea-text-body-md-line-height);\n}\n\n/*\n * The border is drawn over the box rather than on it, so going from 1px to\n * 2px in a state never moves what is inside.\n */\n.Box::after {\n position: absolute;\n border: var(--input-border-width) solid var(--input-border-color);\n border-radius: inherit;\n content: \"\";\n inset: 0;\n pointer-events: none;\n}\n\n@media (hover: hover) {\n .Box:hover:not(:focus-within, [data-disabled], [data-invalid]) {\n --input-border-color: var(--lea-palette-border-strong);\n --input-border-width: 2px;\n }\n}\n\n/* The border is the focus indicator: the input's own outline is taken off below. */\n.Box:focus-within {\n --input-border-color: var(--lea-palette-border-accent);\n --input-border-width: 2px;\n}\n\n.Box:active:not([data-disabled], [data-invalid]) {\n --input-border-color: var(--lea-palette-border-accent);\n --input-border-width: 2px;\n\n background-color: var(--lea-palette-bg-subtle);\n}\n\n/* After focus and active, so an invalid field stays red in every state. */\n.Box[data-invalid] {\n --input-border-color: var(--lea-palette-status-error-base);\n --input-border-width: 2px;\n}\n\n.Box[data-disabled] {\n color: var(--lea-palette-text-muted);\n cursor: not-allowed;\n}\n\n/* The label and the control share this cell, so the label follows an adornment of any width. */\n.Inner {\n --input-inset-start: var(--input-padding-inline);\n\n position: relative;\n display: flex;\n min-width: 0;\n flex: 1;\n}\n\n.Adornment[data-position=\"start\"] + .Inner {\n --input-inset-start: 0px;\n}\n\n.Control {\n width: 100%;\n min-width: 0;\n box-sizing: border-box;\n padding-block: var(--input-padding-top) calc(var(--lea-spacing) * 0.75);\n padding-inline: var(--input-inset-start) var(--input-padding-inline);\n border: 0;\n border-radius: inherit;\n margin: 0;\n background: none;\n color: inherit;\n font: inherit;\n letter-spacing: inherit;\n outline: none;\n}\n\n.Control:disabled {\n cursor: not-allowed;\n opacity: 1;\n /* Safari dims disabled text on top of the colour set here. */\n -webkit-text-fill-color: currentcolor;\n}\n\ntextarea.Control {\n display: block;\n resize: none;\n}\n\n.Control::placeholder {\n color: var(--lea-palette-text-muted);\n opacity: 1;\n}\n\n/* While the label rests over the field the placeholder is hidden, so the two never overlap. */\n.Box[data-has-label]:not(:focus-within) .Control::placeholder {\n color: transparent;\n}\n\n/* Keeps the browser's autofill tint off the field. */\n.Control:-webkit-autofill {\n box-shadow: 0 0 0 100px var(--lea-palette-bg-base) inset;\n caret-color: var(--lea-palette-text-base);\n -webkit-text-fill-color: var(--lea-palette-text-base);\n}\n\n.Label {\n position: absolute;\n z-index: 1;\n overflow: hidden;\n max-width: calc(\n 100% - var(--input-inset-start) - var(--input-padding-inline)\n );\n /*\n * neutral-600 rather than text-subtle: a field has no background of its\n * own, and text-subtle falls below 4.5:1 on the tinted surfaces it can sit on.\n */\n color: var(--lea-color-neutral-600);\n inset-block-start: 0;\n inset-inline-start: var(--input-inset-start);\n pointer-events: none;\n scale: 1;\n text-overflow: ellipsis;\n transform-origin: top left;\n /* Resting, the label is centred in a single-line field, where the value will be. */\n translate: 0\n calc((var(--input-height) - var(--lea-text-body-md-line-height) * 1em) / 2);\n transition: color var(--lea-duration-normal) var(--lea-easing-standard),\n scale var(--lea-duration-normal) var(--lea-easing-standard),\n translate var(--lea-duration-normal) var(--lea-easing-standard);\n white-space: nowrap;\n}\n\n/*\n * The label floats to the top of the field once there is something to make\n * room for: focus, or a value. `:placeholder-shown` is how CSS sees an empty\n * control, which is why the control always has a placeholder, if only a space.\n */\n.Box:focus-within .Label,\n.Inner:has(.Control:not(:placeholder-shown)) .Label {\n max-width: calc(\n (100% - var(--input-inset-start) - var(--input-padding-inline)) / 0.75\n );\n scale: 0.75;\n translate: 0 calc(var(--lea-spacing) * 0.75);\n}\n\n/* Separate rules: a browser that does not know a selector drops the whole list. */\n.Inner:has(.Control:-webkit-autofill) .Label {\n max-width: calc(\n (100% - var(--input-inset-start) - var(--input-padding-inline)) / 0.75\n );\n scale: 0.75;\n translate: 0 calc(var(--lea-spacing) * 0.75);\n}\n\n.Inner:has(.Control:autofill) .Label {\n max-width: calc(\n (100% - var(--input-inset-start) - var(--input-padding-inline)) / 0.75\n );\n scale: 0.75;\n translate: 0 calc(var(--lea-spacing) * 0.75);\n}\n\n.Box:focus-within .Label {\n color: var(--lea-palette-text-accent);\n}\n\n.Box[data-invalid] .Label {\n color: var(--lea-palette-status-error-base);\n}\n\n.Box[data-disabled] .Label {\n color: var(--lea-palette-text-muted);\n}\n\n.Adornment {\n display: flex;\n flex-shrink: 0;\n align-items: center;\n align-self: center;\n color: var(--lea-palette-text-subtle);\n white-space: nowrap;\n}\n\n.Adornment[data-position=\"start\"] {\n /*\n * The value sits low in the field to clear the floated label, so a centred\n * icon reads as too high next to it. The margin moves it down by half its\n * size, onto the text line.\n */\n margin-block-start: var(--lea-spacing-0-5);\n margin-inline: var(--lea-spacing-1-5) var(--lea-spacing-1);\n}\n\n.Adornment[data-position=\"end\"] {\n margin-inline: var(--lea-spacing-1) var(--input-padding-inline);\n}\n\n@media (prefers-reduced-motion: reduce) {\n .Label {\n transition-duration: 0.01ms;\n }\n}\n","/*\n * Design tokens come from src/theme/tokens.css, generated from src/theme/tokens\n * by `pnpm tokens:css`. It is a plain stylesheet rather than runtime-injected\n * CSS variables, so this component renders correctly without a provider.\n *\n * The list of options in a popup, shared by Select, MultiSelect, Autocomplete,\n * EmailInput and the country list of PhoneNumberInput.\n */\n\n/* Level with Dialog and Drawer (1300), and later in the page, so a list\n inside one of them opens above it. */\n.Positioner {\n z-index: 1300;\n outline: none;\n}\n\n.Popup {\n overflow: hidden auto;\n min-width: var(--anchor-width);\n max-width: var(--available-width);\n /*\n * 200px: five options, then it scrolls. Less when the window is short.\n * Base UI sets --available-height once it has placed the popup, and places\n * it by its size before that; the fallback keeps that first size at 200px,\n * so a long list is not sent above the field for want of room it has.\n */\n max-height: min(12.5rem, var(--available-height, 100vh));\n box-sizing: border-box;\n border: 1px solid var(--lea-palette-border-accent);\n border-radius: 0 0 var(--lea-radius-xl) var(--lea-radius-xl);\n background-color: var(--lea-palette-bg-base);\n box-shadow: var(--lea-shadow-lg);\n color: var(--lea-palette-text-base);\n outline: none;\n transition: opacity var(--lea-duration-fast) var(--lea-easing-standard);\n}\n\n.Popup[data-side=\"top\"] {\n border-radius: var(--lea-radius-xl) var(--lea-radius-xl) 0 0;\n}\n\n.Popup[data-starting-style],\n.Popup[data-ending-style] {\n opacity: 0;\n}\n\n.List {\n display: flex;\n flex-direction: column;\n padding: var(--lea-spacing-0-5);\n /* A hair between options, so two marked neighbours do not merge. */\n gap: calc(var(--lea-spacing) * 0.25);\n outline: none;\n}\n\n/* A list to search in can come up empty; `.Empty` then stands in for it. */\n.List[data-empty] {\n display: none;\n}\n\n.Item {\n --option-bg: transparent;\n\n display: flex;\n align-items: center;\n padding-block: var(--lea-spacing-1);\n padding-inline: var(--lea-spacing-2);\n border-radius: var(--lea-radius-md);\n background-color: var(--option-bg);\n cursor: pointer;\n font-size: var(--lea-text-body-md-font-size);\n font-weight: var(--lea-text-body-md-font-weight);\n gap: var(--lea-spacing-1);\n letter-spacing: var(--lea-text-body-md-letter-spacing);\n line-height: var(--lea-text-body-md-line-height);\n outline: none;\n user-select: none;\n}\n\n.ItemText {\n min-width: 0;\n flex: 1;\n}\n\n@media (hover: hover) {\n .Item:hover:not([data-disabled]) {\n --option-bg: var(--lea-palette-bg-subtle);\n }\n}\n\n/* After hover, so the chosen option keeps its fill under the pointer. */\n.Item[data-selected] {\n --option-bg: var(--lea-palette-bg-accent);\n}\n\n/*\n * The option the arrow keys are on: a shade over whatever fill it has. In a\n * select Base UI moves focus to that option, so `:focus-visible` shows it for\n * the keyboard and leaves the mouse its hover. In a combobox focus stays in\n * the text field and Base UI marks the option `data-highlighted` instead; the\n * popup carries `data-keyboard` while the keyboard is what is in use.\n */\n.Item:focus-visible,\n[data-keyboard] .Item[data-highlighted] {\n background-color: color-mix(\n in srgb,\n var(--lea-palette-text-base) calc(var(--lea-opacity-pressed) * 100%),\n var(--option-bg)\n );\n}\n\n.Item[data-disabled] {\n cursor: not-allowed;\n opacity: 0.38;\n}\n\n/* \"No options\" and \"Loading…\", where the options would be. */\n.Empty:not(:empty) {\n padding-block: calc(var(--lea-spacing) * 1.75);\n padding-inline: var(--lea-spacing-2);\n color: var(--lea-palette-text-subtle);\n font-size: var(--lea-text-body-md-font-size);\n font-weight: var(--lea-text-body-md-font-weight);\n letter-spacing: var(--lea-text-body-md-letter-spacing);\n line-height: var(--lea-text-body-md-line-height);\n}\n\n@media (prefers-reduced-motion: reduce) {\n .Popup {\n transition-duration: 0.01ms;\n }\n}\n","import { createTranslation } from \"../../i18n\";\n\n/**\n * Translated texts for the controls with a list to search in (`Autocomplete`\n * and `EmailInput`): what the list says when it has nothing to show, and the\n * names of the open and clear buttons.\n */\nexport const useAutocompleteLabels = createTranslation({\n noOptions: {\n no: \"Ingen alternativer\",\n se: \"Inga alternativ\",\n fi: \"Ei vaihtoehtoja\",\n es: \"Sin opciones\",\n },\n loading: {\n no: \"Laster…\",\n se: \"Laddar…\",\n fi: \"Ladataan…\",\n es: \"Cargando…\",\n },\n open: { no: \"Åpne\", se: \"Öppna\", fi: \"Avaa\", es: \"Abrir\" },\n close: { no: \"Lukk\", se: \"Stäng\", fi: \"Sulje\", es: \"Cerrar\" },\n clear: { no: \"Tøm\", se: \"Rensa\", fi: \"Tyhjennä\", es: \"Borrar\" },\n});\n","import type { FocusEvent, RefObject } from \"react\";\n\n/**\n * `onBlur` for a field that is made of several elements, some of them in a\n * popup: it is called once focus has left them all, not when it moves from\n * one to another. Put the returned handler on each element in `refs`.\n */\nexport function useBlurOutside(\n onBlur: ((event: FocusEvent<HTMLElement>) => void) | undefined,\n refs: readonly RefObject<HTMLElement | null>[],\n) {\n return (event: FocusEvent<HTMLElement>) => {\n if (!onBlur) return;\n // Focus is on its way somewhere; decide when it has arrived.\n window.setTimeout(() => {\n const active = document.activeElement;\n if (refs.some((ref) => ref.current?.contains(active))) return;\n onBlur(event);\n });\n };\n}\n","\"use client\";\n\nimport { Combobox } from \"@base-ui/react/combobox\";\nimport { ChevronDown, X } from \"lucide-react\";\nimport {\n useId,\n useRef,\n useState,\n type CSSProperties,\n type FocusEvent,\n type InputHTMLAttributes,\n type ReactNode,\n type Ref,\n} from \"react\";\n\nimport styles from \"./combo-field.module.css\";\nimport { FieldHelperText, fieldMessage, RequiredAsterisk } from \"./field-parts\";\nimport inputStyles from \"./input.module.css\";\nimport listStyles from \"./option-list.module.css\";\nimport { useAutocompleteLabels } from \"./use-autocomplete-labels\";\nimport { useBlurOutside } from \"./use-blur-outside\";\n\n/*\n * Internal. The field that `Autocomplete` and `EmailInput` share: the box and\n * the floating label of `Input` around a text field with the `combobox` role,\n * the clear and open buttons, and the list in a popup. Not part of the public\n * API, so this file isn't re-exported from `index.ts`.\n *\n * The parts are Base UI's combobox parts. Which root they sit in is up to the\n * caller (`Combobox.Root` to choose among options, `Autocomplete.Root` for\n * free text with suggestions), so the caller renders it through `renderRoot`.\n */\n\n/** The props `Autocomplete` and `EmailInput` have in common. */\nexport type ComboFieldBaseProps = {\n /** Floating label, linked to the input for you. */\n label?: ReactNode;\n /** Helper / error text shown below the control and linked via `aria-describedby`. */\n helperText?: ReactNode;\n /** Puts the control, its label and its helper text into the error state. */\n error?: boolean;\n /**\n * A message for a value that is allowed but unusual, such as an unusually\n * high amount. Shown in amber in place of the helper text, without the\n * error state: the field is not marked invalid. `error` wins when both are set.\n */\n warning?: ReactNode;\n /** Marks the control as required, with an asterisk after the label. */\n required?: boolean;\n disabled?: boolean;\n /**\n * Text shown while the input is empty. With a `label` it appears once the\n * label has floated up, on focus.\n */\n placeholder?: string;\n /** Called when focus leaves the control, its list included. */\n onBlur?: (event: FocusEvent<HTMLElement>) => void;\n /** Submits the value under this name in a native form. */\n name?: string;\n /** Id of the text `<input>`. */\n id?: string;\n /** Names the control when there is no visible `label`. */\n \"aria-label\"?: string;\n \"aria-labelledby\"?: string;\n \"aria-describedby\"?: string;\n /** Class on the outermost element, for layout. */\n className?: string;\n /** Inline style on the outermost element, for layout. */\n style?: CSSProperties;\n /** The text `<input>`. */\n ref?: Ref<HTMLInputElement>;\n};\n\ntype ComboFieldProps = Omit<ComboFieldBaseProps, \"name\"> & {\n /** Wraps the field and its popup in the Base UI root that drives them. */\n renderRoot: (children: ReactNode) => ReactNode;\n /** More attributes for the `<input>`: `type`, `name`, `autoComplete`, … */\n inputProps?: InputHTMLAttributes<HTMLInputElement>;\n /**\n * The chosen values of a multiple control, as `Combobox.Chip`s. They share\n * the field with the input and wrap onto new lines.\n */\n chips?: ReactNode;\n /** Whether a multiple control has values, which is what floats its label. */\n filled?: boolean;\n /** Shows the button that empties the control, while there is something to empty. */\n clearable?: boolean;\n /** Shows the arrow button that opens and closes the list. */\n trigger?: boolean;\n /**\n * Selects the text on the first click into the input, so that typing\n * replaces it. For a control whose text is the label of the chosen option.\n */\n selectTextOnClick?: boolean;\n /** The content of the popup: the list, and what stands in for it when empty. */\n children: ReactNode;\n /** More below the helper text, inside the outermost element. */\n afterHelperText?: ReactNode;\n};\n\nconst join = (...parts: (string | false | null | undefined)[]) =>\n parts.filter(Boolean).join(\" \") || undefined;\n\nexport function ComboField({\n label,\n helperText,\n error = false,\n warning,\n required = false,\n disabled = false,\n placeholder,\n onBlur,\n id,\n \"aria-label\": ariaLabel,\n \"aria-labelledby\": ariaLabelledBy,\n \"aria-describedby\": ariaDescribedBy,\n className,\n style,\n ref,\n renderRoot,\n inputProps,\n chips,\n filled = false,\n clearable = false,\n trigger = false,\n selectTextOnClick = false,\n children,\n afterHelperText,\n}: ComboFieldProps) {\n const labels = useAutocompleteLabels();\n const generatedId = useId();\n const inputId = id ?? generatedId;\n const labelId = useId();\n const helperTextId = useId();\n const hasLabel = label != null;\n const message = fieldMessage(helperText, warning, error);\n const hasHelperText = message.content != null;\n const multiple = chips !== undefined;\n\n const boxRef = useRef<HTMLDivElement>(null);\n const popupRef = useRef<HTMLDivElement>(null);\n const handleBlur = useBlurOutside(onBlur, [boxRef, popupRef]);\n\n // Focus stays in the input while the arrow keys move through the list, so\n // `:focus-visible` cannot tell which of the two is in use. This does: the\n // option the keys are on is only marked once a key has been pressed.\n const [keyboard, setKeyboard] = useState(false);\n\n // True from the moment the input takes focus until the click that gave it\n // focus has been handled.\n const firstClick = useRef(false);\n\n const input = (\n <Combobox.Input\n {...inputProps}\n ref={ref}\n id={inputId}\n disabled={disabled}\n required={required}\n // Never empty: `:placeholder-shown` is how the stylesheet tells an\n // empty input from a filled one, and it needs a placeholder to work.\n placeholder={placeholder || \" \"}\n aria-label={ariaLabel}\n // Base UI hides everything but the input and the list from assistive\n // tech while the list is open, the label included. A label that is\n // referred to by id still names the input then.\n aria-labelledby={ariaLabelledBy ?? (hasLabel ? labelId : undefined)}\n aria-invalid={error || undefined}\n aria-describedby={join(hasHelperText && helperTextId, ariaDescribedBy)}\n className={\n multiple ? styles.ChipInput : join(inputStyles.Control, styles.Control)\n }\n onFocus={() => {\n firstClick.current = true;\n }}\n onClick={(event) => {\n const element = event.currentTarget;\n if (\n selectTextOnClick &&\n firstClick.current &&\n element.selectionStart === element.selectionEnd\n )\n element.select();\n firstClick.current = false;\n }}\n onKeyDown={(event) => {\n // With the list closed, Base UI empties the control on Escape. Left\n // alone, the key keeps its meaning for what is around the control,\n // such as closing a dialog.\n if (\n event.key === \"Escape\" &&\n event.currentTarget.getAttribute(\"aria-expanded\") !== \"true\"\n )\n event.preventBaseUIHandler();\n }}\n />\n );\n\n return (\n <div\n className={join(inputStyles.Field, styles.Field, className)}\n style={style}\n >\n {renderRoot(\n <>\n <Combobox.InputGroup\n ref={boxRef}\n className={join(inputStyles.Box, styles.Box)}\n data-invalid={error ? \"\" : undefined}\n data-has-label={hasLabel ? \"\" : undefined}\n data-filled={filled ? \"\" : undefined}\n onBlur={handleBlur}\n onKeyDownCapture={() => setKeyboard(true)}\n onPointerDownCapture={() => setKeyboard(false)}\n >\n <div className={join(inputStyles.Inner, styles.Inner)}>\n {hasLabel && (\n <label\n id={labelId}\n htmlFor={inputId}\n className={join(inputStyles.Label, styles.Label)}\n >\n {label}\n {required && <RequiredAsterisk />}\n </label>\n )}\n {multiple ? (\n <Combobox.Chips className={styles.Chips}>\n {chips}\n {input}\n </Combobox.Chips>\n ) : (\n input\n )}\n </div>\n {(clearable || trigger) && (\n <div className={styles.Buttons}>\n {clearable && (\n <Combobox.Clear\n className={join(styles.Button, styles.Clear)}\n aria-label={labels.clear}\n // Out of the tab order, as the arrow is: the keyboard\n // empties the input by deleting its text.\n tabIndex={-1}\n >\n <X aria-hidden />\n </Combobox.Clear>\n )}\n {trigger && (\n <Combobox.Trigger\n className={join(styles.Button, styles.Trigger)}\n tabIndex={-1}\n // Until the input has mounted, Base UI takes this button\n // for the combobox itself and says so in the markup the\n // server sends. It is the arrow next to one.\n render={(props, state) => (\n <button\n {...props}\n role={undefined}\n aria-haspopup=\"listbox\"\n aria-required={undefined}\n aria-label={state.open ? labels.close : labels.open}\n />\n )}\n >\n <ChevronDown aria-hidden />\n </Combobox.Trigger>\n )}\n </div>\n )}\n </Combobox.InputGroup>\n <Combobox.Portal>\n <Combobox.Positioner\n anchor={boxRef}\n side=\"bottom\"\n align=\"start\"\n sideOffset={0}\n className={listStyles.Positioner}\n >\n <Combobox.Popup\n ref={popupRef}\n className={join(listStyles.Popup, styles.Popup)}\n data-keyboard={keyboard ? \"\" : undefined}\n onBlur={handleBlur}\n onPointerDownCapture={() => setKeyboard(false)}\n >\n {children}\n </Combobox.Popup>\n </Combobox.Positioner>\n </Combobox.Portal>\n </>,\n )}\n {hasHelperText && (\n <FieldHelperText\n id={helperTextId}\n error={error}\n warning={message.warning}\n >\n {message.content}\n </FieldHelperText>\n )}\n {afterHelperText}\n </div>\n );\n}\n","\"use client\";\n\nimport { Combobox } from \"@base-ui/react/combobox\";\nimport { CircleX } from \"lucide-react\";\nimport { useState, type ReactElement, type ReactNode } from \"react\";\n\nimport chipStyles from \"../data-display/chip.module.css\";\nimport { useChipLabels } from \"../data-display/use-chip-labels\";\nimport { ComboField, type ComboFieldBaseProps } from \"./combo-field\";\nimport listStyles from \"./option-list.module.css\";\nimport type { SelectOption } from \"./select-field\";\nimport { useAutocompleteLabels } from \"./use-autocomplete-labels\";\n\ntype AutocompleteBaseProps<Value extends string> = ComboFieldBaseProps & {\n /** The choices. Typing filters them by their label. */\n options: readonly SelectOption<Value>[];\n /** Shown in the list when nothing matches. Translated by default. */\n noOptionsText?: ReactNode;\n /**\n * Whether the options are on their way. While there are none to show, the\n * list says so instead of \"no options\".\n */\n loading?: boolean;\n};\n\ntype SingleValueProps<Value extends string> = {\n /** Choose several values, shown as chips. */\n multiple?: false;\n /** The chosen value (controlled). `\"\"` means nothing is chosen. */\n value?: Value | \"\";\n /** The chosen value when first rendered, for uncontrolled use. */\n defaultValue?: Value | \"\";\n /** Called with the chosen value, or `\"\"` when the control is emptied. */\n onValueChange?: (value: Value | \"\") => void;\n};\n\ntype MultipleValueProps<Value extends string> = {\n /** Choose several values, shown as chips. */\n multiple: true;\n /** The chosen values (controlled). */\n value?: Value[];\n /** The chosen values when first rendered, for uncontrolled use. */\n defaultValue?: Value[];\n /** Called with the next array of chosen values. */\n onValueChange?: (value: Value[]) => void;\n /** Fewest values that must stay chosen. @default 1 */\n min?: number;\n /** Most values that can be chosen. Unlimited when omitted. */\n max?: number;\n};\n\ntype AutocompleteSingleProps<Value extends string = string> =\n AutocompleteBaseProps<Value> & SingleValueProps<Value>;\n\ntype AutocompleteMultipleProps<Value extends string = string> =\n AutocompleteBaseProps<Value> & MultipleValueProps<Value>;\n\nexport type AutocompleteProps<Value extends string = string> =\n | AutocompleteSingleProps<Value>\n | AutocompleteMultipleProps<Value>;\n\nconst sameOption = (a: SelectOption, b: SelectOption) => a.value === b.value;\n\ntype OptionListProps = {\n noOptionsText?: ReactNode;\n loading?: boolean;\n /** Options that cannot be picked right now, on top of their own `disabled`. */\n isDisabled?: (option: SelectOption) => boolean;\n};\n\n/** The content of the popup: the options that match, or a line of text when none do. */\nfunction OptionList({ noOptionsText, loading, isDisabled }: OptionListProps) {\n const labels = useAutocompleteLabels();\n\n return (\n <>\n <Combobox.Empty className={listStyles.Empty}>\n {loading ? labels.loading : (noOptionsText ?? labels.noOptions)}\n </Combobox.Empty>\n <Combobox.List className={listStyles.List}>\n {(option: SelectOption) => (\n <Combobox.Item\n key={option.value}\n value={option}\n disabled={option.disabled || isDisabled?.(option)}\n className={listStyles.Item}\n >\n <span className={listStyles.ItemText}>{option.label}</span>\n </Combobox.Item>\n )}\n </Combobox.List>\n </>\n );\n}\n\nfunction SingleAutocomplete<Value extends string>({\n options,\n value,\n defaultValue = \"\",\n onValueChange,\n noOptionsText,\n loading,\n name,\n ...field\n}: AutocompleteSingleProps<Value>) {\n const isControlled = value !== undefined;\n const [internal, setInternal] = useState<Value | \"\">(defaultValue);\n const current = isControlled ? value : internal;\n\n const chosen = options.find((option) => option.value === current) ?? null;\n\n return (\n <ComboField\n {...field}\n clearable\n trigger\n selectTextOnClick\n renderRoot={(children) => (\n <Combobox.Root<SelectOption<Value>>\n items={options}\n value={chosen}\n onValueChange={(next) => {\n const nextValue = next?.value ?? \"\";\n if (nextValue === current) return;\n if (!isControlled) setInternal(nextValue);\n onValueChange?.(nextValue);\n }}\n isItemEqualToValue={sameOption}\n name={name}\n disabled={field.disabled}\n required={field.required}\n // The keyboard and the mouse each mark their own option, as in\n // `Select`: hovering does not move the option the arrow keys are on.\n highlightItemOnHover={false}\n >\n {children}\n </Combobox.Root>\n )}\n >\n <OptionList noOptionsText={noOptionsText} loading={loading} />\n </ComboField>\n );\n}\n\nfunction MultipleAutocomplete<Value extends string>({\n options,\n value,\n defaultValue = [],\n onValueChange,\n min = 1,\n max,\n noOptionsText,\n loading,\n name,\n multiple: _multiple,\n ...field\n}: AutocompleteMultipleProps<Value>) {\n const chipLabels = useChipLabels();\n const isControlled = value !== undefined;\n const [internal, setInternal] = useState<Value[]>(defaultValue);\n const selected = isControlled ? value : internal;\n // What is typed to filter the options. Held here to be emptied after a choice.\n const [query, setQuery] = useState(\"\");\n\n // In the order chosen, which is the order of the chips.\n const selectedOptions = selected\n .map((item) => options.find((option) => option.value === item))\n .filter((option) => option !== undefined);\n\n const atMax = max !== undefined && selected.length >= max;\n const atMin = selected.length <= min;\n const canRemove = !field.disabled && !atMin;\n\n return (\n <ComboField\n {...field}\n // Emptying the control would go below `min`, so the button is only\n // there when nothing has to stay chosen.\n clearable={min <= 0}\n trigger\n filled={selectedOptions.length > 0}\n chips={selectedOptions.map((option) => (\n <Combobox.Chip\n key={option.value}\n className={chipStyles.Chip}\n data-color=\"primary\"\n data-variant=\"filled\"\n data-size=\"sm\"\n >\n <span className={chipStyles.Label}>{option.label}</span>\n {canRemove && (\n <Combobox.ChipRemove\n className={chipStyles.Delete}\n aria-label={`${chipLabels.remove} ${option.label}`}\n >\n <CircleX aria-hidden />\n </Combobox.ChipRemove>\n )}\n </Combobox.Chip>\n ))}\n renderRoot={(children) => (\n <Combobox.Root<SelectOption<Value>, true>\n multiple\n items={options}\n value={selectedOptions}\n inputValue={query}\n onInputValueChange={setQuery}\n // A choice leaves the list open, to pick several in a row, and\n // empties the text that was typed to find it. Base UI closes the\n // list instead when there was such text, and a key pressed while it\n // closes brings it back with the options of the old text.\n onOpenChange={(open, details) => {\n if (!open && details.reason === \"item-press\") details.cancel();\n }}\n onValueChange={(next, details) => {\n if (details.reason === \"item-press\") setQuery(\"\");\n const nextValues = next.map((option) => option.value);\n // The options that would break a bound are disabled; this also\n // covers Backspace in the input, which removes the last chip.\n if (nextValues.length < min && nextValues.length < selected.length)\n return;\n if (\n max !== undefined &&\n nextValues.length > max &&\n nextValues.length > selected.length\n )\n return;\n if (!isControlled) setInternal(nextValues);\n onValueChange?.(nextValues);\n }}\n isItemEqualToValue={sameOption}\n name={name}\n disabled={field.disabled}\n required={field.required}\n highlightItemOnHover={false}\n >\n {children}\n </Combobox.Root>\n )}\n >\n <OptionList\n noOptionsText={noOptionsText}\n loading={loading}\n isDisabled={(option) => {\n const isSelected = selected.includes(option.value as Value);\n return (atMax && !isSelected) || (atMin && isSelected);\n }}\n />\n </ComboField>\n );\n}\n\n/**\n * A select to search in, on Base UI's `Combobox`, in the same box as `Input`.\n * Typing filters the options. The label, the helper text and the ids that\n * link them to the input are all rendered and wired for you.\n *\n * ```tsx\n * <Autocomplete\n * label=\"Land\"\n * options={[\n * { value: \"no\", label: \"Norge\" },\n * { value: \"se\", label: \"Sverige\" },\n * ]}\n * value={country}\n * onValueChange={setCountry}\n * />\n * ```\n *\n * Values are strings, typed from the options as in `Select`, and `\"\"` means\n * nothing is chosen. Pass `multiple` to choose several: they show as chips\n * inside the field, bounded by `min` (default 1) and `max`.\n *\n * For an email address with suggested domains, use `EmailInput`.\n */\n// A signature for each mode ahead of the one that takes either: TypeScript\n// then reads the type of the values from `options`, `value` and\n// `onValueChange` together, as it does for `Select` and `MultiSelect`. The\n// last one is for a wrapper that passes on props typed `AutocompleteProps`.\nexport function Autocomplete<Value extends string = string>(\n props: AutocompleteMultipleProps<Value>,\n): ReactElement;\nexport function Autocomplete<Value extends string = string>(\n props: AutocompleteSingleProps<Value>,\n): ReactElement;\nexport function Autocomplete<Value extends string = string>(\n props: AutocompleteProps<Value>,\n): ReactElement;\nexport function Autocomplete<Value extends string = string>(\n props: AutocompleteProps<Value>,\n) {\n return props.multiple ? (\n <MultipleAutocomplete {...props} />\n ) : (\n <SingleAutocomplete {...props} />\n );\n}\n","/*\n * Design tokens come from src/theme/tokens.css, generated from src/theme/tokens\n * by `pnpm tokens:css`. It is a plain stylesheet rather than runtime-injected\n * CSS variables, so this component renders correctly without a provider.\n */\n\n.Checkbox {\n display: flex;\n width: 100%;\n flex-direction: column;\n}\n\n.Box {\n display: inline-flex;\n width: 1.3rem;\n height: 1.3rem;\n box-sizing: border-box;\n flex-shrink: 0;\n align-items: center;\n justify-content: center;\n padding: 0;\n border: 2px solid var(--lea-palette-border-base);\n margin: 0;\n border-radius: var(--lea-radius-sm);\n background-color: var(--lea-palette-bg-base);\n /* The colour of the tick. */\n color: var(--lea-palette-primary-contrast);\n cursor: pointer;\n transition: background-color var(--lea-duration-normal)\n var(--lea-easing-standard),\n border-color var(--lea-duration-normal) var(--lea-easing-standard);\n}\n\n@media (hover: hover) {\n .Box:hover:not([data-checked], [data-disabled]) {\n border-color: var(--lea-palette-border-strong);\n }\n}\n\n.Box[data-checked] {\n border-color: var(--lea-palette-primary-base);\n background-color: var(--lea-palette-primary-base);\n}\n\n.Box:focus-visible {\n outline: 2px solid var(--lea-palette-text-base);\n outline-offset: 0.125rem;\n}\n\n.Box[data-disabled] {\n cursor: not-allowed;\n opacity: 0.7;\n}\n\n.Tick {\n display: block;\n width: 100%;\n height: 100%;\n}\n\n/* The tick starts undrawn: the gap in the dash covers the whole path. */\n.Tick path {\n stroke-dasharray: 1;\n stroke-dashoffset: 1;\n transition: stroke-dashoffset var(--lea-duration-emphasis)\n var(--lea-easing-spring);\n}\n\n.Box[data-checked] .Tick path {\n stroke-dashoffset: 0;\n}\n\n@media (prefers-reduced-motion: reduce) {\n .Box,\n .Tick path {\n transition-duration: 0.01ms;\n }\n}\n","import styles from \"./checkbox.module.css\";\n\n/** The tick. It is drawn in by a transition when its box becomes checked. */\nexport const checkboxTick = (\n <svg className={styles.Tick} viewBox=\"0 0 24 24\" aria-hidden>\n <path\n d=\"M5 12.5l4.5 4.5L19 7\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth={3}\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n pathLength={1}\n />\n </svg>\n);\n\n/**\n * Internal. The checkbox box as a picture only, for places where something\n * else is the control: `MultiSelect` shows it inside each option, and the\n * option is what gets picked. It looks exactly like `Checkbox`, which uses\n * the same class on the real control.\n */\nexport const CheckboxBox = ({ checked }: { checked: boolean }) => (\n <span\n className={styles.Box}\n data-checked={checked ? \"\" : undefined}\n aria-hidden\n >\n {checkboxTick}\n </span>\n);\n","/*\n * Design tokens come from src/theme/tokens.css, generated from src/theme/tokens\n * by `pnpm tokens:css`. It is a plain stylesheet rather than runtime-injected\n * CSS variables, so these parts render correctly without a provider.\n *\n * The row a `Checkbox` and a `RadioGroup.Item` share: the control, then its\n * label text.\n */\n\n.Row {\n display: flex;\n align-items: center;\n padding-block-end: var(--lea-spacing-1);\n margin: 0;\n color: var(--lea-palette-text-base);\n cursor: pointer;\n font-size: var(--lea-text-body-md-font-size);\n font-weight: var(--lea-text-body-md-font-weight);\n gap: var(--lea-spacing-1-5);\n letter-spacing: var(--lea-text-body-md-letter-spacing);\n line-height: var(--lea-text-body-md-line-height);\n}\n\n/* Base UI marks the control, whether it or its whole group is disabled. */\n.Row:has([data-disabled]) {\n color: var(--lea-palette-text-muted);\n cursor: not-allowed;\n}\n\n/* The asterisk keeps its error colour while the label text stays readable. */\n.Row[data-invalid] .Asterisk {\n color: var(--lea-palette-status-error-base);\n}\n\n.Text {\n min-width: 0;\n}\n","\"use client\";\n\nimport { Checkbox as BaseCheckbox } from \"@base-ui/react/checkbox\";\nimport {\n useId,\n type CSSProperties,\n type FocusEventHandler,\n type ReactNode,\n type Ref,\n} from \"react\";\n\nimport { checkboxTick } from \"./checkbox-box\";\nimport styles from \"./checkbox.module.css\";\nimport rowStyles from \"./choice-row.module.css\";\nimport { FieldHelperText, RequiredAsterisk } from \"./field-parts\";\n\n/**\n * Requires an accessible name so the checkbox is never nameless. Provide a\n * visible `label`, or an `aria-label` / `aria-labelledby` when the design has\n * none (a row in a table, say).\n */\ntype CheckboxAccessibleName =\n | { label: ReactNode; \"aria-label\"?: never; \"aria-labelledby\"?: never }\n | { label?: never; \"aria-label\": string; \"aria-labelledby\"?: never }\n | { label?: never; \"aria-label\"?: never; \"aria-labelledby\": string };\n\nexport type CheckboxProps = CheckboxAccessibleName & {\n /** Whether the box is ticked (controlled). Pair with `onCheckedChange`. */\n checked?: boolean;\n /** Whether the box is ticked when first rendered, for uncontrolled use. */\n defaultChecked?: boolean;\n /** Called with the new state when the box is ticked or cleared. */\n onCheckedChange?: (checked: boolean) => void;\n /** Helper / error text shown below the checkbox and linked via `aria-describedby`. */\n helperText?: ReactNode;\n /** Puts the checkbox and its helper text into the error state. */\n error?: boolean;\n /** Submits the checkbox under this name when inside a form. */\n name?: string;\n /** The value submitted when ticked. The browser default is `\"on\"`. */\n value?: string;\n /** Disables the checkbox. */\n disabled?: boolean;\n /** Marks the checkbox as required and adds the asterisk to the label. */\n required?: boolean;\n /** Id of the checkbox itself, the element with the `checkbox` role. */\n id?: string;\n onBlur?: FocusEventHandler<HTMLElement>;\n onFocus?: FocusEventHandler<HTMLElement>;\n /** Extra ids describing the checkbox, alongside the helper text. */\n \"aria-describedby\"?: string;\n /** Class on the outermost element, for layout. */\n className?: string;\n /** Inline style on the outermost element, for layout. */\n style?: CSSProperties;\n /**\n * The `<input type=\"checkbox\">` that holds the value. It is hidden, but\n * `ref.current.focus()` moves focus to the visible box.\n */\n ref?: Ref<HTMLInputElement>;\n};\n\nconst join = (...parts: (string | false | null | undefined)[]) =>\n parts.filter(Boolean).join(\" \") || undefined;\n\n/**\n * Checkbox with its label, helper text and error state built in, on Base UI's\n * accessible `Checkbox` primitive.\n *\n * Pass `label` for the text next to the box; it is a real `<label>`, so\n * clicking it ticks the box. Without a visible label, pass `aria-label`.\n * `className` and `style` go on the outermost element.\n *\n * ```tsx\n * <Checkbox\n * label=\"Jeg godtar vilkårene\"\n * checked={accepted}\n * onCheckedChange={setAccepted}\n * />\n * ```\n */\nexport function Checkbox({\n label,\n helperText,\n error = false,\n checked,\n defaultChecked,\n onCheckedChange,\n name,\n value,\n disabled = false,\n required = false,\n id,\n onBlur,\n onFocus,\n \"aria-label\": ariaLabel,\n \"aria-labelledby\": ariaLabelledBy,\n \"aria-describedby\": ariaDescribedBy,\n className,\n style,\n ref,\n}: CheckboxProps) {\n const helperTextId = useId();\n const hasLabel = label != null;\n const hasHelperText = helperText != null;\n const bare = !hasLabel && !hasHelperText;\n\n const box = (\n <BaseCheckbox.Root\n // A real `<button>`, so the `<label>` around it names it natively: in\n // the server markup, and as one element for `getByLabelText`.\n nativeButton\n render={<button type=\"button\" />}\n id={id}\n inputRef={ref}\n checked={checked}\n defaultChecked={defaultChecked}\n onCheckedChange={(next) => onCheckedChange?.(next)}\n name={name}\n value={value}\n disabled={disabled}\n required={required}\n onBlur={onBlur}\n onFocus={onFocus}\n aria-label={ariaLabel}\n aria-labelledby={ariaLabelledBy}\n aria-describedby={join(hasHelperText && helperTextId, ariaDescribedBy)}\n aria-invalid={error ? true : undefined}\n // Nothing to lay out around the box, so `className` and `style` land on it.\n className={bare ? join(styles.Box, className) : styles.Box}\n style={bare ? style : undefined}\n >\n {checkboxTick}\n </BaseCheckbox.Root>\n );\n\n if (bare) return box;\n\n return (\n <div className={join(styles.Checkbox, className)} style={style}>\n {hasLabel ? (\n <label className={rowStyles.Row} data-invalid={error ? \"\" : undefined}>\n {box}\n <span className={rowStyles.Text}>\n {label}\n {required && <RequiredAsterisk className={rowStyles.Asterisk} />}\n </span>\n </label>\n ) : (\n box\n )}\n {hasHelperText && (\n <FieldHelperText id={helperTextId} error={error}>\n {helperText}\n </FieldHelperText>\n )}\n </div>\n );\n}\n","// `Country` is owned by the hooks/country module and re-exported from the\n// package root via the hooks barrel. Validators import it from there directly so\n// the validation barrel does not produce an ambiguous duplicate `Country`\n// export at the package root.\n\n/**\n * Result of a validation check. `normalized` holds the canonical form of the\n * input (e.g. digits only, or E.164 phone) when the value is valid.\n */\nexport interface ValidationResult {\n valid: boolean;\n normalized?: string;\n}\n\nexport const invalid = (): ValidationResult => ({ valid: false });\n\nexport const valid = (normalized: string): ValidationResult => ({\n valid: true,\n normalized,\n});\n","import type { Country } from \"../hooks/country/countries\";\nimport { invalid, valid, type ValidationResult } from \"./types\";\n\n/**\n * Luhn (mod-10) checksum over a string of digits.\n */\nfunction passesLuhn(digits: string): boolean {\n let sum = 0;\n let double = digits.length % 2 === 0;\n\n for (const char of digits) {\n let value = Number(char);\n if (double) {\n value *= 2;\n if (value > 9) value -= 9;\n }\n sum += value;\n double = !double;\n }\n\n return sum % 10 === 0;\n}\n\n/**\n * Swedish personnummer. Accepts 10 or 12 digit forms (with or without\n * separators) and validates the trailing Luhn check digit.\n */\nexport function isValidSwedishNationalId(value: string): boolean {\n let digits = value.replace(/\\D/g, \"\");\n\n if (digits.length === 12) {\n digits = digits.slice(2);\n }\n\n if (digits.length !== 10) {\n return false;\n }\n\n const month = Number(digits.slice(2, 4));\n const day = Number(digits.slice(4, 6));\n\n if (month < 1 || month > 12 || day < 1 || day > 31) {\n return false;\n }\n\n return passesLuhn(digits);\n}\n\nconst FINNISH_CHECK_CHARACTERS = \"0123456789ABCDEFHJKLMNPRSTUVWXY\";\n\n/**\n * Finnish henkilötunnus (HETU). Validates structure, date, century marker and\n * the mod-31 check character.\n */\nexport function isValidFinnishNationalId(value: string): boolean {\n const normalized = value.replace(/\\s/g, \"\").toUpperCase();\n\n if (!/^\\d{6}[+\\-A]\\d{3}[0-9A-Y]$/.test(normalized)) {\n return false;\n }\n\n const day = Number(normalized.slice(0, 2));\n const month = Number(normalized.slice(2, 4));\n const yearShort = Number(normalized.slice(4, 6));\n const centurySign = normalized[6];\n\n const centuryBase =\n centurySign === \"+\"\n ? 1800\n : centurySign === \"-\"\n ? 1900\n : centurySign === \"A\"\n ? 2000\n : null;\n\n if (centuryBase === null) {\n return false;\n }\n\n const year = centuryBase + yearShort;\n const date = new Date(year, month - 1, day);\n\n if (\n date.getFullYear() !== year ||\n date.getMonth() !== month - 1 ||\n date.getDate() !== day\n ) {\n return false;\n }\n\n const checksumNumber = Number(\n `${normalized.slice(0, 6)}${normalized.slice(7, 10)}`,\n );\n\n return normalized[10] === FINNISH_CHECK_CHARACTERS[checksumNumber % 31];\n}\n\nconst NO_WEIGHTS_1 = [3, 7, 6, 1, 8, 9, 4, 5, 2];\nconst NO_WEIGHTS_2 = [5, 4, 3, 2, 7, 6, 5, 4, 3, 2];\n\nfunction norwegianControlDigit(digits: number[], weights: number[]): number {\n const sum = weights.reduce((acc, weight, i) => acc + weight * digits[i], 0);\n const remainder = sum % 11;\n return remainder === 0 ? 0 : 11 - remainder;\n}\n\n/**\n * Norwegian fødselsnummer. 11 digits with two mod-11 control digits.\n */\nexport function isValidNorwegianNationalId(value: string): boolean {\n const digits = value.replace(/\\D/g, \"\");\n\n if (digits.length !== 11) {\n return false;\n }\n\n const numbers = digits.split(\"\").map(Number);\n const day = Number(digits.slice(0, 2));\n const month = Number(digits.slice(2, 4));\n\n // Accounts for D-numbers (day + 40) and H-numbers (month + 40).\n const realDay = day > 40 ? day - 40 : day;\n const realMonth = month > 40 ? month - 40 : month;\n\n if (realMonth < 1 || realMonth > 12 || realDay < 1 || realDay > 31) {\n return false;\n }\n\n const k1 = norwegianControlDigit(numbers.slice(0, 9), NO_WEIGHTS_1);\n if (k1 === 11 || k1 !== numbers[9]) {\n return false;\n }\n\n const k2 = norwegianControlDigit(numbers.slice(0, 10), NO_WEIGHTS_2);\n if (k2 === 11 || k2 !== numbers[10]) {\n return false;\n }\n\n return true;\n}\n\nconst SPANISH_DNI_LETTERS = \"TRWAGMYFPDXBNJZSQVHLCKE\";\nconst SPANISH_NIE_PREFIX: Record<string, string> = { X: \"0\", Y: \"1\", Z: \"2\" };\n\n/**\n * Spanish DNI / NIE. Validates the control letter (mod-23). NIE prefixes\n * (X/Y/Z) are mapped to their numeric equivalents before the check.\n */\nexport function isValidSpanishNationalId(value: string): boolean {\n const normalized = value.replace(/[\\s-]/g, \"\").toUpperCase();\n\n if (!/^[XYZ]?\\d{7,8}[A-Z]$/.test(normalized)) {\n return false;\n }\n\n const letter = normalized.slice(-1);\n let numberPart = normalized.slice(0, -1);\n\n const prefix = numberPart[0];\n if (prefix in SPANISH_NIE_PREFIX) {\n numberPart = SPANISH_NIE_PREFIX[prefix] + numberPart.slice(1);\n }\n\n if (numberPart.length !== 8) {\n return false;\n }\n\n return SPANISH_DNI_LETTERS[Number(numberPart) % 23] === letter;\n}\n\nconst NATIONAL_ID_VALIDATORS: Record<Country, (value: string) => boolean> = {\n SE: isValidSwedishNationalId,\n FI: isValidFinnishNationalId,\n NO: isValidNorwegianNationalId,\n ES: isValidSpanishNationalId,\n};\n\n/**\n * Validates a national identity number for the given country.\n */\nexport function isValidNationalId(country: Country, value: string): boolean {\n return NATIONAL_ID_VALIDATORS[country](value);\n}\n\n/**\n * Validates a national identity number and returns the normalized (uppercased,\n * separator-free) value when valid.\n */\nexport function validateNationalId(\n country: Country,\n value: string,\n): ValidationResult {\n if (!isValidNationalId(country, value)) {\n return invalid();\n }\n\n return valid(value.replace(/[\\s-]/g, \"\").toUpperCase());\n}\n\n/**\n * The length of a national identity number once {@link normalizeNationalId}\n * has removed its formatting. Swedish numbers are 12 digits: the form with the\n * full year of birth (`YYYYMMDDNNNN`). The 10-digit form passes\n * {@link isValidNationalId} but is 10 long here, so a form that needs the\n * full year can ask for it.\n */\nexport const NATIONAL_ID_LENGTH: Readonly<Record<Country, number>> = {\n SE: 12,\n FI: 11,\n NO: 11,\n ES: 9,\n};\n\n// Hyphen, non-breaking hyphen, figure dash, en dash, em dash, horizontal bar\n// and minus sign. Phones and pasted text turn a typed \"-\" into one of these.\nconst DASHES = /[‐-―−]/g;\n\nconst NATIONAL_ID_NORMALIZERS: Record<Country, (value: string) => string> = {\n // Digits only: separators, the \"+\" of the 10-digit form and stray dots go.\n SE: (value) => value.replace(/\\D/g, \"\"),\n // The century sign (`+`, `-`, `A`…) and the check character are part of\n // the number, so only what cannot be part of it goes.\n FI: (value) =>\n value\n .replace(DASHES, \"-\")\n .toUpperCase()\n .replace(/[^0-9A-Z+-]/g, \"\"),\n NO: (value) => value.replace(/\\D/g, \"\"),\n ES: (value) => value.toUpperCase().replace(/[^0-9A-Z]/g, \"\"),\n};\n\n/**\n * Removes the formatting people type or paste into a national identity\n * number (spaces, separators, dashes of every kind) and keeps what the\n * checksum needs. It does not validate: pass the result to\n * {@link isValidNationalId}, and compare its length with\n * {@link NATIONAL_ID_LENGTH}.\n *\n * @example\n * normalizeNationalId(\"SE\", \"19811218–9876\") // → \"198112189876\"\n * normalizeNationalId(\"FI\", \"131052-308t\") // → \"131052-308T\"\n */\nexport function normalizeNationalId(country: Country, value: string): string {\n return NATIONAL_ID_NORMALIZERS[country](value);\n}\n\n/**\n * Whether two national identity numbers are the same person's, as for \"the\n * co-applicant must not be the main applicant\". Both are normalised first,\n * and both must be valid: an empty or invalid number never matches.\n */\nexport function isSameNationalId(\n country: Country,\n a: string | null | undefined,\n b: string | null | undefined,\n): boolean {\n const first = normalizeNationalId(country, a ?? \"\");\n const second = normalizeNationalId(country, b ?? \"\");\n\n return first !== \"\" && first === second && isValidNationalId(country, first);\n}\n","// Generated by scripts/generate-mobile-patterns.mjs from libphonenumber-js\n// 1.13.10 (\"mobile\" metadata). Do not edit by hand.\n\n/**\n * The national number of a mobile phone, per country. A number is a mobile\n * when the whole national number matches.\n */\nexport const MOBILE_PATTERNS = {\n SE: \"7[023689]\\\\d{7}\",\n FI: \"4946\\\\d{2,6}|(?:4[0-8]|50)\\\\d{4,8}\",\n NO: \"(?:4[015-9]|9\\\\d)\\\\d{6}\",\n ES: \"96906(?:09|10)\\\\d\\\\d|(?:590(?:10[0-2]|600)|97390\\\\d)\\\\d{3}|(?:6\\\\d|7[1-48])\\\\d{7}\",\n} as const;\n","import {\n parsePhoneNumberFromString,\n type CountryCode,\n} from \"libphonenumber-js\";\nimport { MOBILE_PATTERNS } from \"./mobile-patterns\";\nimport { invalid, valid, type ValidationResult } from \"./types\";\n\nexport type { CountryCode };\n\n/**\n * Validates a phone number for the given country, delegating to\n * `libphonenumber-js` so every country's rules stay accurate and maintained.\n *\n * Accepts national format (with or without a leading trunk `0`) and\n * international format (`+CC` / `00CC`). On success, `normalized` holds the\n * canonical E.164 form (e.g. `+358401234567`).\n */\nexport function validatePhoneNumber(\n country: CountryCode,\n value: string,\n): ValidationResult {\n // Strip all whitespace so the display grouping (e.g. \"400 12 345\") never\n // reaches the parser; validation runs on the bare number.\n const cleaned = value.replace(/\\s/g, \"\");\n if (cleaned === \"\") {\n return invalid();\n }\n\n const parsed = parsePhoneNumberFromString(cleaned, country);\n if (!parsed || !parsed.isValid()) {\n return invalid();\n }\n\n return valid(parsed.number);\n}\n\n/**\n * Boolean convenience wrapper around {@link validatePhoneNumber}.\n */\nexport function isValidPhoneNumber(\n country: CountryCode,\n value: string,\n): boolean {\n return validatePhoneNumber(country, value).valid;\n}\n\n/**\n * The countries {@link validateMobileNumber} knows mobile numbers for: Lea\n * Bank's markets.\n */\nexport type MobileCountry = keyof typeof MOBILE_PATTERNS;\n\nconst MOBILE_REGEXPS = Object.fromEntries(\n Object.entries(MOBILE_PATTERNS).map(([country, pattern]) => [\n country,\n new RegExp(`^(?:${pattern})$`),\n ]),\n) as Record<MobileCountry, RegExp>;\n\n/**\n * Whether {@link validateMobileNumber} can tell a mobile number from a\n * landline in this country.\n */\nexport function isMobileCountry(country: string): country is MobileCountry {\n return Object.prototype.hasOwnProperty.call(MOBILE_PATTERNS, country);\n}\n\n/**\n * Validates a mobile phone number of the given country, as\n * {@link validatePhoneNumber} does, and also rejects:\n *\n * - landlines and other numbers that are not a mobile (`08-123 456 78`), and\n * - a valid number of another country (`+47 412 34 567` for `\"SE\"`).\n *\n * Mobile numbers come from libphonenumber-js's own metadata\n * (`scripts/generate-mobile-patterns.mjs`). On success, `normalized` holds\n * the E.164 form (`+46701234567`).\n */\nexport function validateMobileNumber(\n country: MobileCountry,\n value: string,\n): ValidationResult {\n const cleaned = value.replace(/\\s/g, \"\");\n if (cleaned === \"\") {\n return invalid();\n }\n\n const parsed = parsePhoneNumberFromString(cleaned, country);\n if (\n !parsed ||\n !parsed.isValid() ||\n parsed.country !== country ||\n !MOBILE_REGEXPS[country].test(parsed.nationalNumber)\n ) {\n return invalid();\n }\n\n return valid(parsed.number);\n}\n\n/**\n * Whether two phone numbers are the same number, as for \"the co-applicant\n * must not be the main applicant\". Both are read as numbers of `country`\n * unless they carry a country code (`+46…`, `0046…`), and both must be\n * valid: an empty or invalid number never matches.\n */\nexport function isSamePhone(\n country: CountryCode,\n a: string | null | undefined,\n b: string | null | undefined,\n): boolean {\n const first = validatePhoneNumber(country, a ?? \"\");\n const second = validatePhoneNumber(country, b ?? \"\");\n\n return first.valid && second.valid && first.normalized === second.normalized;\n}\n","export const modulo97 = (digits: string): number => {\n let remainder = 0;\n\n for (const digit of digits) {\n remainder = (remainder * 10 + Number(digit)) % 97;\n }\n\n return remainder;\n};\n\nexport const replaceLatinLettersWithNumbers = (value: string): string =>\n value.replace(/[A-Z]/g, (char) => String(char.charCodeAt(0) - 55));\n","import type { Country } from \"../hooks/country/countries\";\nimport { modulo97, replaceLatinLettersWithNumbers } from \"./modulo-97\";\nimport { invalid, valid, type ValidationResult } from \"./types\";\n\nconst IBAN_LENGTHS: Record<Country, number> = {\n SE: 24,\n FI: 18,\n NO: 15,\n ES: 24,\n};\n\nfunction normalize(value: string): string {\n return value.replace(/[\\s-]/g, \"\").toUpperCase();\n}\n\n/**\n * Generic IBAN check: structure, country length and the ISO 7064 mod-97\n * checksum.\n */\nexport function isValidIban(value: string, country?: Country): boolean {\n const iban = normalize(value);\n\n if (!/^[A-Z]{2}\\d{2}[A-Z0-9]+$/.test(iban)) {\n return false;\n }\n\n const ibanCountry = iban.slice(0, 2) as Country;\n\n if (country && ibanCountry !== country) {\n return false;\n }\n\n const expectedLength = IBAN_LENGTHS[ibanCountry];\n if (expectedLength && iban.length !== expectedLength) {\n return false;\n }\n\n const rearranged = iban.slice(4) + iban.slice(0, 4);\n return modulo97(replaceLatinLettersWithNumbers(rearranged)) === 1;\n}\n\nconst NO_ACCOUNT_WEIGHTS = [5, 4, 3, 2, 7, 6, 5, 4, 3, 2];\n\n/**\n * Norwegian kontonummer: 11 digits with a mod-11 control digit.\n */\nexport function isValidNorwegianAccount(value: string): boolean {\n const digits = value.replace(/\\D/g, \"\");\n\n if (digits.length !== 11) {\n return false;\n }\n\n const numbers = digits.split(\"\").map(Number);\n const sum = NO_ACCOUNT_WEIGHTS.reduce(\n (acc, weight, i) => acc + weight * numbers[i],\n 0,\n );\n const remainder = sum % 11;\n const control = remainder === 0 ? 0 : 11 - remainder;\n\n return control < 10 && control === numbers[10];\n}\n\n/**\n * Swedish clearing + account number. Bank-specific checksums vary, so this is a\n * structural check: a 4-5 digit clearing number followed by a 6-10 digit\n * account number.\n */\nexport function isValidSwedishAccount(value: string): boolean {\n const digits = value.replace(/\\D/g, \"\");\n return digits.length >= 10 && digits.length <= 15;\n}\n\n/**\n * Validates a bank account number for the given country.\n *\n * - **FI / ES** require a valid IBAN.\n * - **NO** accepts a domestic kontonummer or a Norwegian IBAN.\n * - **SE** accepts a domestic clearing + account number or a Swedish IBAN.\n */\nexport function validateBankAccount(\n country: Country,\n value: string,\n): ValidationResult {\n const normalized = normalize(value);\n const looksLikeIban = /^[A-Z]{2}\\d{2}/.test(normalized);\n\n switch (country) {\n case \"FI\":\n case \"ES\":\n return isValidIban(normalized, country) ? valid(normalized) : invalid();\n case \"NO\":\n if (looksLikeIban) {\n return isValidIban(normalized, \"NO\") ? valid(normalized) : invalid();\n }\n return isValidNorwegianAccount(normalized)\n ? valid(normalized.replace(/\\D/g, \"\"))\n : invalid();\n case \"SE\":\n if (looksLikeIban) {\n return isValidIban(normalized, \"SE\") ? valid(normalized) : invalid();\n }\n return isValidSwedishAccount(normalized)\n ? valid(normalized.replace(/\\D/g, \"\"))\n : invalid();\n }\n}\n\n/**\n * Boolean convenience wrapper around {@link validateBankAccount}.\n */\nexport function isValidBankAccount(country: Country, value: string): boolean {\n return validateBankAccount(country, value).valid;\n}\n","import { modulo97 } from \"./modulo-97\";\nimport { invalid, valid, type ValidationResult } from \"./types\";\n\nconst normalize = (value: string): string =>\n value.replace(/\\s/g, \"\").toUpperCase();\n\n/** Finnish domestic reference: 3–19 base digits and a 7-3-1 check digit. */\nexport function isValidFinnishDomesticReference(value: string): boolean {\n const reference = normalize(value);\n if (!/^[1-9]\\d{3,19}$/.test(reference)) {\n return false;\n }\n\n const base = reference.slice(0, -1);\n const checkDigit = Number(reference.at(-1));\n const weights = [7, 3, 1];\n let sum = 0;\n\n for (let index = base.length - 1, weightIndex = 0; index >= 0; index--) {\n sum += Number(base[index]) * weights[weightIndex % weights.length];\n weightIndex++;\n }\n\n return (10 - (sum % 10)) % 10 === checkDigit;\n}\n\n/** ISO 11649 RF reference using Finland's 4–20 digit reference length. */\nexport function isValidFinnishRfReference(value: string): boolean {\n const reference = normalize(value);\n if (!/^RF\\d{2}[1-9]\\d{3,19}$/.test(reference)) {\n return false;\n }\n\n const rearranged = `${reference.slice(4)}2715${reference.slice(2, 4)}`;\n return modulo97(rearranged) === 1;\n}\n\n/** Validates either a Finnish domestic or ISO 11649 RF reference. */\nexport function validateFinnishReference(value: string): ValidationResult {\n const normalized = normalize(value);\n\n return isValidFinnishDomesticReference(normalized) ||\n isValidFinnishRfReference(normalized)\n ? valid(normalized)\n : invalid();\n}\n\n/** Boolean convenience wrapper around {@link validateFinnishReference}. */\nexport function isValidFinnishReference(value: string): boolean {\n return validateFinnishReference(value).valid;\n}\n","import { invalid, valid, type ValidationResult } from \"./types\";\n\n// Pragmatic RFC-5322-ish pattern: good enough for UI validation without the\n// false negatives of an overly strict expression.\nconst EMAIL_PATTERN =\n /^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)+$/;\n\n/**\n * Common consumer email domains across the Nordics and Spain, used to power the\n * `@`-triggered autocomplete dropdown.\n */\nexport const COMMON_EMAIL_DOMAINS: readonly string[] = [\n \"gmail.com\",\n \"outlook.com\",\n \"hotmail.com\",\n \"icloud.com\",\n \"yahoo.com\",\n \"live.com\",\n \"live.se\",\n \"live.no\",\n \"hotmail.se\",\n \"hotmail.no\",\n \"telia.com\",\n \"online.no\",\n \"telenor.no\",\n \"elisanet.fi\",\n \"suomi24.fi\",\n \"telia.se\",\n \"comhem.se\",\n \"kolumbus.fi\",\n \"pp.inet.fi\",\n \"luukku.com\",\n \"me.com\",\n \"msn.com\",\n \"gmx.com\",\n \"yahoo.se\",\n \"yahoo.no\",\n];\n\n/**\n * Validates an email address and returns the lowercased value when valid.\n */\nexport function validateEmail(value: string): ValidationResult {\n const trimmed = value.trim();\n\n if (!EMAIL_PATTERN.test(trimmed)) {\n return invalid();\n }\n\n const atIndex = trimmed.lastIndexOf(\"@\");\n if (atIndex >= 0) {\n const domain = trimmed.slice(atIndex + 1).toLowerCase();\n if (domain.endsWith(\".con\")) {\n return invalid();\n }\n }\n\n return valid(trimmed.toLowerCase());\n}\n\n/**\n * Boolean convenience wrapper around {@link validateEmail}.\n */\nexport function isValidEmail(value: string): boolean {\n return validateEmail(value).valid;\n}\n\n/**\n * Given the current email input, returns a list of completed email suggestions\n * based on common domains. Suggestions only appear once an `@` has been typed,\n * and are filtered by whatever partial domain follows it.\n *\n * @example\n * getEmailDomainSuggestions(\"alice@\") // → [\"alice@gmail.com\", ...]\n * getEmailDomainSuggestions(\"alice@gm\") // → [\"alice@gmail.com\"]\n */\nexport function getEmailDomainSuggestions(\n value: string,\n domains: readonly string[] = COMMON_EMAIL_DOMAINS,\n): string[] {\n const atIndex = value.indexOf(\"@\");\n\n if (atIndex < 1) {\n return [];\n }\n\n const localPart = value.slice(0, atIndex);\n const domainPart = value.slice(atIndex + 1).toLowerCase();\n\n // Don't suggest once a complete domain has been typed.\n if (domainPart.includes(\".\") && domains.includes(domainPart)) {\n return [];\n }\n\n return domains\n .filter((domain) => domain.startsWith(domainPart))\n .map((domain) => `${localPart}@${domain}`);\n}\n\n/**\n * Whether two email addresses are the same, ignoring case and surrounding\n * spaces, as for \"the co-applicant must not be the main applicant\". An empty\n * address never matches.\n */\nexport function isSameEmail(\n a: string | null | undefined,\n b: string | null | undefined,\n): boolean {\n const first = (a ?? \"\").trim().toLowerCase();\n const second = (b ?? \"\").trim().toLowerCase();\n\n return first !== \"\" && first === second;\n}\n\n/*\n * Typo suggestions, the approach of Mailcheck (github.com/mailcheck/mailcheck),\n * written here with our own lists: compare the domain with known domains and,\n * failing that, the top-level domain with known ones.\n */\n\n// Real domains a typo or two away from a common one. They are never\n// \"corrected\": anna@mail.com is not a typo of gmail.com.\nconst REAL_LOOKALIKES = [\n \"mail.com\",\n \"email.com\",\n \"ymail.com\",\n \"googlemail.com\",\n \"gmx.net\",\n \"gmx.de\",\n \"gmx.se\",\n \"aol.com\",\n \"mac.com\",\n \"live.dk\",\n \"live.fi\",\n \"hotmail.dk\",\n \"hotmail.fi\",\n \"hotmail.es\",\n \"outlook.es\",\n \"yahoo.es\",\n \"yahoo.dk\",\n \"tele2.se\",\n \"telenor.se\",\n \"telenor.com\",\n \"spray.se\",\n \"bredband.net\",\n];\n\n// Top-level domains people use for email. One that is not here and is one\n// typo from exactly one that is gets corrected (\"con\" → \"com\"), so the list\n// errs on the long side: a real one missing from it could be \"corrected\".\nconst TOP_LEVEL_DOMAINS = [\n \"com\",\n \"net\",\n \"org\",\n \"se\",\n \"no\",\n \"fi\",\n \"es\",\n \"nu\",\n \"dk\",\n \"is\",\n \"ax\",\n \"fo\",\n \"gl\",\n \"de\",\n \"eu\",\n \"uk\",\n \"co.uk\",\n \"fr\",\n \"it\",\n \"nl\",\n \"be\",\n \"at\",\n \"ch\",\n \"pl\",\n \"ee\",\n \"lv\",\n \"lt\",\n \"pt\",\n \"ie\",\n \"us\",\n \"ca\",\n \"info\",\n \"biz\",\n \"edu\",\n \"gov\",\n \"io\",\n \"me\",\n \"app\",\n \"dev\",\n];\n\n/** Edits (insert, delete, replace, swap two neighbours) from `a` to `b`. */\nfunction editDistance(a: string, b: string): number {\n const d = Array.from({ length: a.length + 1 }, (_, i) =>\n Array.from({ length: b.length + 1 }, (_, j) =>\n i === 0 ? j : j === 0 ? i : 0,\n ),\n );\n for (let i = 1; i <= a.length; i++) {\n for (let j = 1; j <= b.length; j++) {\n const cost = a[i - 1] === b[j - 1] ? 0 : 1;\n d[i][j] = Math.min(\n d[i - 1][j] + 1,\n d[i][j - 1] + 1,\n d[i - 1][j - 1] + cost,\n );\n if (i > 1 && j > 1 && a[i - 1] === b[j - 2] && a[i - 2] === b[j - 1]) {\n d[i][j] = Math.min(d[i][j], d[i - 2][j - 2] + 1);\n }\n }\n }\n return d[a.length][b.length];\n}\n\n/** The one candidate within `limit` edits, nearest first. A tie is no answer. */\nfunction closest(\n value: string,\n candidates: readonly string[],\n limit: number,\n): string | undefined {\n let best: string | undefined;\n let bestDistance = limit + 1;\n let tie = false;\n for (const candidate of candidates) {\n const distance = editDistance(value, candidate);\n if (distance < bestDistance) {\n [best, bestDistance, tie] = [candidate, distance, false];\n } else if (distance === bestDistance && candidate !== best) {\n tie = true;\n }\n }\n return tie ? undefined : best;\n}\n\n/**\n * Suggests a correction for a mistyped email domain, or `undefined` when there\n * is nothing to suggest. It never changes a domain it knows, nor a domain that\n * is merely uncommon (`anna@firma.se` stays).\n *\n * @example\n * suggestEmailCorrection(\"anna@gnail.con\") // → \"anna@gmail.com\"\n * suggestEmailCorrection(\"anna@hotmial.com\") // → \"anna@hotmail.com\"\n * suggestEmailCorrection(\"anna@firma.con\") // → \"anna@firma.com\"\n * suggestEmailCorrection(\"anna@firma.se\") // → undefined\n */\nexport function suggestEmailCorrection(\n value: string,\n domains: readonly string[] = COMMON_EMAIL_DOMAINS,\n): string | undefined {\n const trimmed = value.trim();\n const at = trimmed.lastIndexOf(\"@\");\n if (at < 1) return undefined;\n\n const local = trimmed.slice(0, at);\n const domain = trimmed\n .slice(at + 1)\n .toLowerCase()\n .replace(/\\.+$/, \"\");\n if (!/^[a-z0-9-]+(\\.[a-z0-9-]+)*$/.test(domain)) return undefined;\n\n const known = [...domains, ...REAL_LOOKALIKES];\n if (known.includes(domain)) return undefined;\n\n const suggest = (fixed: string | undefined) =>\n fixed && fixed !== domain && !REAL_LOOKALIKES.includes(fixed)\n ? `${local}@${fixed}`\n : undefined;\n const nameOf = (entry: string) => entry.slice(0, entry.indexOf(\".\"));\n const tldOf = (entry: string) => entry.slice(entry.indexOf(\".\") + 1);\n\n const dot = domain.indexOf(\".\");\n\n // No top-level domain at all: \"anna@gmail\", \"anna@hotmial\".\n if (dot < 0) {\n const names = [...new Set(domains.map(nameOf))];\n const name = closest(domain, names, domain.length >= 6 ? 2 : 1);\n return suggest(domains.find((entry) => nameOf(entry) === name));\n }\n\n const name = domain.slice(0, dot);\n const tld = domain.slice(dot + 1);\n\n // A real top-level domain: only a typo in the name, of one edit, against\n // the known domains with that top-level domain: \"hotmial.com\". A name with\n // a different real top-level domain (online.de) is somebody else's.\n if (TOP_LEVEL_DOMAINS.includes(tld)) {\n const sameTld = known.filter((entry) => tldOf(entry) === tld);\n return suggest(closest(domain, sameTld, 1));\n }\n\n // A top-level domain that does not exist: a known domain one typo away, or\n // two in a longer one (\"gnail.con\"), or else the nearest real top-level\n // domain (\"firma.con\").\n const near = closest(domain, known, domain.length >= 9 ? 2 : 1);\n if (near) return suggest(near);\n\n const fixedTld = closest(tld, TOP_LEVEL_DOMAINS, 1);\n return fixedTld ? suggest(`${name}.${fixedTld}`) : undefined;\n}\n","/*\n * Design tokens come from src/theme/tokens.css, generated from src/theme/tokens\n * by `pnpm tokens:css`. It is a plain stylesheet rather than runtime-injected\n * CSS variables, so this component renders correctly without a provider.\n */\n\n.Link {\n --link-color: var(--lea-palette-secondary-base);\n\n color: var(--link-color);\n /* Size, line height and family come from the surrounding text. */\n font-weight: var(--lea-font-weight-regular);\n /*\n * Underlined at rest: in a sentence the colour alone does not set a link\n * apart from the words around it, least of all `secondary`, which is the\n * colour of body text.\n */\n text-decoration: underline;\n text-decoration-thickness: 0.0625rem;\n /* Clears the descenders of the font; there is no token for it. */\n text-underline-offset: 0.3rem;\n cursor: pointer;\n}\n\n/*\n * The brand colours as text: a step of the same scale dark enough to read at\n * body size. `tertiary.base` is too light for text on white.\n */\n.Link[data-color=\"primary\"] {\n --link-color: var(--lea-color-purple-700);\n}\n\n.Link[data-color=\"tertiary\"] {\n --link-color: var(--lea-color-teal-700);\n}\n\n.Link[data-color=\"contrast\"] {\n --link-color: var(--lea-palette-text-contrast);\n}\n\n/* `render={<button type=\"button\" />}`: an action that looks like a link. */\nbutton.Link {\n padding: 0;\n border: 0;\n appearance: none;\n background: none;\n font-family: inherit;\n font-size: inherit;\n line-height: inherit;\n letter-spacing: inherit;\n text-align: inherit;\n}\n\n.Link:focus-visible {\n outline: 2px solid var(--lea-palette-text-base);\n outline-offset: 0.125rem;\n}\n\n/* Hover thickens the line, from 1px to 2px, without moving the text. */\n@media (hover: hover) {\n .Link:hover {\n text-decoration-thickness: 0.125rem;\n }\n}\n","\"use client\";\n\nimport { useRender } from \"@base-ui/react/use-render\";\nimport type { Ref } from \"react\";\n\nimport { mergeClassName } from \"../../utils/merge-class-name\";\nimport type { ColorRoles } from \"../color-roles\";\nimport styles from \"./link.module.css\";\n\nexport type LinkColor = ColorRoles<\n \"secondary\" | \"primary\" | \"tertiary\" | \"contrast\"\n>;\n\nexport type LinkProps = Omit<useRender.ComponentProps<\"a\">, \"ref\" | \"color\"> & {\n /**\n * The colour of the link: `secondary` is the near-black of body text,\n * `primary` the brand purple, `tertiary` the brand teal. Use `contrast`\n * (white) on a dark surface.\n * @default \"secondary\"\n */\n color?: LinkColor;\n /** The rendered element: the `<a>`, or the element passed to `render`. */\n ref?: Ref<HTMLElement>;\n};\n\n/**\n * A link inside running text: underlined, so it is told apart from the words\n * around it by more than its colour, and in the size and line height of the\n * text around it. Renders an `a`; pass a router link\n * through `render`:\n *\n * ```tsx\n * <Link href=\"/om-oss\">Om oss</Link>\n * <Link render={<NextLink href=\"/om-oss\" />}>Om oss</Link>\n * <Link render={<RouterLink to=\"/om-oss\" />}>Om oss</Link>\n * ```\n *\n * For an action that only looks like a link, render a button:\n * `<Link render={<button type=\"button\" />} onClick={…}>`. For a link that\n * looks like a button, use `Button` with `render`.\n */\nexport function Link({\n color = \"secondary\",\n render,\n ref,\n className,\n ...rest\n}: LinkProps) {\n return useRender({\n render,\n ref,\n defaultTagName: \"a\",\n props: {\n ...rest,\n \"data-color\": color,\n className: mergeClassName(styles.Link, className)({}),\n },\n });\n}\n","/*\n * Design tokens come from src/theme/tokens.css, generated from src/theme/tokens\n * by `pnpm tokens:css`. It is a plain stylesheet rather than runtime-injected\n * CSS variables, so this component renders correctly without a provider.\n *\n * `--_gap` arrives inline from the `gap` prop of the root and of each item.\n */\n\n.Root {\n display: flex;\n flex-direction: column;\n gap: calc(var(--lea-spacing) * var(--_gap));\n padding: 0;\n margin: 0;\n list-style: none;\n counter-reset: list-counter;\n}\n\n.Item {\n display: flex;\n align-items: flex-start;\n gap: calc(var(--lea-spacing) * var(--_gap));\n counter-increment: list-counter;\n}\n\n/* As tall as one line of body text, so the marker centres on the first line\n of the item instead of on the whole block. */\n.Marker {\n display: flex;\n min-width: var(--lea-spacing-3);\n height: calc(\n var(--lea-text-body-md-font-size) * var(--lea-text-body-md-line-height)\n );\n flex-shrink: 0;\n align-items: center;\n justify-content: center;\n}\n\n.Marker[data-marker=\"dot\"]::before {\n width: 0.375rem;\n height: 0.375rem;\n border-radius: var(--lea-radius-full);\n background-color: var(--lea-palette-text-base);\n content: \"\";\n}\n\n/* heading-xs's size and weight on a line as tall as the digit, so the number\n centres in the marker like the dot does. */\n.Marker[data-marker=\"number\"] {\n color: var(--lea-palette-text-base);\n font-size: var(--lea-font-step-0);\n font-weight: var(--lea-font-weight-semibold);\n line-height: var(--lea-line-height-none);\n}\n\n.Marker[data-marker=\"number\"]::before {\n content: counter(list-counter) \".\";\n}\n\n.Content {\n min-width: 0;\n flex: 1;\n}\n","\"use client\";\n\nimport {\n type ComponentProps,\n type CSSProperties,\n type ReactNode,\n createContext,\n useContext,\n} from \"react\";\n\nimport styles from \"./lists.module.css\";\nimport { Text } from \"./text\";\n\n/**\n * List is a composition component for rendering ordered or unordered lists.\n *\n * `List.Root` renders the wrapping `<ul>` (default) or `<ol>` element via the\n * `variant` prop. Each `List.Item` shows a marker: a dot for `ul`, an\n * auto-incrementing number for `ol`, or a custom icon when one is passed.\n *\n * @example Unordered list with default dots\n * <List.Root>\n * <List.Item>Fast response</List.Item>\n * <List.Item>Account data report</List.Item>\n * </List.Root>\n *\n * @example Ordered list with auto-numbering\n * <List.Root variant=\"ol\">\n * <List.Item>First step</List.Item>\n * <List.Item>Second step</List.Item>\n * </List.Root>\n *\n * @example Per-item icon marker\n * <List.Root>\n * <List.Item icon={<CircleCheck size={20} />}>Verified</List.Item>\n * </List.Root>\n */\n\ntype ListVariant = \"ul\" | \"ol\";\n\ninterface ListContextValue {\n variant: ListVariant;\n}\n\nconst ListContext = createContext<ListContextValue | null>(null);\n\nconst useListContext = () => {\n const context = useContext(ListContext);\n if (!context) {\n throw new Error(\"List parts must be used within <List.Root>\");\n }\n return context;\n};\n\nconst joinClassNames = (...names: (string | undefined)[]) =>\n names.filter(Boolean).join(\" \");\n\ntype RootProps = Omit<ComponentProps<\"ul\">, \"ref\"> & {\n /**\n * The type of list to render.\n * @default \"ul\"\n */\n variant?: ListVariant;\n /**\n * The gap between the list items, as a multiple of the spacing step.\n * @default 1.5\n */\n gap?: number;\n};\n\nexport const Root = ({\n variant = \"ul\",\n gap = 1.5,\n className,\n style,\n children,\n ...rest\n}: RootProps) => {\n const Element = variant;\n\n return (\n <ListContext.Provider value={{ variant }}>\n <Element\n {...rest}\n className={joinClassNames(styles.Root, className)}\n style={{ \"--_gap\": gap, ...style } as CSSProperties}\n >\n {children}\n </Element>\n </ListContext.Provider>\n );\n};\n\ntype ItemProps = Omit<ComponentProps<\"li\">, \"ref\"> & {\n /** Custom marker rendered in place of the default dot/number. */\n icon?: ReactNode;\n /**\n * The gap between a custom `icon` and the text, as a multiple of the spacing\n * step. The dot and the number keep their own spacing.\n * @default 1.5\n */\n gap?: number;\n};\n\nexport const Item = ({\n icon,\n gap = 1.5,\n className,\n style,\n children,\n ...rest\n}: ItemProps) => {\n const { variant } = useListContext();\n const marker = icon ? \"icon\" : variant === \"ol\" ? \"number\" : \"dot\";\n\n return (\n <li\n {...rest}\n className={joinClassNames(styles.Item, className)}\n style={{ \"--_gap\": icon ? gap : 0, ...style } as CSSProperties}\n >\n <span className={styles.Marker} data-marker={marker}>\n {icon}\n </span>\n <div className={styles.Content}>\n {typeof children === \"string\" ? <Text>{children}</Text> : children}\n </div>\n </li>\n );\n};\n","/*\n * The \"Did you mean …?\" line under the field. It sits where the helper text\n * does and is set like it (field-parts.module.css), so the two read as one\n * column. The address in it is a `Link` rendered as a button.\n */\n\n.Suggestion {\n /* Present even when empty: a live region only announces changes to an\n element that is already in the page. Empty, it takes no room. */\n margin: 0;\n}\n\n.Suggestion p {\n /* 14px, where the text inside a field starts. */\n margin-inline: calc(var(--lea-spacing) * 1.75);\n margin-block: var(--lea-spacing-0-5) 0;\n color: var(--lea-color-neutral-600);\n font-size: var(--lea-text-body-sm-font-size);\n font-weight: var(--lea-text-body-sm-font-weight);\n letter-spacing: var(--lea-text-body-sm-letter-spacing);\n line-height: var(--lea-text-body-sm-line-height);\n overflow-wrap: anywhere;\n}\n","\"use client\";\n\nimport { Autocomplete as BaseAutocomplete } from \"@base-ui/react/autocomplete\";\nimport { useMemo, useRef, useState } from \"react\";\n\nimport { createTranslation } from \"../../i18n\";\nimport {\n COMMON_EMAIL_DOMAINS,\n getEmailDomainSuggestions,\n suggestEmailCorrection,\n} from \"../../validation\";\nimport { Link } from \"../typography\";\nimport { ComboField, type ComboFieldBaseProps } from \"./combo-field\";\nimport styles from \"./email-input.module.css\";\nimport listStyles from \"./option-list.module.css\";\n\nexport type EmailInputProps = ComboFieldBaseProps & {\n /** The address (controlled). Pair with `onValueChange`. */\n value?: string;\n /** The address when first rendered, for uncontrolled use. */\n defaultValue?: string;\n /** Called with the new text on every change, and with a suggestion when one is picked. */\n onValueChange?: (value: string) => void;\n /** Domains offered once the user types `@`. Defaults to common providers. */\n domains?: readonly string[];\n /** Most suggestions shown at once. @default 6 */\n maxSuggestions?: number;\n /**\n * When focus leaves the field, offers a fix for a mistyped domain below it:\n * \"Mente du anna@gmail.com?\" for `anna@gnail.con`, with the address as a\n * button that puts it in the field. The value never changes by itself, and\n * validation is not affected. See `suggestEmailCorrection`.\n * @default true\n */\n suggestCorrection?: boolean;\n /**\n * What the browser may fill in. The default lets it offer the user's own\n * address; pass `\"off\"` when the address is somebody else's.\n * @default \"email\"\n */\n autoComplete?: string;\n};\n\n/**\n * Email text field that suggests common domains in a list once the user\n * types `@`, on Base UI's `Autocomplete`, in the same box as `Input`. The\n * text is the value: a suggestion only saves typing.\n *\n * ```tsx\n * <EmailInput label=\"E-post\" value={email} onValueChange={setEmail} />\n * ```\n */\nexport function EmailInput({\n value,\n defaultValue = \"\",\n onValueChange,\n domains = COMMON_EMAIL_DOMAINS,\n maxSuggestions = 6,\n autoComplete = \"email\",\n suggestCorrection = true,\n name,\n onBlur,\n ref,\n ...field\n}: EmailInputProps) {\n const labels = useEmailInputLabels();\n const isControlled = value !== undefined;\n const [internal, setInternal] = useState(defaultValue);\n const current = isControlled ? value : internal;\n\n const inputRef = useRef<HTMLInputElement | null>(null);\n const setInput = (element: HTMLInputElement | null) => {\n inputRef.current = element;\n if (typeof ref === \"function\") return ref(element);\n if (ref) ref.current = element;\n };\n\n // Worked out when focus leaves the field, and gone as soon as the text\n // changes, so it never interrupts typing.\n const [correction, setCorrection] = useState<string>();\n const shownCorrection =\n suggestCorrection && !field.disabled ? correction : undefined;\n\n const change = (next: string) => {\n if (!isControlled) setInternal(next);\n setCorrection(undefined);\n onValueChange?.(next);\n };\n\n const acceptCorrection = () => {\n if (correction == null) return;\n change(correction);\n // The button goes away; focus goes back to the field, not to the page.\n inputRef.current?.focus();\n };\n\n // There is no \"no suggestions\" text, so with nothing to suggest the list is\n // closed, not open and empty.\n const [open, setOpen] = useState(false);\n\n const suggestions = useMemo(\n () => getEmailDomainSuggestions(current, domains).slice(0, maxSuggestions),\n [current, domains, maxSuggestions],\n );\n\n return (\n <ComboField\n {...field}\n ref={setInput}\n onBlur={(event) => {\n if (suggestCorrection)\n setCorrection(suggestEmailCorrection(current, domains));\n onBlur?.(event);\n }}\n afterHelperText={\n suggestCorrection && (\n <div role=\"status\" className={styles.Suggestion}>\n {shownCorrection != null && (\n <p>\n {labels.didYouMean}{\" \"}\n <Link\n render={<button type=\"button\" />}\n color=\"primary\"\n aria-label={`${labels.use} ${shownCorrection}`}\n onClick={acceptCorrection}\n >\n {shownCorrection}\n </Link>\n ?\n </p>\n )}\n </div>\n )\n }\n clearable\n inputProps={{\n type: \"email\",\n name,\n autoComplete,\n autoCapitalize: \"none\",\n spellCheck: false,\n }}\n renderRoot={(children) => (\n <BaseAutocomplete.Root\n items={suggestions}\n // The suggestions are already made from the text, so nothing is filtered out.\n filter={null}\n open={open && suggestions.length > 0}\n onOpenChange={setOpen}\n value={current}\n onValueChange={change}\n disabled={field.disabled}\n required={field.required}\n highlightItemOnHover={false}\n >\n {children}\n </BaseAutocomplete.Root>\n )}\n >\n <BaseAutocomplete.List className={listStyles.List}>\n {(suggestion: string) => (\n <BaseAutocomplete.Item\n key={suggestion}\n value={suggestion}\n className={listStyles.Item}\n >\n <span className={listStyles.ItemText}>{suggestion}</span>\n </BaseAutocomplete.Item>\n )}\n </BaseAutocomplete.List>\n </ComboField>\n );\n}\n\nconst useEmailInputLabels = createTranslation({\n didYouMean: {\n no: \"Mente du\",\n se: \"Menade du\",\n fi: \"Tarkoititko\",\n es: \"¿Quisiste decir\",\n },\n use: {\n no: \"Bruk\",\n se: \"Använd\",\n fi: \"Käytä\",\n es: \"Usar\",\n },\n});\n","\"use client\";\n\nimport { Input as BaseInput } from \"@base-ui/react/input\";\nimport {\n useEffect,\n useId,\n useLayoutEffect,\n useRef,\n type ComponentPropsWithoutRef,\n type CSSProperties,\n type MouseEvent,\n type ReactNode,\n type Ref,\n} from \"react\";\n\nimport { FieldHelperText, fieldMessage, RequiredAsterisk } from \"./field-parts\";\nimport styles from \"./input.module.css\";\n\ntype NativeInputProps = Omit<\n ComponentPropsWithoutRef<\"input\">,\n | \"value\"\n | \"defaultValue\"\n | \"size\"\n | \"color\"\n | \"children\"\n | \"className\"\n | \"style\"\n>;\n\nexport type InputProps = NativeInputProps & {\n /** Floating label, linked to the input for you. */\n label?: ReactNode;\n /** Helper / error text shown below the input and linked via `aria-describedby`. */\n helperText?: ReactNode;\n /** Puts the input, its label and its helper text into the error state. */\n error?: boolean;\n /**\n * A message for a value that is allowed but unusual, such as an unusually\n * high amount. Shown in amber in place of the helper text, without the\n * error state: the field is not marked invalid. `error` wins when both are set.\n */\n warning?: ReactNode;\n /** The text (controlled). Pair with `onValueChange`. */\n value?: string;\n /** The text when first rendered, for uncontrolled use. */\n defaultValue?: string;\n /** Called with the new text on every change. `onChange` still gets the event. */\n onValueChange?: (value: string) => void;\n /** Content before the text, inside the field, e.g. an icon. */\n startAdornment?: ReactNode;\n /** Content after the text, inside the field, e.g. a show / hide button. */\n endAdornment?: ReactNode;\n /**\n * Renders a `<textarea>` that grows with its content. The native attributes\n * and event handlers then apply to the textarea.\n */\n multiline?: boolean;\n /** Fixed number of rows when `multiline`. */\n rows?: number;\n /** Fewest rows shown when `multiline`. */\n minRows?: number;\n /** Most rows shown when `multiline`, before it scrolls. */\n maxRows?: number;\n /** Class on the outermost element, for layout. */\n className?: string;\n /** Inline style on the outermost element, for layout. */\n style?: CSSProperties;\n /** The `<input>`, or the `<textarea>` when `multiline`. */\n ref?: Ref<HTMLInputElement | HTMLTextAreaElement>;\n};\n\nconst join = (...parts: (string | false | null | undefined)[]) =>\n parts.filter(Boolean).join(\" \") || undefined;\n\n// `useLayoutEffect` warns when a component is rendered on the server.\nconst useIsoLayoutEffect =\n typeof document === \"undefined\" ? useEffect : useLayoutEffect;\n\n/**\n * Sizes a textarea to its content, between `rows` (its `minRows`) and\n * `maxRows`. It listens to the element itself, so it also follows typing in\n * an uncontrolled textarea, which causes no render.\n */\nfunction useAutosize(enabled: boolean, maxRows?: number) {\n const elementRef = useRef<HTMLElement | null>(null);\n\n const resize = () => {\n const element = elementRef.current;\n if (!element) return;\n\n // Back to the height the `rows` attribute gives, to measure from there.\n element.style.height = \"auto\";\n const computed = getComputedStyle(element);\n const max =\n maxRows != null\n ? parseFloat(computed.lineHeight) * maxRows +\n parseFloat(computed.paddingTop) +\n parseFloat(computed.paddingBottom)\n : Infinity;\n const content = element.scrollHeight;\n element.style.height = `${Math.min(content, max)}px`;\n element.style.overflowY = content > max ? \"auto\" : \"hidden\";\n };\n\n useIsoLayoutEffect(() => {\n if (enabled) resize();\n });\n\n useEffect(() => {\n const element = elementRef.current;\n if (!enabled || !element) return;\n\n element.addEventListener(\"input\", resize);\n // The lines rewrap when the width changes.\n const observer =\n typeof ResizeObserver === \"undefined\" ? null : new ResizeObserver(resize);\n observer?.observe(element);\n return () => {\n element.removeEventListener(\"input\", resize);\n observer?.disconnect();\n };\n // `resize` reads nothing but the element and `maxRows`.\n }, [enabled, maxRows]);\n\n return elementRef;\n}\n\n/**\n * Text input, on Base UI's `Input` primitive. The label, the helper text and\n * the ids that link them to the input are all rendered and wired for you.\n *\n * Takes the native `<input>` attributes (`type`, `name`, `placeholder`,\n * `autoComplete`, `inputMode`, `maxLength`, `onKeyDown`, …), which land on the\n * input itself. `className` and `style` go on the outermost element. Pass\n * `multiline` (and `minRows`) for a textarea.\n *\n * ```tsx\n * <Input\n * label=\"E-post\"\n * helperText=\"Vi deler den aldri.\"\n * value={email}\n * onValueChange={setEmail}\n * />\n * ```\n */\nexport function Input({\n label,\n helperText,\n error = false,\n warning,\n value,\n defaultValue,\n onValueChange,\n startAdornment,\n endAdornment,\n multiline = false,\n rows,\n minRows,\n maxRows,\n className,\n style,\n ref,\n id,\n disabled = false,\n required = false,\n placeholder,\n \"aria-describedby\": ariaDescribedBy,\n ...inputAttributes\n}: InputProps) {\n const generatedId = useId();\n const inputId = id ?? generatedId;\n const helperTextId = useId();\n const hasLabel = label != null;\n const message = fieldMessage(helperText, warning, error);\n const hasHelperText = message.content != null;\n\n // A fixed `rows` is left alone; otherwise the textarea follows its content.\n const autosize = multiline && rows == null;\n const autosizeRef = useAutosize(autosize, maxRows);\n\n const setControl = (element: HTMLInputElement | null) => {\n autosizeRef.current = element;\n if (typeof ref === \"function\") return ref(element);\n if (ref) ref.current = element;\n };\n\n // The label, the padding and the adornments are part of the field, so a\n // click on any of them goes to the control, unless it hit something that\n // takes clicks itself (a show / hide button in an adornment).\n const focusControl = (event: MouseEvent<HTMLDivElement>) => {\n const target = event.target as Element;\n if (target.closest(\"button, a, input, textarea, select, [tabindex]\"))\n return;\n event.currentTarget.querySelector<HTMLElement>(\"input, textarea\")?.focus();\n };\n\n return (\n <div className={join(styles.Field, className)} style={style}>\n <div\n className={styles.Box}\n data-invalid={error ? \"\" : undefined}\n data-disabled={disabled ? \"\" : undefined}\n data-has-label={hasLabel ? \"\" : undefined}\n onClick={focusControl}\n >\n {startAdornment != null && (\n <span className={styles.Adornment} data-position=\"start\">\n {startAdornment}\n </span>\n )}\n <div className={styles.Inner}>\n {hasLabel && (\n <label htmlFor={inputId} className={styles.Label}>\n {label}\n {required && <RequiredAsterisk />}\n </label>\n )}\n <BaseInput\n {...inputAttributes}\n ref={setControl}\n id={inputId}\n value={value}\n defaultValue={defaultValue}\n onValueChange={(next) => onValueChange?.(next)}\n disabled={disabled}\n required={required}\n // Never empty: `:placeholder-shown` is how the stylesheet tells an\n // empty control from a filled one, and it needs a placeholder to work.\n placeholder={placeholder || \" \"}\n aria-invalid={error}\n aria-describedby={join(\n hasHelperText && helperTextId,\n ariaDescribedBy,\n )}\n className={styles.Control}\n render={\n multiline ? <textarea rows={rows ?? minRows ?? 1} /> : undefined\n }\n />\n </div>\n {endAdornment != null && (\n <span className={styles.Adornment} data-position=\"end\">\n {endAdornment}\n </span>\n )}\n </div>\n {hasHelperText && (\n <FieldHelperText\n id={helperTextId}\n error={error}\n warning={message.warning}\n >\n {message.content}\n </FieldHelperText>\n )}\n </div>\n );\n}\n","/*\n * Design tokens come from src/theme/tokens.css, generated from src/theme/tokens\n * by `pnpm tokens:css`. It is a plain stylesheet rather than runtime-injected\n * CSS variables, so this component renders correctly without a provider.\n *\n * Shared by Select and MultiSelect. The box, its border states and the\n * adornments come from input.module.css, and the list from\n * option-list.module.css; this file adds the trigger, the label (which floats\n * on a value, not on focus) and the arrow.\n */\n\n/*\n * `.Field` in front of a selector lifts it over the rules of input.module.css\n * for the same element, whichever of the two stylesheets loads last.\n */\n.Field .Box {\n /* White, where Input shows the surface it sits on. As it always was. */\n background-color: var(--lea-palette-bg-base);\n cursor: pointer;\n}\n\n.Field .Box[data-disabled] {\n cursor: not-allowed;\n}\n\n/* The list is in a portal, so focus is not inside the box while it is open. */\n.Field .Box[data-open]:not([data-invalid]) {\n --input-border-color: var(--lea-palette-border-accent);\n --input-border-width: 2px;\n}\n\n/* The field and its open list read as one shape: square where they meet. */\n.Box[data-popup-side=\"bottom\"] {\n border-end-end-radius: 0;\n border-end-start-radius: 0;\n}\n\n.Box[data-popup-side=\"top\"] {\n border-start-end-radius: 0;\n border-start-start-radius: 0;\n}\n\n/* An empty layer over the whole box: a click anywhere in the field opens the list. */\n.Trigger {\n position: absolute;\n border-radius: inherit;\n cursor: inherit;\n inset: 0;\n /* The border of the box is the focus indicator, as in Input. */\n outline: none;\n}\n\n/* What the field shows lies over the trigger and lets clicks through to it. */\n.Box > :not(.Trigger) {\n position: relative;\n pointer-events: none;\n}\n\n.Box :is(button, a, input) {\n pointer-events: auto;\n}\n\n.Inner {\n flex-direction: column;\n}\n\n/* The value, or the chips. One line: a long value is cut off with an ellipsis. */\n.Display {\n overflow: hidden;\n min-height: calc(var(--lea-text-body-md-line-height) * 1em);\n box-sizing: content-box;\n padding-block: var(--input-padding-top) calc(var(--lea-spacing) * 0.75);\n padding-inline: var(--input-inset-start) var(--lea-spacing-0-5);\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.Placeholder {\n color: var(--lea-palette-text-muted);\n}\n\n/* While the label rests over the field the placeholder is hidden, so the two never overlap. */\n.Box[data-has-label]:not(:focus-within, [data-open]) .Placeholder {\n visibility: hidden;\n}\n\n/*\n * The label of Input, with one difference: it floats when there is a value or\n * a placeholder to make room for, not on focus alone. An empty select has\n * nothing to show under a floated label.\n */\n.Label {\n position: absolute;\n z-index: 1;\n overflow: hidden;\n max-width: calc(100% - var(--input-inset-start));\n /*\n * neutral-600 rather than text-subtle: a field has no background of its\n * own, and text-subtle falls below 4.5:1 on the tinted surfaces it can sit on.\n */\n color: var(--lea-color-neutral-600);\n inset-block-start: 0;\n inset-inline-start: var(--input-inset-start);\n scale: 1;\n text-overflow: ellipsis;\n transform-origin: top left;\n /* Resting, the label is centred in the field, where the value will be. */\n translate: 0\n calc((var(--input-height) - var(--lea-text-body-md-line-height) * 1em) / 2);\n transition: color var(--lea-duration-normal) var(--lea-easing-standard),\n scale var(--lea-duration-normal) var(--lea-easing-standard),\n translate var(--lea-duration-normal) var(--lea-easing-standard);\n white-space: nowrap;\n}\n\n.Box[data-filled] .Label,\n.Box[data-has-placeholder]:focus-within .Label,\n.Box[data-has-placeholder][data-open] .Label {\n max-width: calc((100% - var(--input-inset-start)) / 0.75);\n scale: 0.75;\n translate: 0 calc(var(--lea-spacing) * 0.75);\n}\n\n.Box:focus-within .Label,\n.Box[data-open] .Label {\n color: var(--lea-palette-text-accent);\n}\n\n.Box[data-invalid] .Label {\n color: var(--lea-palette-status-error-base);\n}\n\n.Box[data-disabled] .Label {\n color: var(--lea-palette-text-muted);\n}\n\n.Icon {\n width: 1.25rem;\n height: 1.25rem;\n flex-shrink: 0;\n align-self: center;\n margin-inline: var(--lea-spacing-0-5) var(--input-padding-inline);\n color: var(--lea-palette-text-base);\n transition: rotate var(--lea-duration-normal) var(--lea-easing-standard);\n}\n\n.Box[data-open] .Icon {\n rotate: 180deg;\n}\n\n.Box[data-disabled] .Icon {\n color: var(--lea-palette-text-muted);\n}\n\n.EndAdornment {\n display: flex;\n flex-shrink: 0;\n align-items: center;\n align-self: center;\n color: var(--lea-palette-text-subtle);\n margin-inline-start: var(--lea-spacing-1);\n white-space: nowrap;\n}\n\n.SrOnly {\n position: absolute;\n overflow: hidden;\n width: 1px;\n height: 1px;\n padding: 0;\n border: 0;\n margin: -1px;\n clip-path: inset(50%);\n white-space: nowrap;\n}\n\n/* MultiSelect: the chips, on one line. */\n.Chips {\n position: relative;\n display: flex;\n min-width: 0;\n}\n\n.ChipRow {\n display: flex;\n overflow: hidden;\n min-width: 0;\n flex: 1;\n flex-wrap: nowrap;\n align-items: center;\n gap: var(--lea-spacing-0-5);\n}\n\n/* Every chip and a badge, laid out unseen to be measured. */\n.ChipMeasure {\n position: absolute;\n display: flex;\n overflow: hidden;\n height: 0;\n gap: var(--lea-spacing-0-5);\n inset-block-start: 0;\n inset-inline-start: 0;\n visibility: hidden;\n}\n\n@media (prefers-reduced-motion: reduce) {\n .Label,\n .Icon {\n transition-duration: 0.01ms;\n }\n}\n","\"use client\";\n\nimport { Select as BaseSelect } from \"@base-ui/react/select\";\nimport { ChevronDown } from \"lucide-react\";\nimport {\n useEffect,\n useId,\n useRef,\n useState,\n type ComponentProps,\n type CSSProperties,\n type FocusEvent,\n type ReactNode,\n type Ref,\n} from \"react\";\n\nimport { FieldHelperText, RequiredAsterisk } from \"./field-parts\";\nimport inputStyles from \"./input.module.css\";\nimport listStyles from \"./option-list.module.css\";\nimport styles from \"./select.module.css\";\nimport { useBlurOutside } from \"./use-blur-outside\";\n\n/*\n * Internal. The field that `Select` and `MultiSelect` share: the box of\n * `Input`, a trigger with the `combobox` role, and the list in a popup, on\n * Base UI's `Select`. Not part of the public API, so this file isn't\n * re-exported from `index.ts`.\n *\n * The trigger is an empty layer over the whole box, so a click anywhere in\n * the field opens the list. What the field shows (the label, the value or the\n * chips, the adornments, the arrow) lies on top of it and lets clicks through.\n * That keeps the remove buttons of `MultiSelect`'s chips out of the trigger:\n * a control inside a control is invalid, and its keys would open the list.\n */\n\n/** One choice in a `Select` or `MultiSelect`. */\nexport type SelectOption<Value extends string = string> = {\n value: Value;\n label: string;\n /** Shown, but not selectable. */\n disabled?: boolean;\n};\n\n/** The props `Select` and `MultiSelect` have in common. */\nexport type SelectFieldBaseProps = {\n /** Floating label, linked to the select for you. */\n label?: ReactNode;\n /** Helper / error text shown below the control and linked via `aria-describedby`. */\n helperText?: ReactNode;\n /** Puts the select, its label and its helper text into the error state. */\n error?: boolean;\n /** Marks the select as required, with an asterisk after the label. */\n required?: boolean;\n disabled?: boolean;\n /**\n * Text shown while nothing is chosen. With a `label` it appears once the\n * label has floated up: on focus and while the list is open.\n */\n placeholder?: string;\n /** Content before the value, inside the field, e.g. an icon. */\n startAdornment?: ReactNode;\n /** Content after the value, inside the field, left of the dropdown arrow. */\n endAdornment?: ReactNode;\n /** Whether the list is open (controlled). Pair with `onOpenChange`. */\n open?: boolean;\n /** Called when the list opens or closes. */\n onOpenChange?: (open: boolean) => void;\n /** Called when focus leaves the select, the open list included. */\n onBlur?: (event: FocusEvent<HTMLElement>) => void;\n /** Submits the value under this name in a native form. */\n name?: string;\n /** Id of the element with the `combobox` role. */\n id?: string;\n /** Names the select when there is no visible `label`. */\n \"aria-label\"?: string;\n \"aria-labelledby\"?: string;\n \"aria-describedby\"?: string;\n /** Class on the outermost element, for layout. */\n className?: string;\n /** Inline style on the outermost element, for layout. */\n style?: CSSProperties;\n /** The element that takes focus, the one with the `combobox` role. */\n ref?: Ref<HTMLElement>;\n};\n\ntype SelectFieldProps = SelectFieldBaseProps & {\n multiple: boolean;\n /** The value as Base UI holds it: `null` or an array when empty. */\n value: string | string[] | null;\n onValueChange: (value: string | string[] | null) => void;\n /** Whether something is chosen, which is what floats the label. */\n filled: boolean;\n /** What the field shows for the value: text, or the chips. */\n display: ReactNode;\n /**\n * Hides `display` from assistive tech, when it only repeats `valueText`.\n * Not for chips: their remove buttons are controls.\n */\n displayHidden?: boolean;\n /** The value as plain text, for assistive tech, inside the trigger. */\n valueText: string;\n /** The `SelectFieldItem`s. */\n children: ReactNode;\n};\n\nconst join = (...parts: (string | false | null | undefined)[]) =>\n parts.filter(Boolean).join(\" \") || undefined;\n\ntype Side = \"top\" | \"bottom\";\n\ntype PositionerElementProps = ComponentProps<\"div\"> & {\n side: string;\n onSideChange: (side: Side) => void;\n};\n\n/**\n * The popup's positioner, which also reports the side it ended up on. The\n * field squares the corners on that side so the two read as one shape, and\n * the popup is in a portal where the field's CSS cannot see it.\n */\nfunction PositionerElement({\n side,\n onSideChange,\n ...props\n}: PositionerElementProps) {\n useEffect(() => {\n onSideChange(side === \"top\" ? \"top\" : \"bottom\");\n }, [side, onSideChange]);\n\n return <div {...props} />;\n}\n\nexport function SelectField({\n label,\n helperText,\n error = false,\n required = false,\n disabled = false,\n placeholder,\n startAdornment,\n endAdornment,\n open: openProp,\n onOpenChange,\n onBlur,\n name,\n id,\n \"aria-label\": ariaLabel,\n \"aria-labelledby\": ariaLabelledBy,\n \"aria-describedby\": ariaDescribedBy,\n className,\n style,\n ref,\n multiple,\n value,\n onValueChange,\n filled,\n display,\n displayHidden = false,\n valueText,\n children,\n}: SelectFieldProps) {\n const generatedId = useId();\n const triggerId = id ?? generatedId;\n const labelId = useId();\n const helperTextId = useId();\n const hasLabel = label != null;\n const hasHelperText = helperText != null;\n\n const [internalOpen, setInternalOpen] = useState(false);\n const open = openProp ?? internalOpen;\n const [side, setSide] = useState<Side>(\"bottom\");\n\n const boxRef = useRef<HTMLDivElement>(null);\n const popupRef = useRef<HTMLDivElement>(null);\n\n // Opening the list moves focus from the trigger into the popup, and\n // choosing moves it back. Neither is leaving the select.\n const handleBlur = useBlurOutside(onBlur, [boxRef, popupRef]);\n\n return (\n <div\n className={join(inputStyles.Field, styles.Field, className)}\n style={style}\n >\n <BaseSelect.Root\n id={triggerId}\n name={name}\n multiple={multiple}\n value={value}\n onValueChange={onValueChange}\n open={open}\n onOpenChange={(next) => {\n if (openProp === undefined) setInternalOpen(next);\n onOpenChange?.(next);\n }}\n disabled={disabled}\n required={required}\n // The keyboard and the mouse each mark their own option, as in a\n // native list: hovering does not move the option the arrow keys are on.\n highlightItemOnHover={false}\n >\n <div\n ref={boxRef}\n className={join(inputStyles.Box, styles.Box)}\n data-invalid={error ? \"\" : undefined}\n data-disabled={disabled ? \"\" : undefined}\n data-has-label={hasLabel ? \"\" : undefined}\n data-has-placeholder={placeholder ? \"\" : undefined}\n data-filled={filled ? \"\" : undefined}\n data-open={open ? \"\" : undefined}\n data-popup-side={open ? side : undefined}\n onBlur={handleBlur}\n >\n <BaseSelect.Trigger\n // Rendered as a `div`, see above; Base UI types the ref for a button.\n ref={ref as Ref<HTMLButtonElement>}\n nativeButton={false}\n render={<div />}\n aria-label={ariaLabel}\n aria-labelledby={ariaLabelledBy ?? (hasLabel ? labelId : undefined)}\n aria-describedby={join(\n hasHelperText && helperTextId,\n ariaDescribedBy,\n )}\n aria-invalid={error || undefined}\n aria-required={required || undefined}\n className={styles.Trigger}\n >\n <span className={styles.SrOnly}>{valueText}</span>\n </BaseSelect.Trigger>\n {startAdornment != null && (\n <span className={inputStyles.Adornment} data-position=\"start\">\n {startAdornment}\n </span>\n )}\n <div className={join(inputStyles.Inner, styles.Inner)}>\n {hasLabel && (\n <span id={labelId} className={styles.Label}>\n {label}\n {required && <RequiredAsterisk />}\n </span>\n )}\n <div\n className={styles.Display}\n aria-hidden={displayHidden || undefined}\n >\n {filled\n ? display\n : placeholder && (\n <span className={styles.Placeholder} aria-hidden>\n {placeholder}\n </span>\n )}\n </div>\n </div>\n {endAdornment != null && (\n <span className={styles.EndAdornment}>{endAdornment}</span>\n )}\n <ChevronDown className={styles.Icon} aria-hidden />\n </div>\n <BaseSelect.Portal>\n <BaseSelect.Positioner\n side=\"bottom\"\n align=\"start\"\n sideOffset={0}\n alignItemWithTrigger={false}\n className={listStyles.Positioner}\n render={(props, state) => (\n <PositionerElement\n {...props}\n side={state.side}\n onSideChange={setSide}\n />\n )}\n >\n <BaseSelect.Popup\n ref={popupRef}\n className={listStyles.Popup}\n onBlur={handleBlur}\n >\n <BaseSelect.List className={listStyles.List}>\n {children}\n </BaseSelect.List>\n </BaseSelect.Popup>\n </BaseSelect.Positioner>\n </BaseSelect.Portal>\n </BaseSelect.Root>\n {hasHelperText && (\n <FieldHelperText id={helperTextId} error={error}>\n {helperText}\n </FieldHelperText>\n )}\n </div>\n );\n}\n\ntype SelectFieldItemProps = {\n option: SelectOption;\n disabled?: boolean;\n /** Content before the label, e.g. the checkbox of `MultiSelect`. */\n children?: ReactNode;\n};\n\n/** One option in the list. */\nexport function SelectFieldItem({\n option,\n disabled,\n children,\n}: SelectFieldItemProps) {\n return (\n <BaseSelect.Item\n value={option.value}\n label={option.label}\n disabled={disabled ?? option.disabled}\n className={listStyles.Item}\n >\n {children}\n <BaseSelect.ItemText className={listStyles.ItemText}>\n {option.label}\n </BaseSelect.ItemText>\n </BaseSelect.Item>\n );\n}\n","\"use client\";\n\nimport {\n useCallback,\n useEffect,\n useLayoutEffect,\n useRef,\n useState,\n type ReactNode,\n type Ref,\n} from \"react\";\n\nimport { Chip } from \"../data-display/chip\";\nimport { CheckboxBox } from \"./checkbox-box\";\nimport {\n SelectField,\n SelectFieldItem,\n type SelectFieldBaseProps,\n type SelectOption,\n} from \"./select-field\";\nimport styles from \"./select.module.css\";\n\ntype SelectedChipsProps = {\n items: SelectOption[];\n canDelete: boolean;\n onDelete: (value: string) => void;\n};\n\n// Gap between chips, in px (`--lea-spacing-0-5` in the stylesheet).\nconst CHIP_GAP = 4;\n\n// `useLayoutEffect` warns when a component is rendered on the server.\nconst useIsoLayoutEffect =\n typeof document === \"undefined\" ? useEffect : useLayoutEffect;\n\n/**\n * Renders the selected values as chips on a single line. When they don't all\n * fit, the overflow is collapsed into a trailing `+N` badge rather than\n * wrapping onto a second line. Widths are measured off-screen so the visible\n * row can reserve room for the badge before deciding how many chips to show.\n */\nfunction SelectedChips({ items, canDelete, onDelete }: SelectedChipsProps) {\n const containerRef = useRef<HTMLDivElement>(null);\n const measureRef = useRef<HTMLDivElement>(null);\n const [visibleCount, setVisibleCount] = useState(items.length);\n\n const recompute = useCallback(() => {\n const container = containerRef.current;\n const measure = measureRef.current;\n if (!container || !measure) return;\n\n const available = container.clientWidth;\n // The measurement row renders every chip followed by a single badge.\n const children = Array.from(measure.children) as HTMLElement[];\n const badgeEl = children[children.length - 1];\n const chipEls = children.slice(0, -1);\n const badgeWidth = badgeEl ? badgeEl.offsetWidth + CHIP_GAP : 0;\n\n const total = chipEls.reduce(\n (sum, el, index) => sum + el.offsetWidth + (index > 0 ? CHIP_GAP : 0),\n 0,\n );\n if (total <= available) {\n setVisibleCount(items.length);\n return;\n }\n\n let used = 0;\n let count = 0;\n for (let i = 0; i < chipEls.length; i++) {\n const next = chipEls[i].offsetWidth + (i > 0 ? CHIP_GAP : 0);\n if (used + next + badgeWidth <= available) {\n used += next;\n count += 1;\n } else {\n break;\n }\n }\n setVisibleCount(count);\n }, [items.length]);\n\n const itemsKey = items.map((item) => item.value).join(\"|\");\n\n useIsoLayoutEffect(() => {\n recompute();\n // Re-measure when the set of chips or the delete affordance changes.\n }, [recompute, itemsKey, canDelete]);\n\n useEffect(() => {\n const container = containerRef.current;\n if (!container || typeof ResizeObserver === \"undefined\") return;\n const observer = new ResizeObserver(() => recompute());\n observer.observe(container);\n return () => observer.disconnect();\n }, [recompute]);\n\n const hiddenCount = Math.max(items.length - visibleCount, 0);\n\n const renderChip = (item: SelectOption) => (\n <Chip\n key={item.value}\n size=\"sm\"\n label={item.label}\n style={{ flexShrink: 0, maxWidth: \"100%\" }}\n onDelete={canDelete ? () => onDelete(item.value) : undefined}\n />\n );\n\n const badge = (count: number) => (\n <Chip\n color=\"neutral\"\n size=\"sm\"\n label={`+${count}`}\n style={{ flexShrink: 0 }}\n />\n );\n\n return (\n <div className={styles.Chips}>\n {/* Off-screen measurement row: always renders every chip + a badge. */}\n <div ref={measureRef} aria-hidden className={styles.ChipMeasure}>\n {items.map((item) => renderChip(item))}\n {badge(items.length)}\n </div>\n\n <div ref={containerRef} className={styles.ChipRow}>\n {items.slice(0, visibleCount).map((item) => renderChip(item))}\n {hiddenCount > 0 && badge(hiddenCount)}\n </div>\n </div>\n );\n}\n\nexport type MultiSelectProps<Value extends string = string> =\n SelectFieldBaseProps & {\n /** The choices, shown with a checkbox each. */\n options: readonly SelectOption<Value>[];\n /** Currently selected values (controlled). */\n value?: Value[];\n /** Initially selected values (uncontrolled). */\n defaultValue?: Value[];\n /** Called with the next array of selected values. */\n onValueChange?: (value: Value[]) => void;\n /** Minimum number of values that must stay selected. @default 1 */\n min?: number;\n /** Maximum number of values that can be selected. Unlimited when omitted. */\n max?: number;\n /** Override how the selected values are summarised in the closed control. */\n renderValue?: (selected: Value[]) => ReactNode;\n };\n\n/**\n * Multi-select on Base UI's `Select`, in the same box as `Select`, with the\n * label, the helper text and their ids wired. Each option has a checkbox, and\n * the closed control shows the selection as removable chips by default.\n *\n * The selection is bounded by `min` (default 1, so the last value can't be\n * removed) and `max` (unlimited by default): options that would breach either\n * bound are disabled, and the constraints are also enforced on change.\n *\n * Works controlled (`value`) or uncontrolled (`defaultValue`).\n */\nexport function MultiSelect<Value extends string = string>({\n options,\n value,\n defaultValue = [],\n onValueChange,\n renderValue,\n min = 1,\n max,\n disabled = false,\n ref,\n ...rest\n}: MultiSelectProps<Value>) {\n const isControlled = value !== undefined;\n const [internal, setInternal] = useState<Value[]>(defaultValue);\n const selected = isControlled ? value : internal;\n\n const triggerRef = useRef<HTMLElement | null>(null);\n const setTrigger: Ref<HTMLElement> = (element) => {\n triggerRef.current = element;\n if (typeof ref === \"function\") return ref(element);\n if (ref) ref.current = element;\n };\n\n const atMax = max !== undefined && selected.length >= max;\n const atMin = selected.length <= min;\n\n const commit = (next: Value[]) => {\n if (!isControlled) setInternal(next);\n onValueChange?.(next);\n };\n\n const handleChange = (next: Value[]) => {\n // Enforce the bounds even if a disabled option is somehow toggled.\n const isAdding = next.length > selected.length;\n if (isAdding && max !== undefined && next.length > max) return;\n const isRemoving = next.length < selected.length;\n if (isRemoving && next.length < min) return;\n\n commit(next);\n };\n\n const handleDelete = (valueToRemove: string) => {\n if (selected.length <= min) return;\n commit(selected.filter((v) => v !== valueToRemove));\n // The button that was pressed is gone; keep focus in the field.\n triggerRef.current?.focus();\n };\n\n const canDelete = !disabled && selected.length > min;\n\n // In the order they were chosen, like the chips of a tag field.\n const selectedOptions = selected.map(\n (v): SelectOption =>\n options.find((option) => option.value === v) ?? { value: v, label: v },\n );\n\n return (\n <SelectField\n {...rest}\n ref={setTrigger}\n disabled={disabled}\n multiple\n value={selected}\n onValueChange={(next) => handleChange((next ?? []) as Value[])}\n filled={selected.length > 0}\n display={\n renderValue ? (\n renderValue(selected)\n ) : (\n <SelectedChips\n items={selectedOptions}\n canDelete={canDelete}\n onDelete={handleDelete}\n />\n )\n }\n valueText={selectedOptions.map((option) => option.label).join(\", \")}\n >\n {options.map((option) => {\n const isSelected = selected.includes(option.value);\n const atBound = (atMax && !isSelected) || (atMin && isSelected);\n return (\n <SelectFieldItem\n key={option.value}\n option={option}\n disabled={atBound || option.disabled}\n >\n {/* A picture of the state. The option itself is what gets picked. */}\n <CheckboxBox checked={isSelected} />\n </SelectFieldItem>\n );\n })}\n </SelectField>\n );\n}\n","export type Country = \"NO\" | \"SE\" | \"FI\" | \"ES\";\n\nexport type Currency = \"NOK\" | \"SEK\" | \"EUR\";\n\nexport interface CountryConfig {\n country: Country;\n locale: string;\n currency: Currency;\n}\n\nexport const COUNTRIES: Record<Country, CountryConfig> = {\n NO: { country: \"NO\", locale: \"nb-NO\", currency: \"NOK\" },\n SE: { country: \"SE\", locale: \"sv-SE\", currency: \"SEK\" },\n FI: { country: \"FI\", locale: \"fi-FI\", currency: \"EUR\" },\n ES: { country: \"ES\", locale: \"es-ES\", currency: \"EUR\" },\n};\n","import { isValidElement, type ReactNode } from \"react\";\n\nimport {\n COUNTRIES,\n type Country,\n type Currency,\n} from \"../../hooks/country/countries\";\nimport type { Language } from \"../../i18n\";\n\n/**\n * A unit the library writes for you, in the language of `LeaProvider`:\n *\n * - `{ type: \"years\" }`: \"år\", \"vuotta\", \"años\". The word follows the number\n * in the field, so Finnish and Spanish read \"1 vuosi\" and \"2 vuotta\",\n * \"1 año\" and \"2 años\".\n * - `{ type: \"currency\" }`: the symbol of the currency, \"kr\" or \"€\". The\n * currency is the one of the language (`no` NOK, `se` SEK, `fi` and `es`\n * EUR); pass `currency` for another.\n */\nexport type NumberInputUnitSpec =\n { type: \"years\" } | { type: \"currency\"; currency?: Currency };\n\n/** What `NumberInput` takes as `unit`: your own content, or a unit spec. */\nexport type NumberInputUnit = ReactNode | NumberInputUnitSpec;\n\nconst COUNTRY_OF_LANGUAGE: Record<Language, Country> = {\n no: \"NO\",\n se: \"SE\",\n fi: \"FI\",\n es: \"ES\",\n};\n\n/** A spec, as opposed to a string, a number or an element. */\nexport function isUnitSpec(unit: NumberInputUnit): unit is NumberInputUnitSpec {\n return (\n typeof unit === \"object\" &&\n unit !== null &&\n !isValidElement(unit) &&\n \"type\" in unit &&\n (unit.type === \"years\" || unit.type === \"currency\")\n );\n}\n\n/**\n * The text of a unit spec for a language. `value` picks the plural of \"years\"\n * and is ignored for a currency; an empty field counts as zero.\n */\nexport function formatUnit(\n unit: NumberInputUnitSpec,\n language: Language,\n value: number | null | undefined,\n): string {\n const { locale, currency: languageCurrency } =\n COUNTRIES[COUNTRY_OF_LANGUAGE[language]];\n\n const options: Intl.NumberFormatOptions =\n unit.type === \"years\"\n ? { style: \"unit\", unit: \"year\", unitDisplay: \"long\" }\n : {\n style: \"currency\",\n currency: unit.currency ?? languageCurrency,\n currencyDisplay: \"narrowSymbol\",\n };\n\n // Only the unit is wanted. `formatToParts` hands it over on its own, in the\n // right plural, without the number next to it.\n const part = new Intl.NumberFormat(locale, options)\n .formatToParts(unit.type === \"years\" ? (value ?? 0) : 0)\n .find((p) => p.type === (unit.type === \"years\" ? \"unit\" : \"currency\"));\n\n return part?.value ?? \"\";\n}\n","/*\n * Design tokens come from src/theme/tokens.css, generated from src/theme/tokens\n * by `pnpm tokens:css`. It is a plain stylesheet rather than runtime-injected\n * CSS variables, so this component renders correctly without a provider.\n *\n * The field itself is the box of `Input`, from input.module.css. This file\n * adds what only a number field has: the unit and the stepper buttons.\n */\n\n/* With the label above the field, nothing floats, so the value is centred. */\n.Box[data-label-outside] input {\n padding-block: calc(\n (var(--input-height) - var(--lea-text-body-md-line-height) * 1em) / 2\n );\n}\n\n/* The unit, set off from the value by a short line. */\n.Unit {\n display: flex;\n flex-shrink: 0;\n align-items: center;\n align-self: center;\n padding-inline-start: var(--lea-spacing-1-5);\n border-inline-start: 1px solid var(--lea-palette-border-subtle);\n margin-inline-end: var(--lea-spacing-1);\n color: var(--lea-palette-text-subtle);\n /* Tighter than body text, which sets how tall the line beside it is. */\n line-height: var(--lea-line-height-tight);\n white-space: nowrap;\n}\n\n.Box[data-disabled] .Unit {\n color: var(--lea-palette-text-muted);\n}\n\n.Steppers {\n display: flex;\n flex-shrink: 0;\n align-self: center;\n gap: var(--lea-spacing-0-5);\n margin-inline: var(--lea-spacing-1);\n}\n\n/* Next to a unit, the unit's own margin is the gap. */\n.Unit + .Steppers {\n margin-inline-start: 0;\n}\n\n.Stepper {\n --stepper-tint: color-mix(\n in srgb,\n var(--lea-palette-text-base) calc(var(--lea-opacity-hover) * 100%),\n transparent\n );\n\n display: inline-flex;\n width: 2.25rem;\n height: 2.25rem;\n box-sizing: border-box;\n align-items: center;\n justify-content: center;\n padding: 0;\n border: 2px solid var(--lea-palette-border-subtle);\n border-radius: var(--lea-radius-full);\n background-color: transparent;\n color: var(--lea-palette-text-subtle);\n cursor: pointer;\n transition: background-color var(--lea-duration-normal)\n var(--lea-easing-standard);\n}\n\n.Stepper svg {\n display: block;\n flex-shrink: 0;\n}\n\n.Stepper:focus-visible {\n outline: 2px solid var(--lea-palette-text-base);\n outline-offset: 0.125rem;\n}\n\n.Stepper[data-disabled] {\n color: var(--lea-palette-text-muted);\n cursor: not-allowed;\n}\n\n@media (hover: hover) {\n .Stepper:hover:not([data-disabled]) {\n background-color: var(--stepper-tint);\n }\n}\n\n@media (prefers-reduced-motion: reduce) {\n .Stepper {\n transition-duration: 0.01ms;\n }\n}\n","\"use client\";\n\nimport { NumberField as BaseNumberField } from \"@base-ui/react/number-field\";\nimport { Minus, Plus } from \"lucide-react\";\nimport {\n useId,\n useState,\n type CSSProperties,\n type MouseEvent,\n type ReactNode,\n type Ref,\n} from \"react\";\n\nimport { createTranslation, useLanguage } from \"../../i18n\";\nimport {\n FieldGroupLabel,\n FieldHelperText,\n fieldMessage,\n RequiredAsterisk,\n} from \"./field-parts\";\nimport inputStyles from \"./input.module.css\";\nimport {\n formatUnit,\n isUnitSpec,\n type NumberInputUnit,\n} from \"./number-input-unit\";\nimport styles from \"./number-input.module.css\";\n\nexport type { NumberInputUnit, NumberInputUnitSpec } from \"./number-input-unit\";\n\nexport type NumberInputProps = Omit<\n BaseNumberField.Root.Props,\n \"ref\" | \"inputRef\" | \"render\" | \"className\" | \"style\"\n> & {\n /** The visible `<input>`. */\n ref?: Ref<HTMLInputElement>;\n /** The label, linked to the input for you. */\n label?: ReactNode;\n /** Floating inside the field, or as a line above it. @default \"inside\" */\n labelPlacement?: \"inside\" | \"outside\";\n /**\n * Help text behind an info button next to the label. Needs\n * `labelPlacement=\"outside\"`: a floating label has no room for it.\n */\n tooltip?: ReactNode;\n /** Helper / error text shown below the control and linked via `aria-describedby`. */\n helperText?: ReactNode;\n /** Renders the field in its error state (border, label and helper colour). */\n error?: boolean;\n /**\n * A message for a value that is allowed but unusual, such as an unusually\n * high amount. Shown in amber in place of the helper text, without the\n * error state: the field is not marked invalid. `error` wins when both are set.\n */\n warning?: ReactNode;\n /** Reflects `required` onto the control and the label asterisk. */\n required?: boolean;\n /** Disables the input and the stepper buttons. */\n disabled?: boolean;\n /** Placeholder shown while the field is empty. */\n placeholder?: string;\n /**\n * Decorative leading icon (e.g. a category glyph). Rendered `aria-hidden`, so\n * the visible label must carry the meaning.\n */\n startIcon?: ReactNode;\n /**\n * Trailing unit shown inside the field. Rendered as real text linked to the\n * input via `aria-describedby` — not a placeholder — so it is announced and\n * survives typing.\n *\n * - Your own content: `unit=\"kr/mnd\"`. It is not translated.\n * - `{ type: \"years\" }`: \"år\", \"vuotta\" or \"años\" in the language of\n * `LeaProvider`, in the plural that fits the number in the field.\n * - `{ type: \"currency\" }`: \"kr\" or \"€\" for the language (`{ type:\n * \"currency\", currency: \"EUR\" }` for another currency).\n */\n unit?: NumberInputUnit;\n /**\n * Whether to render the increment / decrement stepper buttons.\n * @default true\n */\n showSteppers?: boolean;\n /** Class on the outermost element, for layout. */\n className?: string;\n /** Inline style on the outermost element, for layout. */\n style?: CSSProperties;\n};\n\nconst join = (...parts: (string | false | null | undefined)[]) =>\n parts.filter(Boolean).join(\" \") || undefined;\n\n/**\n * Numeric input built on Base UI's `NumberField` (value / min / max / step /\n * formatting), in the same box as `Input`, with increment / decrement buttons.\n *\n * The label, the helper text and the ids that link them to the input are all\n * rendered and wired for you. Set `labelPlacement=\"outside\"` for a label above\n * the field, which can also carry a `tooltip`.\n *\n * For money and other open-ended amounts, set `showSteppers={false}` and use a\n * `unit` (e.g. `kr`) instead — a stepper is only helpful for small bounded\n * counts.\n *\n * `unit` takes your own text, or a unit the library writes in the language of\n * `LeaProvider`:\n *\n * ```tsx\n * <NumberInput label=\"Lånebeløp\" unit={{ type: \"currency\" }} showSteppers={false} />\n * <NumberInput label=\"Nedbetalingstid\" unit={{ type: \"years\" }} min={1} max={15} />\n * ```\n */\nexport function NumberInput({\n label,\n labelPlacement = \"inside\",\n tooltip,\n helperText,\n error = false,\n warning,\n required = false,\n disabled = false,\n id,\n placeholder,\n startIcon,\n unit,\n showSteppers = true,\n className,\n style,\n ref,\n value,\n defaultValue,\n onValueChange,\n ...rest\n}: NumberInputProps) {\n const language = useLanguage();\n // The plural of \"years\" follows the number in the field, controlled or not.\n const [typedValue, setTypedValue] = useState(defaultValue ?? null);\n const currentValue = value !== undefined ? value : typedValue;\n const unitContent = isUnitSpec(unit)\n ? formatUnit(unit, language, currentValue)\n : unit;\n const generatedId = useId();\n const inputId = id ?? generatedId;\n const labelId = useId();\n const helperTextId = useId();\n const unitId = useId();\n const stepperLabels = useStepperLabels();\n\n const hasLabel = label != null;\n const labelOutside = hasLabel && labelPlacement === \"outside\";\n const message = fieldMessage(helperText, warning, error);\n const hasHelperText = message.content != null;\n\n // The input is described by any combination of helper text + the trailing\n // unit, in reading order, and never points at an element that isn't rendered.\n const describedBy = join(\n hasHelperText && helperTextId,\n unitContent != null && unitContent !== \"\" && unitId,\n );\n\n // The label, the padding, the icon and the unit are part of the field, so a\n // click on any of them goes to the input. The stepper buttons keep theirs.\n const focusInput = (event: MouseEvent<HTMLDivElement>) => {\n const target = event.target as Element;\n if (target.closest(\"button, a, input, [tabindex]\")) return;\n event.currentTarget.querySelector(\"input\")?.focus();\n };\n\n return (\n <BaseNumberField.Root\n {...rest}\n value={value}\n defaultValue={defaultValue}\n onValueChange={(next, details) => {\n setTypedValue(next);\n onValueChange?.(next, details);\n }}\n id={inputId}\n disabled={disabled}\n required={required}\n className={join(inputStyles.Field, className)}\n style={style}\n >\n {labelOutside && (\n <FieldGroupLabel\n id={labelId}\n htmlFor={inputId}\n tooltip={tooltip}\n required={required}\n error={error}\n disabled={disabled}\n >\n {label}\n </FieldGroupLabel>\n )}\n <div\n className={join(inputStyles.Box, styles.Box)}\n data-invalid={error ? \"\" : undefined}\n data-disabled={disabled ? \"\" : undefined}\n data-has-label={hasLabel && !labelOutside ? \"\" : undefined}\n data-label-outside={labelOutside ? \"\" : undefined}\n onClick={focusInput}\n >\n {startIcon != null && (\n <span\n className={inputStyles.Adornment}\n data-position=\"start\"\n aria-hidden\n >\n {startIcon}\n </span>\n )}\n <div className={inputStyles.Inner}>\n {hasLabel && !labelOutside && (\n <label htmlFor={inputId} className={inputStyles.Label}>\n {label}\n {required && <RequiredAsterisk />}\n </label>\n )}\n <BaseNumberField.Input\n ref={ref}\n // Never empty: `:placeholder-shown` is how the stylesheet tells an\n // empty field from a filled one, and it needs a placeholder to work.\n placeholder={placeholder || \" \"}\n aria-invalid={error || undefined}\n aria-describedby={describedBy}\n className={inputStyles.Control}\n />\n </div>\n {unitContent != null && unitContent !== \"\" && (\n <span id={unitId} className={styles.Unit}>\n {unitContent}\n </span>\n )}\n {showSteppers && (\n <span className={styles.Steppers}>\n <BaseNumberField.Decrement\n aria-label={stepperLabels.decrease}\n className={styles.Stepper}\n >\n <Minus size={16} aria-hidden />\n </BaseNumberField.Decrement>\n <BaseNumberField.Increment\n aria-label={stepperLabels.increase}\n className={styles.Stepper}\n >\n <Plus size={16} aria-hidden />\n </BaseNumberField.Increment>\n </span>\n )}\n </div>\n {hasHelperText && (\n <FieldHelperText\n id={helperTextId}\n error={error}\n warning={message.warning}\n >\n {message.content}\n </FieldHelperText>\n )}\n </BaseNumberField.Root>\n );\n}\n\nconst useStepperLabels = createTranslation({\n increase: {\n no: \"Øk\",\n se: \"Öka\",\n fi: \"Lisää\",\n es: \"Aumentar\",\n },\n decrease: {\n no: \"Reduser\",\n se: \"Minska\",\n fi: \"Vähennä\",\n es: \"Disminuir\",\n },\n});\n","import {\n getCountries,\n getCountryCallingCode,\n type CountryCode,\n} from \"libphonenumber-js\";\n\nexport type { CountryCode };\n\n/**\n * Countries surfaced at the top of the country-code select. Lea Bank's core\n * markets, in priority order. The rest of the world follows, sorted by their\n * localised name.\n */\nexport const PINNED_COUNTRIES: readonly CountryCode[] = [\n \"FI\",\n \"SE\",\n \"NO\",\n \"ES\",\n];\n\nexport interface CountryOption {\n /** ISO 3166-1 alpha-2 code, e.g. `\"FI\"`. */\n code: CountryCode;\n /** International dialling code without the leading `+`, e.g. `\"358\"`. */\n dialCode: string;\n /** Localised country name, e.g. `\"Finland\"`. */\n name: string;\n /** Flag emoji derived from the ISO code. Purely decorative. */\n flag: string;\n /** Whether this is one of the pinned core-market countries. */\n pinned: boolean;\n}\n\n/**\n * Turns a two-letter ISO country code into its flag emoji by mapping each\n * letter to the matching Unicode regional-indicator symbol. No asset library\n * needed — the platform renders the pair as a flag.\n */\nexport function flagEmoji(code: string): string {\n return code\n .toUpperCase()\n .replace(/[A-Z]/g, (char) =>\n String.fromCodePoint(127397 + char.charCodeAt(0)),\n );\n}\n\n/**\n * Builds the ordered country list for the select: the pinned core markets\n * first, then every remaining country sorted by its name in the given locale.\n * Country names come from `Intl.DisplayNames`, so they follow the active locale\n * with no hand-maintained list.\n */\nexport function getCountryOptions(locale: string): CountryOption[] {\n const displayNames = new Intl.DisplayNames([locale], { type: \"region\" });\n const all = getCountries();\n\n const toOption = (code: CountryCode, pinned: boolean): CountryOption => ({\n code,\n dialCode: getCountryCallingCode(code),\n name: displayNames.of(code) ?? code,\n flag: flagEmoji(code),\n pinned,\n });\n\n const pinned = PINNED_COUNTRIES.filter((code) => all.includes(code)).map(\n (code) => toOption(code, true),\n );\n\n const rest = all\n .filter((code) => !PINNED_COUNTRIES.includes(code))\n .map((code) => toOption(code, false))\n .sort((a, b) => a.name.localeCompare(b.name, locale));\n\n return [...pinned, ...rest];\n}\n","/*\n * Design tokens come from src/theme/tokens.css, generated from src/theme/tokens\n * by `pnpm tokens:css`. It is a plain stylesheet rather than runtime-injected\n * CSS variables, so this component renders correctly without a provider.\n *\n * The box, its border states, the label and the text field come from\n * input.module.css, and the options from option-list.module.css; this file\n * adds the country button at the start of the field and the popup it opens.\n */\n\n/*\n * `.Field` in front of a selector lifts it over the rules of input.module.css\n * for the same element, whichever of the two stylesheets loads last.\n */\n\n/* The country list is in a portal, so focus is not inside the box while it is open. */\n.Field .Box[data-country-open]:not([data-invalid]) {\n --input-border-color: var(--lea-palette-border-accent);\n --input-border-width: 2px;\n}\n\n/*\n * The label is always up: the country button takes the place where it would\n * rest, and with it up there is room for a placeholder that shows the format.\n */\n.Field .Label {\n max-width: calc(\n (100% - var(--input-inset-start) - var(--input-padding-inline)) / 0.75\n );\n scale: 0.75;\n translate: 0 calc(var(--lea-spacing) * 0.75);\n}\n\n.Field .Inner {\n /* 10px between the line after the country button and the number. */\n --input-inset-start: calc(var(--lea-spacing) * 1.25);\n}\n\n.Trigger {\n display: flex;\n flex-shrink: 0;\n align-items: center;\n padding-block: 0;\n padding-inline: var(--lea-spacing-1) var(--lea-spacing-0-5);\n border: 0;\n /* The line between the country and the number. */\n border-inline-end: 1px solid var(--lea-palette-border-subtle);\n border-radius: var(--lea-radius-xl) 0 0 var(--lea-radius-xl);\n margin: 0;\n background: none;\n color: var(--lea-palette-text-base);\n cursor: pointer;\n font: inherit;\n gap: var(--lea-spacing-0-5);\n letter-spacing: inherit;\n white-space: nowrap;\n}\n\n@media (hover: hover) {\n .Trigger:hover:not(:disabled) {\n background-color: var(--lea-palette-bg-subtle);\n }\n}\n\n.Trigger[data-popup-open] {\n background-color: var(--lea-palette-bg-subtle);\n}\n\n/*\n * The dial code of a field with one country (`countries` of one): the\n * country button without the button. Same place, line and type, so a form\n * with both kinds lines up; no chevron and no hover, as there is nothing to\n * open.\n */\n.DialCode {\n display: flex;\n flex-shrink: 0;\n align-items: center;\n padding-inline: var(--lea-spacing-1);\n border-inline-end: 1px solid var(--lea-palette-border-subtle);\n color: var(--lea-palette-text-base);\n gap: var(--lea-spacing-0-5);\n white-space: nowrap;\n}\n\n.Box[data-disabled] .DialCode {\n opacity: 0.6;\n}\n\n/* Inside the border of the field, which a ring around the button would cover. */\n.Trigger:focus-visible {\n outline: 2px solid var(--lea-palette-text-base);\n outline-offset: -0.25rem;\n}\n\n.Trigger:disabled {\n cursor: not-allowed;\n opacity: 0.6;\n}\n\n/* One step up the type scale: a flag at the size of the text reads as smaller than it. */\n.Flag {\n font-size: var(--lea-font-step-1);\n line-height: var(--lea-line-height-none);\n}\n\n/* One width for every dial code, +1 or +358, so the number does not move with the country. */\n.Dial {\n min-width: 2.5rem;\n text-align: center;\n}\n\n.Chevron {\n width: 1rem;\n height: 1rem;\n flex-shrink: 0;\n color: var(--lea-palette-text-subtle);\n}\n\n/* As wide as the field, a little below it. */\n.Popup {\n overflow: hidden;\n width: var(--anchor-width);\n max-width: var(--available-width);\n box-sizing: border-box;\n border: 1px solid var(--lea-palette-border-accent);\n border-radius: var(--lea-radius-4xl);\n background-color: var(--lea-palette-bg-base);\n box-shadow: var(--lea-shadow-lg);\n color: var(--lea-palette-text-base);\n outline: none;\n transition: opacity var(--lea-duration-fast) var(--lea-easing-standard);\n}\n\n/*\n * The popup fades in, and goes at once: opened again while on its way out, it\n * came back with the search text it was closed with. See combo-field.module.css.\n */\n.Popup[data-starting-style] {\n opacity: 0;\n}\n\n.Popup[data-ending-style] {\n transition: none;\n}\n\n.Search {\n display: flex;\n align-items: center;\n padding-block: calc(var(--lea-spacing) * 1.25);\n padding-inline: calc(var(--lea-spacing) * 1.75);\n border-block-end: 1px solid var(--lea-palette-border-subtle);\n gap: var(--lea-spacing-1);\n}\n\n.Search svg {\n width: 1.125rem;\n height: 1.125rem;\n flex-shrink: 0;\n color: var(--lea-palette-text-subtle);\n}\n\n.SearchInput {\n min-width: 0;\n flex: 1;\n padding: 0;\n border: 0;\n margin: 0;\n background: none;\n color: inherit;\n font-family: inherit;\n font-size: var(--lea-text-body-md-font-size);\n font-weight: var(--lea-text-body-md-font-weight);\n letter-spacing: var(--lea-text-body-md-letter-spacing);\n line-height: var(--lea-text-body-md-line-height);\n /* The popup has the border that shows where focus is. */\n outline: none;\n}\n\n.SearchInput::placeholder {\n color: var(--lea-palette-text-muted);\n opacity: 1;\n}\n\n/*\n * 200px: five countries, then it scrolls. Less when the window is short, by\n * the height of the search box above it. The fallback is for the first\n * measurement, see option-list.module.css.\n */\n.List {\n overflow: hidden auto;\n max-height: min(12.5rem, var(--available-height, 100vh) - 4rem);\n}\n\n.Country {\n gap: calc(var(--lea-spacing) * 1.25);\n}\n\n.CountryName {\n overflow: hidden;\n min-width: 0;\n flex: 1;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n/*\n * neutral-600 rather than text-subtle, which falls below 4.5:1 on the fill of\n * a row under the pointer. On the fill of the country in use it takes the\n * colour of the name.\n */\n.CountryDial {\n color: var(--lea-color-neutral-600);\n}\n\n.Country[data-selected] .CountryDial {\n color: inherit;\n}\n\n/* Between the pinned countries and the rest. */\n.Separator {\n flex-shrink: 0;\n height: 1px;\n background-color: var(--lea-palette-border-base);\n}\n\n@media (prefers-reduced-motion: reduce) {\n .Popup {\n transition-duration: 0.01ms;\n }\n}\n","\"use client\";\n\nimport { Combobox } from \"@base-ui/react/combobox\";\nimport {\n AsYouType,\n getCountryCallingCode,\n parsePhoneNumberFromString,\n} from \"libphonenumber-js\";\nimport { ChevronDown, Search } from \"lucide-react\";\nimport {\n Fragment,\n useId,\n useMemo,\n useRef,\n useState,\n type ChangeEvent,\n type ComponentPropsWithoutRef,\n type CSSProperties,\n type FocusEvent,\n type MouseEvent,\n type ReactNode,\n type Ref,\n type RefObject,\n} from \"react\";\n\nimport { createTranslation, useLanguage, type Language } from \"../../../i18n\";\nimport {\n isMobileCountry,\n validateMobileNumber,\n validatePhoneNumber,\n} from \"../../../validation/phone\";\nimport { invalid, valid } from \"../../../validation/types\";\nimport { FieldHelperText, RequiredAsterisk } from \"../field-parts\";\nimport inputStyles from \"../input.module.css\";\nimport listStyles from \"../option-list.module.css\";\nimport {\n getCountryOptions,\n type CountryCode,\n type CountryOption,\n} from \"./countries\";\nimport styles from \"./phone-number-input.module.css\";\n\n/** The default country and the locale used to name/sort the list, per language. */\nconst LANGUAGE_TO_COUNTRY: Record<Language, CountryCode> = {\n no: \"NO\",\n se: \"SE\",\n fi: \"FI\",\n es: \"ES\",\n};\n\nconst LANGUAGE_TO_LOCALE: Record<Language, string> = {\n no: \"nb-NO\",\n se: \"sv-SE\",\n fi: \"fi-FI\",\n es: \"es-ES\",\n};\n\n/** Details reported alongside every change so the consumer can react to validity. */\nexport interface PhoneNumberMeta {\n /** The selected country. */\n country: CountryCode;\n /** Canonical E.164 number when valid (e.g. `\"+358401234567\"`), otherwise `undefined`. */\n e164?: string;\n /** Whether the current number is a valid phone number for the country. */\n isValid: boolean;\n}\n\ntype NativeInputProps = Omit<\n ComponentPropsWithoutRef<\"input\">,\n | \"value\"\n | \"defaultValue\"\n | \"onChange\"\n | \"type\"\n | \"size\"\n | \"color\"\n | \"children\"\n | \"className\"\n | \"style\"\n>;\n\nexport type PhoneNumberInputProps = NativeInputProps & {\n /** Floating label, linked to the input for you. */\n label?: ReactNode;\n /** Helper / error text shown below the control and linked via `aria-describedby`. */\n helperText?: ReactNode;\n /**\n * Puts the input, its label and its helper text into the error state. When\n * set, true or false, the built-in check on blur stays out of it.\n */\n error?: boolean;\n /** Selected country (controlled). Pair with `onCountryChange`. */\n country?: CountryCode;\n /** Initial country when uncontrolled. Defaults to the country for the active locale. */\n defaultCountry?: CountryCode;\n /** Fired when the user picks a different country. */\n onCountryChange?: (country: CountryCode) => void;\n /** The national number as displayed (controlled). Pair with `onValueChange`. */\n value?: string;\n /** Initial national number when uncontrolled. */\n defaultValue?: string;\n /** Fired on every keystroke with the formatted national number and validity meta. */\n onValueChange?: (value: string, meta: PhoneNumberMeta) => void;\n /**\n * The countries the number may be from. With one, there is no country\n * list: its dial code stands fixed at the start of the field (`+46`). With\n * several, the list holds these alone.\n *\n * Either way the value is the national number without the trunk `0`\n * (`70 123 45 67`): a pasted `+46 70…`, `0046 70…` or `070…` is cleaned up to\n * it, and when focus leaves the field. A number of another country is\n * invalid. Left out, every country is in the list and the number is kept as\n * typed, as before.\n */\n countries?: readonly CountryCode[];\n /**\n * Accept mobile numbers only: a landline is invalid, with a message of its\n * own (\"Skriv inn et mobilnummer\"). Applies to Sweden, Finland, Norway and\n * Spain, as `validateMobileNumber`; a number of another country is checked\n * as any number. `meta.isValid` follows it.\n */\n mobileOnly?: boolean;\n /**\n * Show a built-in \"invalid number\" error once the field is blurred with a\n * non-empty, invalid value. Ignored when the consumer drives `error`.\n * @default true\n */\n validateOnBlur?: boolean;\n /** Class on the outermost element, for layout. */\n className?: string;\n /** Inline style on the outermost element, for layout. */\n style?: CSSProperties;\n /** The phone number `<input>`. */\n ref?: Ref<HTMLInputElement>;\n};\n\n/**\n * Formats the national number as the user types. Norwegian mobile numbers are\n * grouped 3-2-3 (e.g. `400 12 345`), which `libphonenumber-js` doesn't do on its\n * own (it pairs digits as `40 01 23 45`). Every other country keeps the library's\n * standard grouping via `AsYouType`.\n */\nfunction formatNationalNumber(country: CountryCode, input: string): string {\n if (country === \"NO\") {\n const digits = input.replace(/\\D/g, \"\").slice(0, 8);\n return [digits.slice(0, 3), digits.slice(3, 5), digits.slice(5, 8)]\n .filter(Boolean)\n .join(\" \");\n }\n return new AsYouType(country).input(input);\n}\n\n/**\n * The national number, grouped as in the international format but without\n * the dial code, for a field that shows the dial code in front of it:\n * `70 123 45 67` rather than `070-123 45 67`.\n */\nfunction formatWithoutDialCode(country: CountryCode, digits: string): string {\n if (country === \"NO\") return formatNationalNumber(country, digits);\n const dialCode = getCountryCallingCode(country);\n return new AsYouType(country)\n .input(`+${dialCode}${digits}`)\n .replace(`+${dialCode}`, \"\")\n .trim();\n}\n\n/** What typing gives, with the dial code in front of the field. */\nfunction formatTyped(country: CountryCode, text: string): string {\n // Someone typing \"070…\" or \"+46…\" by hand: left as typed until focus\n // leaves the field, rather than losing the first digit under their cursor.\n if (/^\\s*[+0]/.test(text)) return new AsYouType(country).input(text);\n return formatWithoutDialCode(country, text.replace(/\\D/g, \"\"));\n}\n\n/**\n * The text cleaned up to the national number of `country`, when it is a\n * number of that country (`+46 70…`, `0046 70…`, `070…`); otherwise as typed.\n */\nfunction cleanUp(country: CountryCode, text: string): string {\n const parsed = parsePhoneNumberFromString(\n text.replace(/[\\s-]/g, \"\"),\n country,\n );\n if (parsed && parsed.countryCallingCode === getCountryCallingCode(country)) {\n return formatWithoutDialCode(country, parsed.nationalNumber);\n }\n return formatTyped(country, text);\n}\n\ntype NumberCheck = { valid: boolean; normalized?: string; landline: boolean };\n\n/**\n * Validates the number for the field: of the selected country only, when the\n * countries are restricted, and a mobile only, with `mobileOnly`.\n */\nfunction checkNumber(\n country: CountryCode,\n value: string,\n { sameCountry, mobileOnly }: { sameCountry: boolean; mobileOnly: boolean },\n): NumberCheck {\n const ofCountry = () => {\n const parsed = parsePhoneNumberFromString(\n value.replace(/\\s/g, \"\"),\n country,\n );\n return parsed?.isValid() && parsed.country === country\n ? valid(parsed.number)\n : invalid();\n };\n\n if (mobileOnly && isMobileCountry(country)) {\n const mobile = validateMobileNumber(country, value);\n return mobile.valid\n ? { ...mobile, landline: false }\n : { valid: false, landline: ofCountry().valid };\n }\n\n return {\n ...(sameCountry ? ofCountry() : validatePhoneNumber(country, value)),\n landline: false,\n };\n}\n\nconst usePhoneLabels = createTranslation({\n countryLabel: {\n no: \"Landskode\",\n se: \"Landskod\",\n fi: \"Maakoodi\",\n es: \"Código de país\",\n },\n searchCountry: {\n no: \"Søk etter land\",\n se: \"Sök efter land\",\n fi: \"Hae maata\",\n es: \"Buscar país\",\n },\n noCountries: {\n no: \"Ingen land funnet\",\n se: \"Inga länder hittades\",\n fi: \"Maita ei löytynyt\",\n es: \"No se han encontrado países\",\n },\n invalid: {\n no: \"Ugyldig telefonnummer\",\n se: \"Ogiltigt telefonnummer\",\n fi: \"Virheellinen puhelinnumero\",\n es: \"Número de teléfono no válido\",\n },\n notMobile: {\n no: \"Skriv inn et mobilnummer\",\n se: \"Ange ett mobilnummer\",\n fi: \"Anna matkapuhelinnumero\",\n es: \"Introduce un número de móvil\",\n },\n});\n\nconst join = (...parts: (string | false | null | undefined)[]) =>\n parts.filter(Boolean).join(\" \") || undefined;\n\n/** What typing in the search box is matched against. */\nconst searchText = (option: CountryOption) =>\n `${option.name} ${option.code} ${option.dialCode} +${option.dialCode}`;\n\nconst sameCountry = (a: CountryOption, b: CountryOption) => a.code === b.code;\n\ntype CountrySelectProps = {\n options: CountryOption[];\n value: CountryCode;\n onChange: (country: CountryCode) => void;\n ariaLabel: string;\n searchLabel: string;\n noOptionsText: string;\n disabled: boolean;\n open: boolean;\n onOpenChange: (open: boolean) => void;\n /** The field, which the popup sits under and matches in width. */\n anchorRef: RefObject<HTMLDivElement | null>;\n};\n\n/**\n * The country button at the start of the field, and the popup it opens: a\n * search box over the list of countries, on Base UI's `Combobox`. The popup\n * is anchored to the whole field rather than to the button.\n */\nfunction CountrySelect({\n options,\n value,\n onChange,\n ariaLabel,\n searchLabel,\n noOptionsText,\n disabled,\n open,\n onOpenChange,\n anchorRef,\n}: CountrySelectProps) {\n const { contains } = Combobox.useFilter({ sensitivity: \"base\" });\n const [query, setQuery] = useState(\"\");\n // See `ComboField`: the option the arrow keys are on is marked once a key\n // has been pressed, not for a list opened with the mouse.\n const [keyboard, setKeyboard] = useState(false);\n\n const selected = options.find((option) => option.code === value) ?? null;\n const pinnedCount = options.filter((option) => option.pinned).length;\n\n return (\n <Combobox.Root<CountryOption>\n items={options}\n value={selected}\n onValueChange={(next) => {\n if (next) onChange(next.code);\n }}\n inputValue={query}\n onInputValueChange={setQuery}\n open={open}\n onOpenChange={onOpenChange}\n filter={(option, text) => contains(searchText(option), text)}\n itemToStringLabel={(option) => option.name}\n itemToStringValue={(option) => option.code}\n isItemEqualToValue={sameCountry}\n disabled={disabled}\n highlightItemOnHover={false}\n >\n <Combobox.Trigger\n className={styles.Trigger}\n aria-label={selected ? `${ariaLabel}, ${selected.name}` : ariaLabel}\n >\n {selected && (\n <>\n <span aria-hidden className={styles.Flag}>\n {selected.flag}\n </span>\n <span className={styles.Dial}>+{selected.dialCode}</span>\n </>\n )}\n <ChevronDown aria-hidden className={styles.Chevron} />\n </Combobox.Trigger>\n <Combobox.Portal>\n <Combobox.Positioner\n anchor={anchorRef}\n side=\"bottom\"\n align=\"start\"\n sideOffset={4}\n className={listStyles.Positioner}\n >\n <Combobox.Popup\n className={styles.Popup}\n // Base UI makes the popup a dialog, which needs a name.\n aria-label={ariaLabel}\n data-keyboard={keyboard ? \"\" : undefined}\n onKeyDownCapture={() => setKeyboard(true)}\n onPointerDownCapture={() => setKeyboard(false)}\n >\n <div className={styles.Search}>\n <Search aria-hidden />\n <Combobox.Input\n className={styles.SearchInput}\n placeholder={searchLabel}\n aria-label={searchLabel}\n />\n </div>\n <Combobox.Empty className={listStyles.Empty}>\n {noOptionsText}\n </Combobox.Empty>\n <Combobox.List className={join(listStyles.List, styles.List)}>\n {(option: CountryOption, index: number) => (\n <Fragment key={option.code}>\n {query === \"\" && pinnedCount > 0 && index === pinnedCount && (\n // A line to look at only: a listbox may hold nothing but\n // options, so it has no role of its own.\n <div role=\"presentation\" className={styles.Separator} />\n )}\n <Combobox.Item\n value={option}\n className={join(listStyles.Item, styles.Country)}\n >\n <span aria-hidden className={styles.Flag}>\n {option.flag}\n </span>\n <span className={styles.CountryName}>{option.name}</span>\n <span className={styles.CountryDial}>\n +{option.dialCode}\n </span>\n </Combobox.Item>\n </Fragment>\n )}\n </Combobox.List>\n </Combobox.Popup>\n </Combobox.Positioner>\n </Combobox.Portal>\n </Combobox.Root>\n );\n}\n\n/**\n * Phone number input with a searchable country-code picker at its start, in\n * the same box as `Input`. The number is formatted as you type and validated\n * with `libphonenumber-js`. Lea Bank's core markets (Finland, Sweden, Norway,\n * Spain) are pinned to the top of the country list; the default country follows\n * the active locale.\n *\n * The label, the helper text and the ids that link them to the input are all\n * rendered and wired for you. Takes the native `<input>` attributes (`name`,\n * `placeholder`, `onBlur`, `autoComplete`, …), which land on the number input.\n *\n * Both country and number can be **controlled** (`country` + `onCountryChange`,\n * `value` + `onValueChange`) or left **uncontrolled** (`defaultCountry` /\n * `defaultValue`).\n */\nexport function PhoneNumberInput({\n label,\n helperText,\n error,\n required = false,\n disabled = false,\n id,\n country,\n defaultCountry,\n onCountryChange,\n value,\n defaultValue,\n onValueChange,\n onBlur,\n countries,\n mobileOnly = false,\n validateOnBlur = true,\n className,\n style,\n ref,\n \"aria-describedby\": ariaDescribedBy,\n ...inputAttributes\n}: PhoneNumberInputProps) {\n const language = useLanguage();\n const t = usePhoneLabels();\n const generatedId = useId();\n const inputId = id ?? generatedId;\n const helperTextId = useId();\n const dialCodeId = useId();\n const boxRef = useRef<HTMLDivElement>(null);\n const [countryOpen, setCountryOpen] = useState(false);\n\n // Restricted to `countries`; with one, its dial code is fixed in front.\n const allowed = countries != null && countries.length > 0 ? countries : null;\n const fixed = allowed?.length === 1;\n const allowedKey = allowed?.join(\",\");\n\n // Keyed by the codes, as `countries` may be a new array on every render.\n const options = useMemo(() => {\n const all = getCountryOptions(LANGUAGE_TO_LOCALE[language]);\n const codes = allowedKey?.split(\",\");\n return codes ? all.filter((option) => codes.includes(option.code)) : all;\n }, [language, allowedKey]);\n\n const preferredCountry = defaultCountry ?? LANGUAGE_TO_COUNTRY[language];\n const [countryState, setCountryState] = useState<CountryCode>(\n allowed && !allowed.includes(preferredCountry)\n ? allowed[0]\n : preferredCountry,\n );\n const currentCountry = country ?? countryState;\n const checkOptions = { sameCountry: allowed != null, mobileOnly };\n\n const [valueState, setValueState] = useState<string>(defaultValue ?? \"\");\n const currentValue = value ?? valueState;\n\n const [touched, setTouched] = useState(false);\n\n const check = checkNumber(currentCountry, currentValue, checkOptions);\n const meta: PhoneNumberMeta = {\n country: currentCountry,\n e164: check.normalized,\n isValid: check.valid,\n };\n\n const showValidationError =\n validateOnBlur && touched && currentValue.trim() !== \"\" && !meta.isValid;\n const resolvedError = error ?? showValidationError;\n const resolvedHelper =\n helperText ??\n (showValidationError\n ? check.landline\n ? t.notMobile\n : t.invalid\n : undefined);\n const hasHelperText = resolvedHelper != null;\n\n const emit = (nextValue: string, nextCountry: CountryCode) => {\n const result = checkNumber(nextCountry, nextValue, checkOptions);\n onValueChange?.(nextValue, {\n country: nextCountry,\n e164: result.normalized,\n isValid: result.valid,\n });\n };\n\n const setNumber = (nextValue: string, nextCountry: CountryCode) => {\n if (value === undefined) setValueState(nextValue);\n if (nextCountry !== currentCountry) {\n if (country === undefined) setCountryState(nextCountry);\n onCountryChange?.(nextCountry);\n }\n emit(nextValue, nextCountry);\n };\n\n const handleCountryChange = (next: CountryCode) => {\n if (country === undefined) {\n setCountryState(next);\n }\n onCountryChange?.(next);\n // Re-emit so the consumer's meta (e.g. E.164) reflects the new dial code.\n emit(currentValue, next);\n };\n\n const handleInputChange = (event: ChangeEvent<HTMLInputElement>) => {\n const text = event.target.value;\n\n if (!allowed) {\n setNumber(formatNationalNumber(currentCountry, text), currentCountry);\n return;\n }\n\n // More than one character at once: pasted, or filled in by the browser.\n if (text.length - currentValue.length > 1) {\n // A number of another country in the list switches to that country.\n const parsed = parsePhoneNumberFromString(\n text.replace(/[\\s-]/g, \"\"),\n currentCountry,\n );\n const nextCountry =\n parsed?.country && allowed.includes(parsed.country)\n ? parsed.country\n : currentCountry;\n setNumber(cleanUp(nextCountry, text), nextCountry);\n return;\n }\n\n setNumber(formatTyped(currentCountry, text), currentCountry);\n };\n\n const handleBlur = (event: FocusEvent<HTMLInputElement>) => {\n setTouched(true);\n if (allowed) {\n const cleaned = cleanUp(currentCountry, currentValue);\n if (cleaned !== currentValue) setNumber(cleaned, currentCountry);\n }\n onBlur?.(event);\n };\n\n const fixedOption = fixed\n ? options.find((option) => option.code === currentCountry)\n : undefined;\n\n // The label and the padding are part of the field, so a click on them goes\n // to the number, unless it hit the country button. Clicks in the country\n // list arrive here as well, through the portal, and are not for the number.\n const focusInput = (event: MouseEvent<HTMLDivElement>) => {\n const target = event.target as Element;\n if (!event.currentTarget.contains(target)) return;\n if (target.closest(\"button, input\")) return;\n // By type: Base UI keeps a hidden input for the country in here too.\n event.currentTarget\n .querySelector<HTMLElement>('input[type=\"tel\"]')\n ?.focus();\n };\n\n return (\n <div\n className={join(inputStyles.Field, styles.Field, className)}\n style={style}\n >\n <div\n ref={boxRef}\n className={join(inputStyles.Box, styles.Box)}\n data-invalid={resolvedError ? \"\" : undefined}\n data-disabled={disabled ? \"\" : undefined}\n data-country-open={countryOpen ? \"\" : undefined}\n onClick={focusInput}\n >\n {fixed ? (\n fixedOption && (\n // The dial code is read with the field, as its description.\n <span className={styles.DialCode}>\n <span aria-hidden className={styles.Flag}>\n {fixedOption.flag}\n </span>\n <span id={dialCodeId} className={styles.Dial}>\n +{fixedOption.dialCode}\n </span>\n </span>\n )\n ) : (\n <CountrySelect\n options={options}\n value={currentCountry}\n onChange={handleCountryChange}\n ariaLabel={t.countryLabel}\n searchLabel={t.searchCountry}\n noOptionsText={t.noCountries}\n disabled={disabled}\n open={countryOpen}\n onOpenChange={setCountryOpen}\n anchorRef={boxRef}\n />\n )}\n <div className={join(inputStyles.Inner, styles.Inner)}>\n {label != null && (\n <label\n htmlFor={inputId}\n className={join(inputStyles.Label, styles.Label)}\n >\n {label}\n {required && <RequiredAsterisk />}\n </label>\n )}\n <input\n inputMode=\"tel\"\n autoComplete=\"tel-national\"\n {...inputAttributes}\n ref={ref}\n id={inputId}\n type=\"tel\"\n value={currentValue}\n onChange={handleInputChange}\n onBlur={handleBlur}\n disabled={disabled}\n required={required}\n aria-invalid={resolvedError}\n aria-describedby={join(\n fixedOption && dialCodeId,\n hasHelperText && helperTextId,\n ariaDescribedBy,\n )}\n className={inputStyles.Control}\n />\n </div>\n </div>\n {hasHelperText && (\n <FieldHelperText id={helperTextId} error={resolvedError}>\n {resolvedHelper}\n </FieldHelperText>\n )}\n </div>\n );\n}\n","/*\n * Design tokens come from src/theme/tokens.css, generated from src/theme/tokens\n * by `pnpm tokens:css`. It is a plain stylesheet rather than runtime-injected\n * CSS variables, so this component renders correctly without a provider.\n */\n\n/* The options of a `RadioGroup.Root`, one under the other. */\n.Options {\n display: flex;\n flex-direction: column;\n gap: var(--lea-spacing-1);\n}\n\n/*\n * The radio itself: a bordered circle with a dot that springs in when it is\n * chosen. `RadioCard.Indicator` draws the same circle as a picture, from the\n * same classes, so the two can never drift apart.\n */\n.Circle {\n --radio-size: 1.3rem;\n --radio-dot-size: 0.6rem;\n\n display: inline-flex;\n width: var(--radio-size);\n height: var(--radio-size);\n box-sizing: border-box;\n flex-shrink: 0;\n align-items: center;\n justify-content: center;\n padding: 0;\n border: 2px solid var(--lea-palette-border-base);\n border-radius: var(--lea-radius-full);\n margin: 0;\n background-color: var(--lea-palette-bg-base);\n cursor: pointer;\n transition: background-color var(--lea-duration-normal)\n var(--lea-easing-standard),\n border-color var(--lea-duration-normal) var(--lea-easing-standard);\n}\n\n.Circle[data-size=\"sm\"] {\n --radio-size: 1rem;\n --radio-dot-size: 0.45rem;\n}\n\n@media (hover: hover) {\n .Circle:hover:not([data-checked], [data-disabled]) {\n border-color: var(--lea-palette-border-strong);\n }\n}\n\n.Circle[data-checked] {\n border-color: var(--lea-palette-primary-base);\n background-color: var(--lea-palette-primary-base);\n}\n\n.Circle:focus-visible {\n outline: 2px solid var(--lea-palette-text-base);\n outline-offset: 0.125rem;\n}\n\n.Circle[data-disabled] {\n cursor: not-allowed;\n opacity: 0.7;\n}\n\n.Dot {\n width: var(--radio-dot-size);\n height: var(--radio-dot-size);\n border-radius: var(--lea-radius-full);\n background-color: var(--lea-palette-primary-contrast);\n scale: 0;\n transition: scale var(--lea-duration-emphasis) var(--lea-easing-spring);\n}\n\n.Circle[data-checked] .Dot {\n scale: 1;\n}\n\n@media (prefers-reduced-motion: reduce) {\n .Circle,\n .Dot {\n transition-duration: 0.01ms;\n }\n}\n","import styles from \"./radio.module.css\";\n\nexport type RadioSize = \"sm\" | \"md\";\n\n/** The classes of the radio visual, for the real control to wear. */\nexport const radioCircleClassName = styles.Circle;\nexport const radioDotClassName = styles.Dot;\n\nexport type RadioCircleProps = {\n /**\n * Fills the circle and springs the dot in. Leave it out when a parent\n * selector decides instead, as `RadioCard.Root` does for its indicator.\n */\n checked?: boolean;\n size?: RadioSize;\n className?: string;\n};\n\n/**\n * Internal. The radio visual as a picture only, for places where something else\n * is the control: `RadioCard.Indicator` shows it inside a card, and the card's\n * own hidden radio is what gets picked. It looks exactly like\n * `RadioGroup.Item`, which puts the same classes on the real control.\n */\nexport const RadioCircle = ({\n checked = false,\n size = \"md\",\n className,\n}: RadioCircleProps) => (\n <span\n aria-hidden\n className={[styles.Circle, className].filter(Boolean).join(\" \")}\n data-size={size}\n data-checked={checked ? \"\" : undefined}\n >\n <span className={styles.Dot} />\n </span>\n);\n","/*\n * Design tokens come from src/theme/tokens.css, generated from src/theme/tokens\n * by `pnpm tokens:css`. It is a plain stylesheet rather than runtime-injected\n * CSS variables, so this part renders correctly without a provider.\n */\n\n/* The label, the options and the helper text of a radio group, stacked. */\n.Group {\n display: flex;\n width: 100%;\n min-width: 0;\n flex-direction: column;\n}\n","\"use client\";\n\nimport { RadioGroup as BaseRadioGroup } from \"@base-ui/react/radio-group\";\nimport {\n createContext,\n useContext,\n useId,\n useMemo,\n type CSSProperties,\n type FocusEvent,\n type ReactNode,\n type Ref,\n} from \"react\";\n\nimport { FieldGroupLabel, FieldHelperText } from \"./field-parts\";\nimport styles from \"./radio-group-root.module.css\";\nimport type { RadioSize } from \"./radio-circle\";\n\n/** What a radio can stand for. Compared with `===`, so `true` is not `\"true\"`. */\nexport type RadioValue = string | number | boolean;\n\nexport type RadioCardSize = \"sm\" | \"lg\";\n\ntype RadioGroupContextValue = {\n /** Size of the radio circle, set by `RadioGroup.Root`. */\n size?: RadioSize;\n /** Size of the cards, set by `RadioCard.Group`. */\n cardSize?: RadioCardSize;\n};\n\nconst RadioGroupContext = createContext<RadioGroupContextValue | null>(null);\n\n/** Reads the surrounding group. A radio cannot work without one. */\nexport const useRadioGroupContext = (component: string) => {\n const group = useContext(RadioGroupContext);\n if (!group) {\n throw new Error(\n `<${component}> must be rendered inside a <RadioGroup.Root> or <RadioCard.Group>.`,\n );\n }\n return group;\n};\n\n/**\n * Requires an accessible name so the group is never nameless. Provide a\n * visible `label`, or an `aria-label` / `aria-labelledby` when the question\n * is written somewhere else on the page.\n */\ntype RadioGroupAccessibleName =\n | { label: ReactNode; \"aria-label\"?: never; \"aria-labelledby\"?: never }\n | { label?: never; \"aria-label\": string; \"aria-labelledby\"?: never }\n | { label?: never; \"aria-label\"?: never; \"aria-labelledby\": string };\n\n/** The props `RadioGroup.Root` and `RadioCard.Group` have in common. */\nexport type RadioGroupBaseProps<T extends RadioValue> =\n RadioGroupAccessibleName & {\n /** Help text behind an info button next to the label. Needs a `label`. */\n tooltip?: ReactNode;\n /** Helper / error text shown below the options and linked via `aria-describedby`. */\n helperText?: ReactNode;\n /** Puts the group and its helper text into the error state. */\n error?: boolean;\n /** The chosen value (controlled). `null` means nothing is chosen. */\n value?: T | null;\n /** The chosen value when first rendered, for uncontrolled use. */\n defaultValue?: T;\n /** Called with the value of the option the user picks. */\n onValueChange?: (value: T) => void;\n /** Submits the choice under this name when inside a form. */\n name?: string;\n /** Disables every option. */\n disabled?: boolean;\n /** Marks the group as required and adds the asterisk to the label. */\n required?: boolean;\n /** Called when focus leaves the group, not when it moves between options. */\n onBlur?: (event: FocusEvent<HTMLDivElement>) => void;\n /** Id of the element with the `radiogroup` role. */\n id?: string;\n /** Extra ids describing the group, alongside the helper text. */\n \"aria-describedby\"?: string;\n /** Class on the outermost element, for layout. */\n className?: string;\n /** Inline style on the outermost element, for layout. */\n style?: CSSProperties;\n /**\n * The `<input>` of the radio that takes focus: the chosen one, or the\n * first that is not disabled. It is hidden, but `ref.current.focus()`\n * moves focus to the visible radio.\n */\n ref?: Ref<HTMLInputElement>;\n /**\n * `RadioGroup.Item` / `RadioCard.Root` elements, instead of or after `options`.\n */\n children?: ReactNode;\n };\n\ntype RadioGroupRootProps<T extends RadioValue> = RadioGroupBaseProps<T> & {\n size?: RadioSize;\n cardSize?: RadioCardSize;\n /** Layout of the options. */\n optionsClassName: string;\n optionsStyle?: CSSProperties;\n /** `\"many\"` when the options sit in more than one column. */\n optionsDataColumns?: string;\n};\n\nconst join = (...parts: (string | false | null | undefined)[]) =>\n parts.filter(Boolean).join(\" \") || undefined;\n\n/**\n * Internal. Everything `RadioGroup.Root` and `RadioCard.Group` share: Base UI's\n * `RadioGroup`, which holds the value and moves focus with the arrow keys,\n * and the label, tooltip, helper text and error state around the options.\n */\nexport function RadioGroupRoot<T extends RadioValue>({\n label,\n tooltip,\n helperText,\n error = false,\n value,\n defaultValue,\n onValueChange,\n name,\n disabled = false,\n required = false,\n onBlur,\n id,\n \"aria-label\": ariaLabel,\n \"aria-labelledby\": ariaLabelledBy,\n \"aria-describedby\": ariaDescribedBy,\n className,\n style,\n ref,\n size,\n cardSize,\n optionsClassName,\n optionsStyle,\n optionsDataColumns,\n children,\n}: RadioGroupRootProps<T>) {\n // Ids are wired by hand so the name and description of the group are\n // already in the markup the server sends.\n const labelId = useId();\n const helperTextId = useId();\n const hasLabel = label != null;\n const hasHelperText = helperText != null;\n\n const group = useMemo<RadioGroupContextValue>(\n () => ({ size, cardSize }),\n [size, cardSize],\n );\n\n return (\n <div className={join(styles.Group, className)} style={style}>\n {hasLabel && (\n <FieldGroupLabel\n id={labelId}\n tooltip={tooltip}\n required={required}\n error={error}\n disabled={disabled}\n >\n {label}\n </FieldGroupLabel>\n )}\n <RadioGroupContext.Provider value={group}>\n <BaseRadioGroup\n id={id}\n inputRef={ref}\n name={name}\n value={value}\n defaultValue={defaultValue}\n onValueChange={(next) => onValueChange?.(next as T)}\n disabled={disabled}\n required={required}\n aria-label={ariaLabel}\n aria-labelledby={hasLabel ? labelId : ariaLabelledBy}\n aria-describedby={join(\n hasHelperText && helperTextId,\n ariaDescribedBy,\n )}\n aria-invalid={error ? true : undefined}\n onBlur={(event) => {\n // Moving between two options is not leaving the group.\n if (event.currentTarget.contains(event.relatedTarget)) return;\n onBlur?.(event);\n }}\n className={optionsClassName}\n style={optionsStyle}\n data-columns={optionsDataColumns}\n >\n {children}\n </BaseRadioGroup>\n </RadioGroupContext.Provider>\n {hasHelperText && (\n <FieldHelperText id={helperTextId} error={error}>\n {helperText}\n </FieldHelperText>\n )}\n </div>\n );\n}\n","\"use client\";\n\nimport { Radio as BaseRadio } from \"@base-ui/react/radio\";\nimport type { CSSProperties, ReactNode, Ref } from \"react\";\n\nimport rowStyles from \"./choice-row.module.css\";\nimport {\n radioCircleClassName,\n radioDotClassName,\n type RadioSize,\n} from \"./radio-circle\";\nimport {\n RadioGroupRoot,\n useRadioGroupContext,\n type RadioGroupBaseProps,\n type RadioValue,\n} from \"./radio-group-root\";\nimport styles from \"./radio.module.css\";\n\nexport type { RadioSize as Size, RadioValue as Value };\n\n/**\n * One choice in the `options` list of a `RadioGroup.Root` or `RadioCard.Group`.\n */\nexport type Option<T extends RadioValue = string> = {\n value: T;\n label: ReactNode;\n disabled?: boolean;\n};\n\nexport type ItemProps<T extends RadioValue = RadioValue> = {\n /** What `onValueChange` on the group is called with when this radio is picked. */\n value: T;\n /** The text next to the radio. Without it, pass `aria-label`. */\n label?: ReactNode;\n /** Disables this radio only. */\n disabled?: boolean;\n /** Size of the circle. Defaults to the group's `size`. */\n size?: RadioSize;\n /** Id of the radio itself, the element with the `radio` role. */\n id?: string;\n /** Names the radio when it has no `label`. */\n \"aria-label\"?: string;\n /** Class on the outermost element. */\n className?: string;\n /** Inline style on the outermost element. */\n style?: CSSProperties;\n /**\n * The `<input type=\"radio\">` that holds the value. It is hidden, but\n * `ref.current.focus()` moves focus to the visible radio.\n */\n ref?: Ref<HTMLInputElement>;\n};\n\nconst join = (...parts: (string | false | null | undefined)[]) =>\n parts.filter(Boolean).join(\" \") || undefined;\n\n/**\n * One choice in a `RadioGroup.Root`, for when the `options` list is not enough:\n * a label with markup in it, or content between the choices. The group holds\n * the value, so a `RadioGroup.Item` only works inside one.\n *\n * ```tsx\n * <RadioGroup.Root label=\"Betaling\" value={value} onValueChange={setValue}>\n * <RadioGroup.Item value=\"monthly\" label=\"Månedlig\" />\n * <RadioGroup.Item value=\"yearly\" label={<>Årlig <Chip label=\"Spar 10 %\" /></>} />\n * </RadioGroup.Root>\n * ```\n */\nexport function Item<T extends RadioValue = RadioValue>({\n value,\n label,\n disabled = false,\n size,\n id,\n \"aria-label\": ariaLabel,\n className,\n style,\n ref,\n}: ItemProps<T>) {\n const group = useRadioGroupContext(\"RadioGroup.Item\");\n const bare = label == null;\n\n const circle = (\n <BaseRadio.Root\n // A real `<button>`, so the `<label>` around it names it natively: in\n // the server markup, and as one element for `getByLabelText`.\n nativeButton\n render={<button type=\"button\" />}\n id={id}\n inputRef={ref}\n value={value}\n disabled={disabled}\n aria-label={ariaLabel}\n data-size={size ?? group.size ?? \"md\"}\n className={\n bare ? join(radioCircleClassName, className) : radioCircleClassName\n }\n style={bare ? style : undefined}\n >\n <BaseRadio.Indicator keepMounted className={radioDotClassName} />\n </BaseRadio.Root>\n );\n\n if (bare) return circle;\n\n return (\n <label className={join(rowStyles.Row, className)} style={style}>\n {circle}\n <span className={rowStyles.Text}>{label}</span>\n </label>\n );\n}\n\nexport type RootProps<T extends RadioValue = string> =\n RadioGroupBaseProps<T> & {\n /** The choices, each rendered as a radio with its label. */\n options?: Option<T>[];\n /**\n * Size of the radio circles. A `size` on a `RadioGroup.Item` wins.\n * @default \"md\"\n */\n size?: RadioSize;\n };\n\n/**\n * A question with one answer, as a list of radios, on Base UI's accessible\n * `RadioGroup` primitive. The label, the helper text and the error state are\n * handled for you. Arrow keys move between the choices.\n *\n * Pass the choices as `options`. Values are compared with `===` and can be\n * strings, numbers or booleans, so a yes / no question can hold a real\n * `boolean`. For choices that need more than a label, pass `RadioGroup.Item`\n * children.\n *\n * ```tsx\n * <RadioGroup.Root\n * label=\"Hvor ofte vil du betale?\"\n * options={[\n * { value: \"monthly\", label: \"Månedlig\" },\n * { value: \"yearly\", label: \"Årlig\" },\n * ]}\n * value={value}\n * onValueChange={setValue}\n * />\n * ```\n */\nexport function Root<T extends RadioValue = string>({\n options,\n children,\n ...rest\n}: RootProps<T>) {\n return (\n <RadioGroupRoot {...rest} optionsClassName={styles.Options}>\n {options?.map((option) => (\n <Item\n key={String(option.value)}\n value={option.value}\n label={option.label}\n disabled={option.disabled}\n />\n ))}\n {children}\n </RadioGroupRoot>\n );\n}\n","/*\n * Design tokens come from src/theme/tokens.css, generated from src/theme/tokens\n * by `pnpm tokens:css`. It is a plain stylesheet rather than runtime-injected\n * CSS variables, so this component renders correctly without a provider.\n */\n\n/* The cards of a `RadioCard.Group`, in as many columns as asked for. */\n.Options {\n display: grid;\n /* A list of cards sits tighter than a grid of them. */\n gap: var(--lea-spacing-1);\n grid-template-columns: repeat(var(--radio-card-columns, 1), 1fr);\n}\n\n.Options[data-columns=\"many\"] {\n gap: var(--lea-spacing-1-5);\n}\n\n.Card {\n --radio-card-padding-block: var(--lea-spacing-2);\n\n position: relative;\n display: flex;\n align-items: center;\n justify-content: flex-start;\n padding-block: var(--radio-card-padding-block);\n padding-inline: var(--lea-spacing-2);\n border: 1px solid var(--lea-palette-border-base);\n border-radius: var(--lea-radius-xl);\n background-color: var(--lea-palette-bg-base);\n color: var(--lea-palette-text-base);\n cursor: pointer;\n font-size: var(--lea-text-body-md-font-size);\n font-weight: var(--lea-text-body-md-font-weight);\n gap: var(--lea-spacing-1-5);\n letter-spacing: var(--lea-text-body-md-letter-spacing);\n line-height: var(--lea-text-body-md-line-height);\n text-align: start;\n transition: background-color var(--lea-duration-normal)\n var(--lea-easing-standard),\n border-color var(--lea-duration-normal) var(--lea-easing-standard);\n}\n\n.Card[data-size=\"sm\"] {\n --radio-card-padding-block: var(--lea-spacing-1-5);\n}\n\n.Card[data-orientation=\"vertical\"] {\n --radio-card-padding-block: var(--lea-spacing-4);\n\n flex-direction: column;\n justify-content: center;\n text-align: center;\n}\n\n.Card[data-orientation=\"vertical\"][data-size=\"sm\"] {\n --radio-card-padding-block: var(--lea-spacing-2);\n}\n\n@media (hover: hover) {\n .Card:hover:not(:has(.Radio[data-disabled])) {\n border-color: var(--lea-palette-border-strong);\n }\n}\n\n/*\n * The card reads its state off the radio inside it, which Base UI marks.\n * A chosen card changes border and fill, and its indicator fills in.\n */\n.Card:has(.Radio[data-checked]) {\n border-color: var(--lea-palette-primary-base);\n background-color: var(--lea-palette-bg-accent);\n}\n\n/* Keyboard focus is on the hidden radio, so the ring is drawn on the card. */\n.Card:has(.Radio:focus-visible) {\n outline: 2px solid var(--lea-palette-text-base);\n outline-offset: 0.125rem;\n}\n\n.Card:has(.Radio[data-disabled]) {\n cursor: not-allowed;\n opacity: 0.6;\n}\n\n/*\n * The real control. It is there for the keyboard and for assistive\n * technology, and takes no room: the card around it is what you see and click.\n */\n.Radio {\n position: absolute;\n overflow: hidden;\n width: 1px;\n height: 1px;\n padding: 0;\n border: 0;\n margin: 0;\n clip-path: inset(50%);\n white-space: nowrap;\n}\n\n.Card:has(.Radio[data-checked]) .Indicator {\n border-color: var(--lea-palette-primary-base);\n background-color: var(--lea-palette-primary-base);\n}\n\n.Card:has(.Radio[data-checked]) .Indicator > * {\n scale: 1;\n}\n\n.Icon {\n flex-shrink: 0;\n color: var(--lea-palette-text-base);\n}\n\n.Content {\n display: flex;\n min-width: 0;\n flex: 1;\n flex-direction: column;\n align-items: flex-start;\n /* 2px between the two lines, tighter than any step: they read as one block. */\n gap: calc(var(--lea-spacing) * 0.25);\n text-align: start;\n}\n\n.Card[data-orientation=\"vertical\"] .Content {\n flex: none;\n align-items: center;\n text-align: center;\n}\n\n.Label {\n display: block;\n color: var(--lea-palette-text-base);\n font-size: var(--lea-text-label-lg-font-size);\n font-weight: var(--lea-text-label-lg-font-weight);\n letter-spacing: var(--lea-text-label-lg-letter-spacing);\n line-height: var(--lea-text-label-lg-line-height);\n}\n\n.Description {\n display: block;\n color: var(--lea-palette-text-subtle);\n font-size: var(--lea-text-body-sm-font-size);\n font-weight: var(--lea-text-body-sm-font-weight);\n letter-spacing: var(--lea-text-body-sm-letter-spacing);\n line-height: var(--lea-text-body-sm-line-height);\n}\n\n@media (prefers-reduced-motion: reduce) {\n .Card {\n transition-duration: 0.01ms;\n }\n}\n","\"use client\";\n\nimport { Radio as BaseRadio } from \"@base-ui/react/radio\";\nimport { LucideIcon } from \"lucide-react\";\nimport type { CSSProperties, ReactNode, Ref } from \"react\";\n\nimport styles from \"./radio-card.module.css\";\nimport type { Option } from \"./radio\";\nimport { RadioCircle, type RadioSize } from \"./radio-circle\";\nimport {\n RadioGroupRoot,\n useRadioGroupContext,\n type RadioCardSize,\n type RadioGroupBaseProps,\n type RadioValue,\n} from \"./radio-group-root\";\n\nconst join = (...parts: (string | false | null | undefined)[]) =>\n parts.filter(Boolean).join(\" \") || undefined;\n\nexport type RootProps<T extends RadioValue = RadioValue> = {\n /** What `onValueChange` on the group is called with when this card is picked. */\n value: T;\n /** `\"horizontal\"` (indicator + text in a row) or `\"vertical\"` (icon stacked above text). */\n orientation?: \"horizontal\" | \"vertical\";\n /** Disables this card only. */\n disabled?: boolean;\n /** Padding of the card. Defaults to the group's `size`. */\n size?: RadioCardSize;\n /** Class on the card. */\n className?: string;\n /** Inline style on the card. */\n style?: CSSProperties;\n /** The card, which is a `<label>` around the radio. */\n ref?: Ref<HTMLLabelElement>;\n children?: ReactNode;\n};\n\n/**\n * One choice in a `RadioCard.Group`, for when the `options` list is not\n * enough. The whole card is clickable, and it is built from composable\n * pieces: `RadioCard.Content` (wraps the text), `RadioCard.Indicator`\n * (optional), `RadioCard.Icon`, `RadioCard.Label`, `RadioCard.Description`.\n *\n * Children are laid out as plain flex items, so the indicator is just another\n * child — place it before or after `RadioCard.Content` and it sits at that edge\n * (the content grows to fill the row, pushing the indicator to the side).\n *\n * The group holds the value, so a `RadioCard.Root` only works inside one.\n *\n * ```tsx\n * <RadioCard.Group label=\"Nedbetalingstid\" value={value} onValueChange={setValue}>\n * <RadioCard.Root value={10}>\n * <RadioCard.Content>\n * <RadioCard.Label>1316 kr/mnd</RadioCard.Label>\n * <RadioCard.Description>Over 10 år</RadioCard.Description>\n * </RadioCard.Content>\n * <RadioCard.Indicator />\n * </RadioCard.Root>\n * </RadioCard.Group>\n * ```\n */\nexport function Root<T extends RadioValue = RadioValue>({\n value,\n orientation = \"horizontal\",\n disabled = false,\n size,\n className,\n style,\n ref,\n children,\n}: RootProps<T>) {\n const group = useRadioGroupContext(\"RadioCard.Root\");\n\n return (\n <label\n ref={ref}\n className={join(styles.Card, className)}\n style={style}\n data-orientation={orientation}\n data-size={size ?? group.cardSize ?? \"lg\"}\n >\n <BaseRadio.Root\n // A real `<button>`, so the card, which is its `<label>`, names it\n // natively: in the server markup, and as one element for\n // `getByLabelText`.\n nativeButton\n render={<button type=\"button\" />}\n value={value}\n disabled={disabled}\n className={styles.Radio}\n />\n {children}\n </label>\n );\n}\n\nexport type IndicatorProps = {\n /** Size of the circle. @default \"md\" */\n size?: RadioSize;\n};\n\n/**\n * Optional radio dot for a `RadioCard.Root`. It is a picture of the card's\n * state, drawn like a `RadioGroup.Item`; the card's own radio is what gets\n * picked. Omit it for icon-only cards.\n */\nexport const Indicator = ({ size }: IndicatorProps) => (\n <RadioCircle size={size} className={styles.Indicator} />\n);\n\nexport type IconProps = {\n /** Icon box size (predefined, overridable). */\n size?: number | string;\n icon: LucideIcon;\n};\n\n/**\n * Fixed-size icon slot so every card's icon renders at the same size regardless\n * of the icon passed in.\n */\nexport const Icon = ({ size = 24, icon }: IconProps) => {\n const Glyph = icon;\n return <Glyph size={size} aria-hidden className={styles.Icon} />;\n};\n\n/**\n * Wraps the text lines (`RadioCard.Label` / `RadioCard.Description`) into a\n * column. Grows to fill the row in `horizontal` orientation — so a sibling\n * `RadioCard.Indicator` is pushed to the opposite edge — and centers in\n * `vertical`.\n */\nexport const Content = ({\n children,\n className,\n style,\n}: {\n children: ReactNode;\n className?: string;\n style?: CSSProperties;\n}) => (\n <span className={join(styles.Content, className)} style={style}>\n {children}\n </span>\n);\n\n/** Primary line of a `RadioCard.Root`. */\nexport const Label = ({ children }: { children: ReactNode }) => (\n <span className={styles.Label}>{children}</span>\n);\n\n/** Secondary, muted line of a `RadioCard.Root`. */\nexport const Description = ({ children }: { children: ReactNode }) => (\n <span className={styles.Description}>{children}</span>\n);\n\nexport type GroupProps<T extends RadioValue = string> =\n RadioGroupBaseProps<T> & {\n /**\n * The choices, each rendered as a card with a radio dot and its label.\n * For icons, descriptions or cards without the dot, pass `RadioCard.Root`\n * children instead.\n */\n options?: Option<T>[];\n /** How many cards sit side by side. @default 1 */\n columns?: number;\n /**\n * Padding of the cards. A `size` on a `RadioCard.Root` wins.\n * @default \"lg\"\n */\n size?: RadioCardSize;\n };\n\n/**\n * A question with one answer, as a set of selectable cards, on Base UI's\n * accessible `RadioGroup` primitive. The label, the tooltip, the helper text\n * and the error state are handled for you. Arrow keys move between the cards.\n *\n * Pass the choices as `options`. Values are compared with `===` and can be\n * strings, numbers or booleans, so a yes / no question can hold a real\n * `boolean`:\n *\n * ```tsx\n * <RadioCard.Group\n * label=\"Vil du legge til en medsøker?\"\n * columns={2}\n * size=\"sm\"\n * options={[\n * { value: true, label: \"Ja\" },\n * { value: false, label: \"Nei\" },\n * ]}\n * value={hasCoApplicant}\n * onValueChange={setHasCoApplicant}\n * />\n * ```\n *\n * For richer cards, pass `RadioCard.Root` children.\n */\nexport function Group<T extends RadioValue = string>({\n options,\n columns = 1,\n size,\n children,\n ...rest\n}: GroupProps<T>) {\n return (\n <RadioGroupRoot\n {...rest}\n cardSize={size}\n optionsClassName={styles.Options}\n optionsStyle={{ \"--radio-card-columns\": columns } as CSSProperties}\n optionsDataColumns={columns > 1 ? \"many\" : undefined}\n >\n {options?.map((option) => (\n <Root\n key={String(option.value)}\n value={option.value}\n disabled={option.disabled}\n >\n <Indicator />\n {option.label}\n </Root>\n ))}\n {children}\n </RadioGroupRoot>\n );\n}\n\nexport type { Option, RadioCardSize as Size, RadioValue as Value };\n","\"use client\";\n\nimport { useState } from \"react\";\n\nimport {\n SelectField,\n SelectFieldItem,\n type SelectFieldBaseProps,\n type SelectOption,\n} from \"./select-field\";\n\nexport type { SelectOption };\n\nexport type SelectProps<Value extends string = string> =\n SelectFieldBaseProps & {\n /** The choices. */\n options: readonly SelectOption<Value>[];\n /** The chosen value (controlled). `\"\"` means nothing is chosen. */\n value?: Value | \"\";\n /** The chosen value when first rendered, for uncontrolled use. */\n defaultValue?: Value | \"\";\n /** Called with the value of the option the user picks. */\n onValueChange?: (value: Value) => void;\n };\n\n/**\n * Select on Base UI's `Select`, in the same box as `Input`. The label, the\n * helper text and the ids that link them to the control are all rendered and\n * wired for you.\n *\n * ```tsx\n * <Select\n * label=\"Land\"\n * options={[\n * { value: \"no\", label: \"Norge\" },\n * { value: \"se\", label: \"Sverige\" },\n * ]}\n * value={country}\n * onValueChange={setCountry}\n * />\n * ```\n *\n * Values are strings, and `\"\"` means nothing is chosen. Written with\n * `as const`, the options give `value` and `onValueChange` their type:\n * `\"no\" | \"se\"` here.\n */\nexport function Select<Value extends string = string>({\n options,\n value,\n defaultValue = \"\",\n onValueChange,\n ...rest\n}: SelectProps<Value>) {\n const isControlled = value !== undefined;\n const [internal, setInternal] = useState<Value | \"\">(defaultValue);\n const current = isControlled ? value : internal;\n\n const chosen = options.find((option) => option.value === current);\n\n return (\n <SelectField\n {...rest}\n multiple={false}\n // Base UI's \"nothing chosen\" is `null`; an option may still have `\"\"`\n // as its value, e.g. \"None\", and is then a choice like any other.\n value={chosen ? chosen.value : null}\n onValueChange={(next) => {\n const nextValue = (next ?? \"\") as Value;\n if (!isControlled) setInternal(nextValue);\n onValueChange?.(nextValue);\n }}\n filled={chosen != null}\n display={chosen?.label}\n displayHidden\n valueText={chosen?.label ?? \"\"}\n >\n {options.map((option) => (\n <SelectFieldItem key={option.value} option={option} />\n ))}\n </SelectField>\n );\n}\n","/*\n * Design tokens come from src/theme/tokens.css, generated from src/theme/tokens\n * by `pnpm tokens:css`. It is a plain stylesheet rather than runtime-injected\n * CSS variables, so this component renders correctly without a provider.\n *\n * The track, the min / max row and the helper text are styled in\n * slider-parts.module.css, which `AmountSlider` shares.\n */\n\n.Slider {\n display: flex;\n width: 100%;\n flex-direction: column;\n color: var(--lea-palette-text-base);\n font-size: var(--lea-text-body-md-font-size);\n font-weight: var(--lea-text-body-md-font-weight);\n line-height: var(--lea-text-body-md-line-height);\n letter-spacing: var(--lea-text-body-md-letter-spacing);\n}\n\n.Header {\n display: flex;\n align-items: baseline;\n justify-content: space-between;\n gap: calc(var(--lea-spacing) * 2);\n}\n\n.Label {\n min-width: 0;\n font-weight: var(--lea-font-weight-medium);\n}\n\n.Value {\n margin-inline-start: auto;\n font-weight: var(--lea-font-weight-semibold);\n font-variant-numeric: tabular-nums;\n white-space: nowrap;\n}\n","\"use client\";\n\nimport { Field } from \"@base-ui/react/field\";\nimport { Slider as BaseSlider } from \"@base-ui/react/slider\";\nimport { useId, type ReactNode } from \"react\";\n\nimport { mergeClassName } from \"../../utils/merge-class-name\";\nimport {\n renderWithoutElement,\n SliderHelperText,\n SliderRange,\n SliderTrack,\n} from \"./slider-parts\";\nimport styles from \"./slider.module.css\";\n\n/**\n * Requires an accessible name so the slider is never nameless. Provide a\n * visible `label`, or an `aria-label` when the design has none.\n */\ntype SliderAccessibleName =\n | { label: ReactNode; \"aria-label\"?: never }\n | { label?: never; \"aria-label\": string };\n\nexport type SliderProps = Omit<\n BaseSlider.Root.Props<number>,\n | \"children\"\n | \"orientation\"\n | \"minStepsBetweenValues\"\n | \"thumbAlignment\"\n | \"thumbCollisionBehavior\"\n | \"aria-label\"\n | \"aria-labelledby\"\n> &\n SliderAccessibleName & {\n /** Helper / error text shown below the slider and linked via `aria-describedby`. */\n helperText?: ReactNode;\n /** Puts the slider and its helper text into the error state. */\n error?: boolean;\n };\n\n/**\n * A single-value slider built on Base UI's accessible `Slider` primitive.\n *\n * The label, the current value, the `min` / `max` under each end of the track\n * and the helper text are all rendered and wired internally: the label names\n * the control, the helper text describes it, and `error` marks it invalid and\n * announces the helper text. Base UI renders a native range input, so arrow\n * keys, Page Up / Down, Home and End work, and the value is submitted when\n * `name` is set.\n *\n * Pass `format` and `locale` to control how the value, `min` and `max` are\n * written and announced.\n *\n * ```tsx\n * <Slider\n * label=\"Lånebeløp\"\n * min={50000}\n * max={600000}\n * step={5000}\n * defaultValue={150000}\n * locale=\"nb-NO\"\n * format={{ style: \"currency\", currency: \"NOK\", maximumFractionDigits: 0 }}\n * onValueChange={(value) => setAmount(value)}\n * />\n * ```\n */\nexport function Slider({\n label,\n \"aria-label\": ariaLabel,\n helperText,\n error = false,\n min = 0,\n max = 100,\n format,\n locale,\n className,\n ...rest\n}: SliderProps) {\n // Base UI's `Slider.Label` only links itself after mount, which leaves the\n // server-rendered control nameless, so the label is wired by id here.\n const labelId = useId();\n const helperTextId = useId();\n\n return (\n // The field renders no element of its own, so `className`, `ref` and the\n // rest land on the slider.\n <Field.Root invalid={error} render={renderWithoutElement}>\n <BaseSlider.Root\n {...rest}\n min={min}\n max={max}\n format={format}\n locale={locale}\n aria-labelledby={label != null ? labelId : undefined}\n className={mergeClassName(styles.Slider, className)}\n >\n <div className={styles.Header}>\n {label != null && (\n <div id={labelId} className={styles.Label}>\n {label}\n </div>\n )}\n <BaseSlider.Value className={styles.Value} />\n </div>\n <SliderTrack\n aria-label={ariaLabel}\n aria-describedby={helperText != null ? helperTextId : undefined}\n />\n <SliderRange min={min} max={max} format={format} locale={locale} />\n {helperText != null && (\n <SliderHelperText id={helperTextId} error={error}>\n {helperText}\n </SliderHelperText>\n )}\n </BaseSlider.Root>\n </Field.Root>\n );\n}\n","/*\n * Design tokens come from src/theme/tokens.css, generated from src/theme/tokens\n * by `pnpm tokens:css`. It is a plain stylesheet rather than runtime-injected\n * CSS variables, so this component renders correctly without a provider.\n */\n\n.Switch {\n display: inline-flex;\n width: 2.5rem;\n height: 1.5rem;\n flex-shrink: 0;\n align-items: center;\n padding: 0.125rem;\n border: none;\n border-radius: var(--lea-radius-full);\n background-color: var(--lea-color-neutral-200);\n cursor: pointer;\n transition: background-color var(--lea-duration-normal)\n var(--lea-easing-standard);\n}\n\n.Switch[data-checked] {\n background-color: var(--lea-palette-primary-base);\n}\n\n.Switch:focus-visible {\n outline: 2px solid var(--lea-palette-text-base);\n outline-offset: 0.125rem;\n}\n\n.Switch[data-disabled] {\n cursor: not-allowed;\n opacity: 0.5;\n}\n\n.Thumb {\n display: block;\n width: 1.25rem;\n height: 1.25rem;\n border-radius: var(--lea-radius-full);\n background-color: var(--lea-palette-bg-base);\n transition: translate var(--lea-duration-normal) var(--lea-easing-standard);\n}\n\n.Thumb[data-checked] {\n translate: 1rem 0;\n}\n\n@media (prefers-reduced-motion: reduce) {\n .Switch,\n .Thumb {\n transition-duration: 0.01ms;\n }\n}\n","\"use client\";\n\nimport { Switch as BaseSwitch } from \"@base-ui/react/switch\";\n\nimport { mergeClassName } from \"../../utils/merge-class-name\";\nimport styles from \"./switch.module.css\";\n\n/**\n * Requires an accessible name so the switch is never nameless. Provide exactly\n * one of `aria-label` or `aria-labelledby`.\n */\ntype SwitchAccessibleName =\n | { \"aria-label\": string; \"aria-labelledby\"?: never }\n | { \"aria-labelledby\": string; \"aria-label\"?: never };\n\nexport type SwitchProps = Omit<\n BaseSwitch.Root.Props,\n \"children\" | \"aria-label\" | \"aria-labelledby\"\n> &\n SwitchAccessibleName;\n\n/**\n * An on/off toggle built on Base UI's accessible `Switch` primitive.\n *\n * Base UI renders the `switch` role, keeps `aria-checked` in sync and submits\n * a hidden input when `name` is set. The thumb is rendered internally so it\n * can never be left out, and the slide respects `prefers-reduced-motion`.\n *\n * Unlike a checkbox, a switch takes effect immediately — use it for settings\n * that apply on toggle, not for values confirmed by a submit button.\n *\n * ```tsx\n * <Switch\n * aria-label=\"Analyse-informasjonskapsler\"\n * defaultChecked\n * onCheckedChange={(checked) => save(checked)}\n * />\n * ```\n */\nexport function Switch({ className, ...rest }: SwitchProps) {\n return (\n <BaseSwitch.Root\n {...rest}\n className={mergeClassName(styles.Switch, className)}\n >\n <BaseSwitch.Thumb className={styles.Thumb} />\n </BaseSwitch.Root>\n );\n}\n","/*\n * Responsive props arrive as inline `--_<prop>-<breakpoint>` properties, set\n * only for the breakpoints the consumer gave. Each media query falls back\n * through the smaller breakpoints, so `{ base: 1, md: 3 }` holds 1 until `md`.\n */\n.Grid {\n --_columns: var(--_columns-base, 12);\n --_gap: var(--_gap-base, 0);\n\n display: grid;\n min-width: 0;\n gap: calc(var(--lea-spacing) * var(--_gap));\n grid-template-columns: repeat(var(--_columns), minmax(0, 1fr));\n}\n\n/* A `GridItem` given no `span` takes the whole row; plain children take one column. */\n.GridItem {\n --_span: var(--_span-base, 1 / -1);\n\n min-width: 0;\n grid-column: var(--_span);\n}\n\n@media (min-width: 600px) {\n .Grid {\n --_columns: var(--_columns-sm, var(--_columns-base, 12));\n --_gap: var(--_gap-sm, var(--_gap-base, 0));\n }\n\n .GridItem {\n --_span: var(--_span-sm, var(--_span-base, 1 / -1));\n }\n}\n\n@media (min-width: 900px) {\n .Grid {\n --_columns: var(--_columns-md, var(--_columns-sm, var(--_columns-base, 12)));\n --_gap: var(--_gap-md, var(--_gap-sm, var(--_gap-base, 0)));\n }\n\n .GridItem {\n --_span: var(--_span-md, var(--_span-sm, var(--_span-base, 1 / -1)));\n }\n}\n\n@media (min-width: 1200px) {\n .Grid {\n --_columns: var(\n --_columns-lg,\n var(--_columns-md, var(--_columns-sm, var(--_columns-base, 12)))\n );\n --_gap: var(--_gap-lg, var(--_gap-md, var(--_gap-sm, var(--_gap-base, 0))));\n }\n\n .GridItem {\n --_span: var(\n --_span-lg,\n var(--_span-md, var(--_span-sm, var(--_span-base, 1 / -1)))\n );\n }\n}\n\n@media (min-width: 1536px) {\n .Grid {\n --_columns: var(\n --_columns-xl,\n var(\n --_columns-lg,\n var(--_columns-md, var(--_columns-sm, var(--_columns-base, 12)))\n )\n );\n --_gap: var(\n --_gap-xl,\n var(--_gap-lg, var(--_gap-md, var(--_gap-sm, var(--_gap-base, 0))))\n );\n }\n\n .GridItem {\n --_span: var(\n --_span-xl,\n var(\n --_span-lg,\n var(--_span-md, var(--_span-sm, var(--_span-base, 1 / -1)))\n )\n );\n }\n}\n","import type { CSSProperties } from \"react\";\n\nimport type { Breakpoint } from \"../../theme/tokens/breakpoints\";\n\n/** `base` applies from zero width; each other key from its breakpoint up. */\nexport type ResponsiveKey = \"base\" | Exclude<Breakpoint, \"xs\">;\n\n/**\n * A single value, or one per breakpoint, mobile-first. Unset breakpoints keep\n * the value of the nearest smaller one: `{ base: 1, md: 3 }` is 1 below `md`\n * and 3 from `md` up.\n */\nexport type Responsive<T> = T | Partial<Record<ResponsiveKey, T>>;\n\nconst isPerBreakpoint = <T>(\n value: Responsive<T>,\n): value is Partial<Record<ResponsiveKey, T>> =>\n typeof value === \"object\" && value !== null;\n\n/**\n * Writes a responsive prop as inline custom properties — `--_gap-base`,\n * `--_gap-md`, … — which the component's CSS Module picks up in its media\n * queries. Only the breakpoints that are set are written; the stylesheet\n * falls back through the smaller ones.\n *\n * Internal helper — not part of the public API.\n */\nexport function responsiveVars<T>(\n name: string,\n value: Responsive<T> | undefined,\n format: (value: T) => string | number = String,\n): CSSProperties {\n if (value === undefined) return {};\n\n const entries = isPerBreakpoint(value)\n ? Object.entries(value as Record<string, T | undefined>)\n : [[\"base\", value] as const];\n\n const vars: Record<string, string | number> = {};\n for (const [key, entry] of entries) {\n if (entry !== undefined) vars[`--_${name}-${key}`] = format(entry);\n }\n\n return vars as CSSProperties;\n}\n","\"use client\";\n\nimport { useRender } from \"@base-ui/react/use-render\";\n\nimport type { SpacingFactor } from \"../../theme/token-types\";\nimport { mergeClassName } from \"../../utils/merge-class-name\";\nimport styles from \"./grid.module.css\";\nimport { type Responsive, responsiveVars } from \"./responsive\";\n\nexport type GridProps = Omit<useRender.ComponentProps<\"div\">, \"ref\"> & {\n /**\n * Number of equal-width columns.\n * @default 12\n */\n columns?: Responsive<number>;\n /**\n * Space between rows and columns, as a multiple of the spacing step\n * (`spacing(n)`).\n * @default 0\n */\n gap?: Responsive<SpacingFactor>;\n};\n\n/**\n * A grid of equal-width columns. Children fill one column each; wrap them in\n * `GridItem` to span several. Both props take a value per breakpoint,\n * mobile-first:\n *\n * ```tsx\n * <Grid columns={{ base: 1, sm: 2, lg: 3 }} gap={2}>\n * <Card />\n * <Card />\n * <Card />\n * </Grid>\n * ```\n */\nexport function Grid({\n columns,\n gap,\n render,\n className,\n style,\n ...rest\n}: GridProps) {\n return useRender({\n render,\n props: {\n ...rest,\n className: mergeClassName(styles.Grid, className)({}),\n style: {\n ...responsiveVars(\"columns\", columns),\n ...responsiveVars(\"gap\", gap),\n ...style,\n },\n },\n });\n}\n\nexport type GridItemSpan = number | \"full\";\n\nexport type GridItemProps = Omit<useRender.ComponentProps<\"div\">, \"ref\"> & {\n /**\n * How many of the grid's columns the item covers. `\"full\"` covers the whole\n * row whatever the column count.\n * @default \"full\"\n */\n span?: Responsive<GridItemSpan>;\n};\n\nconst spanValue = (span: GridItemSpan) =>\n span === \"full\" ? \"1 / -1\" : `span ${span} / span ${span}`;\n\n/**\n * An item in a `Grid`. It takes the whole row until `span` says otherwise, so\n * layouts stay single-column on small screens by default:\n *\n * ```tsx\n * <Grid gap={3}>\n * <GridItem span={{ md: 8 }}>Main content</GridItem>\n * <GridItem span={{ md: 4 }}>Sidebar</GridItem>\n * </Grid>\n * ```\n */\nexport function GridItem({\n span,\n render,\n className,\n style,\n ...rest\n}: GridItemProps) {\n return useRender({\n render,\n props: {\n ...rest,\n className: mergeClassName(styles.GridItem, className)({}),\n style: { ...responsiveVars(\"span\", span, spanValue), ...style },\n },\n });\n}\n","/*\n * Responsive props arrive as inline `--_<prop>-<breakpoint>` properties, set\n * only for the breakpoints the consumer gave. Each media query falls back\n * through the smaller breakpoints, so `{ base: 1, md: 3 }` holds 1 until `md`.\n */\n.Stack {\n --_direction: var(--_direction-base, column);\n --_gap: var(--_gap-base, 0);\n\n display: flex;\n min-width: 0;\n flex-direction: var(--_direction);\n gap: calc(var(--lea-spacing) * var(--_gap));\n}\n\n@media (min-width: 600px) {\n .Stack {\n --_direction: var(--_direction-sm, var(--_direction-base, column));\n --_gap: var(--_gap-sm, var(--_gap-base, 0));\n }\n}\n\n@media (min-width: 900px) {\n .Stack {\n --_direction: var(\n --_direction-md,\n var(--_direction-sm, var(--_direction-base, column))\n );\n --_gap: var(--_gap-md, var(--_gap-sm, var(--_gap-base, 0)));\n }\n}\n\n@media (min-width: 1200px) {\n .Stack {\n --_direction: var(\n --_direction-lg,\n var(--_direction-md, var(--_direction-sm, var(--_direction-base, column)))\n );\n --_gap: var(--_gap-lg, var(--_gap-md, var(--_gap-sm, var(--_gap-base, 0))));\n }\n}\n\n@media (min-width: 1536px) {\n .Stack {\n --_direction: var(\n --_direction-xl,\n var(\n --_direction-lg,\n var(\n --_direction-md,\n var(--_direction-sm, var(--_direction-base, column))\n )\n )\n );\n --_gap: var(\n --_gap-xl,\n var(--_gap-lg, var(--_gap-md, var(--_gap-sm, var(--_gap-base, 0))))\n );\n }\n}\n\n.Stack[data-align=\"start\"] {\n align-items: flex-start;\n}\n\n.Stack[data-align=\"center\"] {\n align-items: center;\n}\n\n.Stack[data-align=\"end\"] {\n align-items: flex-end;\n}\n\n.Stack[data-align=\"stretch\"] {\n align-items: stretch;\n}\n\n.Stack[data-align=\"baseline\"] {\n align-items: baseline;\n}\n\n.Stack[data-justify=\"start\"] {\n justify-content: flex-start;\n}\n\n.Stack[data-justify=\"center\"] {\n justify-content: center;\n}\n\n.Stack[data-justify=\"end\"] {\n justify-content: flex-end;\n}\n\n.Stack[data-justify=\"between\"] {\n justify-content: space-between;\n}\n\n.Stack[data-justify=\"around\"] {\n justify-content: space-around;\n}\n\n.Stack[data-justify=\"evenly\"] {\n justify-content: space-evenly;\n}\n\n.Stack[data-wrap] {\n flex-wrap: wrap;\n}\n","\"use client\";\n\nimport { useRender } from \"@base-ui/react/use-render\";\n\nimport type { SpacingFactor } from \"../../theme/token-types\";\nimport { mergeClassName } from \"../../utils/merge-class-name\";\nimport { type Responsive, responsiveVars } from \"./responsive\";\nimport styles from \"./stack.module.css\";\n\nexport type StackDirection = \"column\" | \"row\";\nexport type StackAlign = \"start\" | \"center\" | \"end\" | \"stretch\" | \"baseline\";\nexport type StackJustify =\n | \"start\"\n | \"center\"\n | \"end\"\n | \"between\"\n | \"around\"\n | \"evenly\";\n\nexport type StackProps = Omit<useRender.ComponentProps<\"div\">, \"ref\"> & {\n /**\n * Main axis. There is deliberately no reversed direction: it would make the\n * visual order differ from the reading and focus order.\n * @default \"column\"\n */\n direction?: Responsive<StackDirection>;\n /**\n * Space between children, as a multiple of the spacing step (`spacing(n)`).\n * @default 0\n */\n gap?: Responsive<SpacingFactor>;\n /** Cross-axis alignment (`align-items`). Stretches when unset. */\n align?: StackAlign;\n /** Main-axis distribution (`justify-content`). */\n justify?: StackJustify;\n /**\n * Lets children wrap onto new lines.\n * @default false\n */\n wrap?: boolean;\n};\n\n/**\n * Lays its children out in one direction with even, token-based spacing.\n * `direction` and `gap` take a value per breakpoint, mobile-first:\n *\n * ```tsx\n * <Stack direction={{ base: \"column\", md: \"row\" }} gap={{ base: 2, md: 3 }}>\n * <Card />\n * <Card />\n * </Stack>\n * ```\n *\n * Renders a `div`; pass `render` for another element, e.g.\n * `render={<ul />}` with `<li>` children.\n */\nexport function Stack({\n direction,\n gap,\n align,\n justify,\n wrap = false,\n render,\n className,\n style,\n ...rest\n}: StackProps) {\n return useRender({\n render,\n props: {\n ...rest,\n \"data-align\": align,\n \"data-justify\": justify,\n \"data-wrap\": wrap || undefined,\n className: mergeClassName(styles.Stack, className)({}),\n style: {\n ...responsiveVars(\"direction\", direction),\n ...responsiveVars(\"gap\", gap),\n ...style,\n },\n },\n });\n}\n\nexport type HStackProps = Omit<StackProps, \"direction\">;\n\n/**\n * A `Stack` fixed to `direction=\"row\"`. Children stay on one line unless\n * `wrap` is set.\n *\n * ```tsx\n * <HStack gap={1} justify=\"end\">\n * <Button variant=\"outline\">Avbryt</Button>\n * <Button>Lagre</Button>\n * </HStack>\n * ```\n */\nexport function HStack(props: HStackProps) {\n return <Stack {...props} direction=\"row\" />;\n}\n","/*\n * Design tokens come from src/theme/tokens.css, generated from src/theme/tokens\n * by `pnpm tokens:css`. It is a plain stylesheet rather than runtime-injected\n * CSS variables, so this component renders correctly without a provider.\n */\n\n.Header {\n display: flex;\n width: 100%;\n align-items: center;\n justify-content: space-between;\n gap: var(--lea-spacing-2);\n}\n\n.Lead {\n display: flex;\n align-items: center;\n gap: var(--lea-spacing-2);\n}\n\n.Titles {\n display: flex;\n flex-direction: column;\n}\n\n.Title {\n margin: 0;\n color: var(--lea-palette-text-base);\n /* heading-sm's size at medium weight; the heading styles are semibold. */\n font-size: var(--lea-font-step-2);\n font-weight: var(--lea-font-weight-medium);\n line-height: var(--lea-line-height-normal);\n /* Focus is moved here from code when the step changes, never by Tab. */\n outline: none;\n}\n\n/* `titleAs=\"text\"`: body text at medium weight. */\n.Title[data-title-as=\"text\"] {\n font-size: var(--lea-font-step-0);\n}\n\n.Next {\n margin: 0;\n color: var(--lea-palette-text-subtle);\n font-size: var(--lea-text-body-sm-font-size);\n font-weight: var(--lea-text-body-sm-font-weight);\n line-height: var(--lea-text-body-sm-line-height);\n letter-spacing: var(--lea-text-body-sm-letter-spacing);\n}\n\n.Divider {\n border: 0;\n border-block-end: 1px solid var(--lea-palette-border-base);\n margin-block: var(--lea-spacing-1);\n margin-inline: 0;\n}\n\n.SrOnly {\n position: absolute;\n overflow: hidden;\n width: 1px;\n height: 1px;\n padding: 0;\n border: 0;\n margin: -1px;\n clip-path: inset(50%);\n white-space: nowrap;\n}\n","/*\n * Design tokens come from src/theme/tokens.css, generated from src/theme/tokens\n * by `pnpm tokens:css`. It is a plain stylesheet rather than runtime-injected\n * CSS variables, so this component renders correctly without a provider.\n *\n * The diameter arrives inline from the `size` prop, and so does\n * `--_label-fit`: the largest font size at which the label stays inside the\n * ring.\n */\n\n.ProgressCircle {\n position: relative;\n flex-shrink: 0;\n /* The ring and the value are both drawn in the current colour. */\n color: var(--lea-palette-primary-base);\n}\n\n.ProgressCircle[data-color=\"tertiary\"] {\n color: var(--lea-palette-tertiary-base);\n}\n\n/* Turned so progress starts at 12 o'clock. */\n.Svg {\n display: block;\n transform: rotate(-90deg);\n transform-origin: center;\n}\n\n/* The unfilled part of the ring: the ring colour, faint. No opacity token is\n this strong without being the 60% highlight. */\n.Track {\n stroke-opacity: 0.2;\n}\n\n.Value {\n position: absolute;\n display: flex;\n align-items: center;\n justify-content: center;\n /* label-md's size and weight on a line as tall as the digits, so they\n centre on the ring. Smaller only where that size does not fit. */\n font-size: min(var(--lea-font-step-minus-1), var(--_label-fit));\n font-weight: var(--lea-font-weight-medium);\n line-height: var(--lea-line-height-none);\n inset: 0;\n}\n","\"use client\";\n\nimport {\n animate,\n motion,\n useMotionValue,\n useReducedMotion,\n} from \"motion/react\";\nimport { useEffect, type CSSProperties } from \"react\";\n\nimport type { ColorRoles } from \"../color-roles\";\nimport styles from \"./progress-circle.module.css\";\n\nexport type ProgressCircleColor = ColorRoles<\"primary\" | \"tertiary\">;\n\n/*\n * How much room the `value/max` label takes, in em. The widths are the advance\n * of each digit, 0 to 9, and of the slash in Clash Grotesk at weight 500, and\n * the height is that of a digit; all measured in a browser. Measure again if\n * the font or the weight of the label changes.\n */\nconst DIGIT_WIDTHS = [\n 0.69, 0.33, 0.61, 0.6, 0.63, 0.64, 0.64, 0.54, 0.62, 0.64,\n];\nconst SLASH_WIDTH = 0.43;\nconst DIGIT_HEIGHT = 0.69;\n/** Air between the label and the ring, in px. */\nconst LABEL_GAP = 2;\n\n/**\n * The largest font size, in px, at which `text` stays inside a ring with a\n * hole of `diameter` px: the corners of the text are what reach the ring first.\n */\nconst fitFontSize = (text: string, diameter: number) => {\n const width = Array.from(text).reduce(\n (sum, char) =>\n // Anything but a digit or the slash counts as the widest digit.\n sum + (char === \"/\" ? SLASH_WIDTH : (DIGIT_WIDTHS[Number(char)] ?? 0.69)),\n 0,\n );\n const room = Math.max(diameter - 2 * LABEL_GAP, 0);\n\n return room / Math.hypot(width, DIGIT_HEIGHT);\n};\n\nexport type ProgressCircleProps = {\n /** Current value, e.g. the active step (1-based). Clamped to `0..max`. */\n value: number;\n /** Maximum value, e.g. the total number of steps. */\n max: number;\n /** Ring colour. Defaults to `primary`. */\n color?: ProgressCircleColor;\n /** Rendered diameter in px. Defaults to `48`. */\n size?: number;\n /** Ring thickness in px. Defaults to `4`. */\n strokeWidth?: number;\n /**\n * Show the `value/max` label in the centre. Defaults to `true`. The label\n * is set smaller when it would otherwise touch the ring, in a small circle\n * or with many digits. Below about 32px it is too small to read: leave it\n * out there.\n */\n showValue?: boolean;\n /**\n * Accessible name. When provided, the circle is exposed as a\n * `role=\"progressbar\"` (with `aria-valuetext={label}`) so it announces on its\n * own. When omitted, the circle is decorative (`aria-hidden`) — use this when\n * the surrounding component already conveys progress in text (as `FormStepper`\n * does).\n */\n label?: string;\n};\n\n/**\n * An animated circular progress indicator: the ring is an SVG whose stroke\n * animates as `value` changes, respecting `prefers-reduced-motion`. Colour is\n * limited to `primary` (purple) and `tertiary` (teal) so contrast stays owned\n * by the theme.\n *\n * ```tsx\n * <ProgressCircle value={2} max={5} color=\"tertiary\" label=\"Step 2 of 5\" />\n * ```\n */\nexport const ProgressCircle = ({\n value,\n max,\n color = \"primary\",\n size = 48,\n strokeWidth = 4,\n showValue = true,\n label,\n}: ProgressCircleProps) => {\n const prefersReducedMotion = useReducedMotion();\n\n const radius = (size - strokeWidth) / 2;\n const circumference = 2 * Math.PI * radius;\n const fraction = max > 0 ? Math.min(Math.max(value / max, 0), 1) : 0;\n const dashOffsetFor = (value: number) => circumference * (1 - value);\n\n const offset = useMotionValue(dashOffsetFor(0));\n\n useEffect(() => {\n const target = dashOffsetFor(fraction);\n if (prefersReducedMotion) {\n offset.set(target);\n return;\n }\n\n const controls = animate(offset, target, {\n duration: 0.6,\n ease: \"easeInOut\",\n });\n return () => controls.stop();\n // `circumference` is derived from size/strokeWidth, so it re-runs when those change.\n }, [fraction, circumference, prefersReducedMotion, offset]);\n\n const valueText = `${value}/${max}`;\n const labelFit = fitFontSize(valueText, size - 2 * strokeWidth);\n\n const accessibilityProps = label\n ? ({\n role: \"progressbar\",\n \"aria-label\": label,\n \"aria-valuemin\": 0,\n \"aria-valuemax\": max,\n \"aria-valuenow\": value,\n } as const)\n : ({ \"aria-hidden\": true } as const);\n\n return (\n <div\n {...accessibilityProps}\n className={styles.ProgressCircle}\n data-color={color}\n style={\n {\n width: size,\n height: size,\n \"--_label-fit\": `${labelFit.toFixed(2)}px`,\n } as CSSProperties\n }\n >\n <svg\n className={styles.Svg}\n width={size}\n height={size}\n viewBox={`0 0 ${size} ${size}`}\n >\n <circle\n className={styles.Track}\n cx={size / 2}\n cy={size / 2}\n r={radius}\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth={strokeWidth}\n />\n <motion.circle\n cx={size / 2}\n cy={size / 2}\n r={radius}\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth={strokeWidth}\n strokeLinecap=\"round\"\n strokeDasharray={circumference}\n style={{ strokeDashoffset: offset }}\n />\n </svg>\n {showValue && <span className={styles.Value}>{valueText}</span>}\n </div>\n );\n};\n","import { createTranslation } from \"../../i18n\";\n\n/**\n * Translated labels for `FormStepper`: the back button's accessible name, the\n * \"Next\" subtitle prefix, and the visually-hidden \"step X of Y\" context.\n * Consumers can override any of these per-instance via the `labels` prop.\n */\nexport const useStepperLabels = createTranslation({\n back: { no: \"Tilbake\", se: \"Tillbaka\", fi: \"Takaisin\", es: \"Atrás\" },\n next: { no: \"Neste\", se: \"Nästa\", fi: \"Seuraava\", es: \"Siguiente\" },\n step: { no: \"Trinn\", se: \"Steg\", fi: \"Vaihe\", es: \"Paso\" },\n of: { no: \"av\", se: \"av\", fi: \"/\", es: \"de\" },\n});\n\nexport type StepperLabels = Partial<ReturnType<typeof useStepperLabels>>;\n","\"use client\";\n\nimport { ArrowLeft } from \"lucide-react\";\nimport { useId, type ReactNode } from \"react\";\n\nimport { IconButton } from \"../buttons/icon-button\";\nimport styles from \"./form-stepper.module.css\";\nimport { ProgressCircle, type ProgressCircleColor } from \"./progress-circle\";\nimport { useStepperLabels, type StepperLabels } from \"./use-stepper-labels\";\n\nexport type FormStepperProps = {\n /** Active step (1-based). */\n currentStep: number;\n /** Total number of steps. */\n totalSteps: number;\n /** Title of the current step. Rendered as a heading by default (see `titleAs`). */\n title: ReactNode;\n /**\n * Name of the next step. When set, a translated `\"{Next}: {nextStep}\"`\n * subtitle is shown. Omit it on the last step.\n */\n nextStep?: ReactNode;\n /**\n * Called when the back button is pressed. The back button only renders when\n * this is provided, so omit it on the first step or in forms without a back\n * flow.\n */\n onBack?: () => void;\n /** Progress circle colour. Defaults to `primary`. */\n color?: ProgressCircleColor;\n /**\n * Render the title as a `heading` (default) or plain `text`. Prefer `heading`\n * so screen-reader users can navigate to it; only use `text` when another\n * heading already labels the view.\n */\n titleAs?: \"heading\" | \"text\";\n /** Heading level when `titleAs=\"heading\"`. Defaults to `h1`. */\n headingLevel?: \"h1\" | \"h2\" | \"h3\";\n /**\n * Id applied to the title. Defaults to a generated id. Use it to move focus to\n * the title when the step changes so the new step is announced.\n */\n titleId?: string;\n /** Override the built-in translated labels per-instance. */\n labels?: StepperLabels;\n /** Show the divider below the header. Defaults to `true`. */\n showDivider?: boolean;\n};\n\n/**\n * Header for a multi-step form. Shows the current step title (as a heading by\n * default), an optional `\"Next: ...\"` subtitle, an optional back button, and an\n * animated `ProgressCircle`.\n *\n * Accessibility is wired internally: the step count (`\"step X of Y\"`) is added\n * to the title as visually-hidden text and the circle is decorative, so the\n * count is announced once. The title carries `tabIndex={-1}`; move focus to it\n * (via `titleId`) whenever the step changes so screen-reader users hear the new\n * step.\n *\n * ```tsx\n * <FormStepper\n * currentStep={2}\n * totalSteps={5}\n * title=\"Civil status\"\n * nextStep=\"Employment\"\n * onBack={() => history.back()}\n * />\n * ```\n */\nexport const FormStepper = ({\n currentStep,\n totalSteps,\n title,\n nextStep,\n onBack,\n color = \"primary\",\n titleAs = \"heading\",\n headingLevel = \"h1\",\n titleId,\n labels,\n showDivider = true,\n}: FormStepperProps) => {\n const t = useStepperLabels();\n const l = { ...t, ...labels };\n const generatedId = useId();\n const resolvedTitleId = titleId ?? generatedId;\n\n const Title = titleAs === \"heading\" ? headingLevel : \"p\";\n const stepContext = `, ${l.step} ${currentStep} ${l.of} ${totalSteps}`;\n\n return (\n <>\n <div className={styles.Header}>\n <div className={styles.Lead}>\n {onBack && (\n <IconButton\n aria-label={l.back}\n onClick={onBack}\n variant=\"outline\"\n color=\"secondary\"\n >\n <ArrowLeft aria-hidden />\n </IconButton>\n )}\n <div className={styles.Titles}>\n <Title\n id={resolvedTitleId}\n tabIndex={-1}\n className={styles.Title}\n data-title-as={titleAs}\n >\n {title}\n <span className={styles.SrOnly}>{stepContext}</span>\n </Title>\n {nextStep != null && (\n <p className={styles.Next}>\n {l.next}: {nextStep}\n </p>\n )}\n </div>\n </div>\n <ProgressCircle value={currentStep} max={totalSteps} color={color} />\n </div>\n {showDivider && <hr className={styles.Divider} />}\n </>\n );\n};\n","/*\n * Design tokens come from src/theme/tokens.css, generated from src/theme/tokens\n * by `pnpm tokens:css`. It is a plain stylesheet rather than runtime-injected\n * CSS variables, so this component renders correctly without a provider.\n */\n\n.LinearFormStepper {\n --stepper-bar: var(--lea-palette-primary-base);\n --stepper-track: var(--lea-palette-primary-subtle);\n\n display: flex;\n width: 100%;\n flex-direction: column;\n gap: calc(var(--lea-spacing) * 1.5);\n}\n\n.LinearFormStepper[data-color=\"tertiary\"] {\n --stepper-bar: var(--lea-palette-tertiary-base);\n --stepper-track: var(--lea-palette-tertiary-subtle);\n}\n\n.Progress {\n width: 100%;\n}\n\n.Track {\n position: relative;\n overflow: hidden;\n height: calc(var(--lea-spacing) * 0.75);\n border-radius: var(--lea-radius-full);\n background-color: var(--stepper-track);\n}\n\n.Indicator {\n height: 100%;\n border-radius: var(--lea-radius-full);\n background-color: var(--stepper-bar);\n transition: width var(--lea-duration-emphasis) var(--lea-easing-standard);\n}\n\n.Header {\n display: flex;\n align-items: center;\n gap: calc(var(--lea-spacing) * 2);\n}\n\n.Title {\n margin: 0;\n color: var(--lea-palette-text-base);\n /* heading-md's size at medium weight; the heading styles are semibold. */\n font-size: var(--lea-font-step-4);\n font-weight: var(--lea-font-weight-medium);\n line-height: var(--lea-line-height-snug);\n outline: none;\n}\n\n.TitleText {\n animation: stepper-title-in var(--lea-duration-normal)\n var(--lea-easing-standard);\n}\n\n@keyframes stepper-title-in {\n from {\n opacity: 0;\n }\n}\n\n@media (prefers-reduced-motion: reduce) {\n .Indicator {\n transition: none;\n }\n\n .TitleText {\n animation: none;\n }\n}\n","\"use client\";\n\nimport { Progress } from \"@base-ui/react/progress\";\nimport { ArrowLeft } from \"lucide-react\";\nimport { useId, type ReactNode } from \"react\";\n\nimport { IconButton } from \"../buttons/icon-button\";\nimport styles from \"./linear-form-stepper.module.css\";\nimport type { ProgressCircleColor } from \"./progress-circle\";\nimport { useStepperLabels, type StepperLabels } from \"./use-stepper-labels\";\n\nexport type LinearFormStepperProps = {\n /** Active step (1-based). */\n currentStep: number;\n /**\n * Total number of steps. May change between renders, e.g. when the next step\n * from the API reveals a different path; the bar animates to the new value.\n */\n totalSteps: number;\n /** Title of the current step. Rendered as a heading and names the progress bar. */\n title: ReactNode;\n /**\n * Called when the back button is pressed. The back button only renders when\n * this is provided, so omit it on the first step or in forms without a back\n * flow.\n */\n onBack?: () => void;\n /**\n * Bar colour.\n * @default \"primary\"\n */\n color?: ProgressCircleColor;\n /**\n * Heading level of the title.\n * @default \"h1\"\n */\n headingLevel?: \"h1\" | \"h2\" | \"h3\";\n /**\n * Id applied to the title. Defaults to a generated id. Use it to move focus to\n * the title when the step changes so the new step is announced. Must be\n * unique in the document.\n */\n titleId?: string;\n /** Override the built-in translated labels per-instance. */\n labels?: StepperLabels;\n};\n\n/**\n * Header for a multi-step form whose steps aren't all known up front: a linear\n * progress bar above the current step's title, with an optional back button.\n * Use `FormStepper` instead when the full step list is known.\n *\n * The bar is a `progressbar` named by the title heading, with the step count\n * (`\"step X of Y\"`) as its value text. The title carries `tabIndex={-1}`; move\n * focus to it (via `titleId`) whenever the step changes so screen-reader users\n * hear the new step.\n *\n * ```tsx\n * <LinearFormStepper\n * currentStep={2}\n * totalSteps={5}\n * title=\"Refinancing\"\n * onBack={() => history.back()}\n * />\n * ```\n */\nexport const LinearFormStepper = ({\n currentStep,\n totalSteps,\n title,\n onBack,\n color = \"primary\",\n headingLevel: Heading = \"h1\",\n titleId,\n labels,\n}: LinearFormStepperProps) => {\n const t = useStepperLabels();\n const l = { ...t, ...labels };\n const generatedId = useId();\n const resolvedTitleId = titleId ?? generatedId;\n\n return (\n <div className={styles.LinearFormStepper} data-color={color}>\n <Progress.Root\n className={styles.Progress}\n value={currentStep}\n max={totalSteps}\n aria-labelledby={resolvedTitleId}\n getAriaValueText={() =>\n `${l.step} ${currentStep} ${l.of} ${totalSteps}`\n }\n >\n <Progress.Track className={styles.Track}>\n <Progress.Indicator className={styles.Indicator} />\n </Progress.Track>\n </Progress.Root>\n <div className={styles.Header}>\n {onBack && (\n <IconButton\n aria-label={l.back}\n onClick={onBack}\n variant=\"outline\"\n color=\"secondary\"\n >\n <ArrowLeft aria-hidden />\n </IconButton>\n )}\n <Heading id={resolvedTitleId} tabIndex={-1} className={styles.Title}>\n <span key={currentStep} className={styles.TitleText}>\n {title}\n </span>\n </Heading>\n </div>\n </div>\n );\n};\n","\"use client\";\n\nimport {\n createContext,\n useContext,\n useEffect,\n useState,\n type Dispatch,\n type ReactNode,\n type SetStateAction,\n} from \"react\";\n\nimport {\n LinearFormStepper,\n type LinearFormStepperProps,\n} from \"./linear-form-stepper\";\n\n/**\n * The step a flow is on, already resolved by the app. The library never\n * defines steps: the app maps its own step (e.g. from the API) to a position\n * and a translated title, then reports it.\n */\nexport type StepProgress = {\n /** Active step (1-based). */\n currentStep: number;\n /** Total number of steps. May change as the flow reveals its path. */\n totalSteps: number;\n /** Translated title of the current step. */\n title: string;\n};\n\nconst StepProgressStateContext = createContext<StepProgress | null>(null);\nconst ReportStepProgressContext = createContext<Dispatch<\n SetStateAction<StepProgress | null>\n> | null>(null);\n\nexport type StepProgressProviderProps = {\n children: ReactNode;\n /**\n * Progress to show on the first render, before any page has reported, e.g.\n * so a server-rendered layout paints the bar straight away.\n */\n initialProgress?: StepProgress;\n};\n\n/**\n * Holds the step a persistent flow header shows. Put it in the flow layout,\n * above the route's loading boundary, so the header survives step navigations\n * instead of remounting with the page, and its bar animates between steps.\n *\n * ```tsx\n * <StepProgressProvider>\n * <StepProgressHeader onBack={router.back} />\n * {children}\n * </StepProgressProvider>\n * ```\n */\nexport const StepProgressProvider = ({\n children,\n initialProgress,\n}: StepProgressProviderProps) => {\n const [progress, setProgress] = useState<StepProgress | null>(\n initialProgress ?? null,\n );\n\n return (\n <ReportStepProgressContext.Provider value={setProgress}>\n <StepProgressStateContext.Provider value={progress}>\n {children}\n </StepProgressStateContext.Provider>\n </ReportStepProgressContext.Provider>\n );\n};\n\n/**\n * The last reported step, or `null` before anything has been reported or\n * outside a `StepProgressProvider`. Use it to render `FormStepper` or a custom\n * header from the same state.\n */\nexport const useStepProgress = () => useContext(StepProgressStateContext);\n\n/**\n * Publishes the current step to the nearest `StepProgressProvider`. Pass\n * `null` while the step isn't resolved yet; nothing is reported then. Never\n * clears on unmount, so the header holds its value while the next route's\n * loading fallback is on screen.\n *\n * ```tsx\n * useReportStepProgress({ currentStep: 2, totalSteps: 5, title: t(\"income\") });\n * ```\n */\nexport const useReportStepProgress = (progress: StepProgress | null) => {\n const report = useContext(ReportStepProgressContext);\n const currentStep = progress?.currentStep;\n const totalSteps = progress?.totalSteps;\n const title = progress?.title;\n\n useEffect(() => {\n if (\n !report ||\n currentStep === undefined ||\n totalSteps === undefined ||\n title === undefined\n ) {\n return;\n }\n report({ currentStep, totalSteps, title });\n }, [report, currentStep, totalSteps, title]);\n};\n\nexport type StepProgressHeaderProps = Omit<\n LinearFormStepperProps,\n \"currentStep\" | \"totalSteps\" | \"title\"\n>;\n\n/**\n * A `LinearFormStepper` driven by the nearest `StepProgressProvider`. Renders\n * nothing until a step has been reported. Everything except the step itself\n * (`onBack`, `color`, `headingLevel`, …) is passed as props.\n */\nexport const StepProgressHeader = (props: StepProgressHeaderProps) => {\n const progress = useStepProgress();\n if (!progress) {\n return null;\n }\n\n return <LinearFormStepper {...props} {...progress} />;\n};\n","/*\n * Design tokens come from src/theme/tokens.css, generated from src/theme/tokens\n * by `pnpm tokens:css`. It is a plain stylesheet rather than runtime-injected\n * CSS variables, so this component renders correctly without a provider.\n */\n\n.Tabs {\n --tabs-pill: var(--lea-palette-primary-base);\n\n /*\n * One column that may be narrower than the tabs in it. Without it the row of\n * tabs is the least width the control can have, and where the layout sizes\n * things by their content (a flex row, a centred column) it pushes the page\n * wider than the screen instead of scrolling inside its track.\n */\n display: grid;\n grid-template-columns: minmax(0, 1fr);\n}\n\n.Tabs[data-color=\"secondary\"] {\n --tabs-pill: var(--lea-palette-secondary-base);\n}\n\n/*\n * The track: a beige pill that holds the tabs. It scrolls sideways when they\n * do not fit, with the scrollbar hidden so the row stays a clean pill.\n */\n.List {\n position: relative;\n display: flex;\n overflow: auto hidden;\n max-width: 100%;\n box-sizing: border-box;\n flex-flow: row nowrap;\n align-items: center;\n padding: var(--lea-spacing-0-5);\n border-radius: var(--lea-radius-full);\n background-color: var(--lea-palette-bg-muted);\n gap: var(--lea-spacing-0-5);\n scrollbar-width: none;\n}\n\n.List::-webkit-scrollbar {\n display: none;\n}\n\n/* Above the pill, so the label of the active tab shows on top of it. */\n.Tab {\n position: relative;\n z-index: 1;\n display: inline-flex;\n flex-shrink: 0;\n align-items: center;\n justify-content: center;\n /* 10px: with one line of text it makes a tab 36px tall, 44px with the track. */\n padding-block: calc(var(--lea-spacing) * 1.25);\n padding-inline: var(--lea-spacing-2);\n border: 0;\n border-radius: var(--lea-radius-full);\n margin: 0;\n background: none;\n /*\n * neutral-600 rather than text-subtle, so the inactive label clears 4.5:1\n * against the beige track.\n */\n color: var(--lea-color-neutral-600);\n cursor: pointer;\n font-family: inherit;\n /* label-lg on a line as tall as the text: the padding sets the height. */\n font-size: var(--lea-font-step-0);\n font-weight: var(--lea-font-weight-medium);\n gap: var(--lea-spacing-1);\n line-height: var(--lea-line-height-none);\n transition: color var(--lea-duration-normal) var(--lea-easing-standard);\n user-select: none;\n white-space: nowrap;\n}\n\n.Tab svg {\n display: block;\n flex-shrink: 0;\n}\n\n.Tab[data-active] {\n color: var(--lea-palette-text-contrast);\n}\n\n.Tab[data-disabled] {\n cursor: not-allowed;\n opacity: 0.45;\n pointer-events: none;\n}\n\n.Tab:focus-visible,\n.Panel:focus-visible {\n outline: 2px solid var(--lea-palette-text-base);\n outline-offset: 0.125rem;\n}\n\n/*\n * The pill behind the active tab. Base UI writes the place and size of the\n * active tab to the `--active-tab-*` properties on this element.\n */\n.Indicator {\n position: absolute;\n z-index: 0;\n top: var(--active-tab-top);\n left: var(--active-tab-left);\n width: var(--active-tab-width);\n height: var(--active-tab-height);\n border-radius: var(--lea-radius-full);\n background-color: var(--tabs-pill);\n transition: top var(--lea-duration-normal) var(--lea-easing-standard),\n left var(--lea-duration-normal) var(--lea-easing-standard),\n width var(--lea-duration-normal) var(--lea-easing-standard),\n height var(--lea-duration-normal) var(--lea-easing-standard);\n}\n\n/* The panel takes focus, so keyboard users can reach content without controls. */\n.Panel {\n padding-block-start: var(--lea-spacing-2);\n}\n\n@media (prefers-reduced-motion: reduce) {\n .Tab,\n .Indicator {\n transition-duration: 0.01ms;\n }\n}\n","\"use client\";\n\nimport { Tabs as BaseTabs } from \"@base-ui/react/tabs\";\n\nimport { mergeClassName } from \"../../utils/merge-class-name\";\nimport type { ColorRoles } from \"../color-roles\";\nimport styles from \"./tabs.module.css\";\n\n/** The colours of the active \"pill\". */\nexport type Color = ColorRoles<\"primary\" | \"secondary\">;\n\nexport type RootProps = Omit<BaseTabs.Root.Props, \"color\"> & {\n /**\n * Colour of the active-tab \"pill\".\n * - `\"primary\"` — filled with the brand purple (default).\n * - `\"secondary\"` — filled with near-black, for a neutral surface.\n * @default \"primary\"\n */\n color?: Color;\n};\n\n/**\n * A segmented, pill-style tabs control built on Base UI's accessible `Tabs`\n * primitive. Renders a beige track with a sliding pill behind the active tab.\n *\n * Compose it from `Tabs.Root`, `Tabs.List` + `Tabs.Tab` (the tab bar) and,\n * optionally, `Tabs.Panel` for built-in content. Roles\n * (`tablist`/`tab`/`tabpanel`), roving `tabindex`, arrow-key navigation,\n * `aria-selected` and the `tab`↔`tabpanel` links are all wired by Base UI, so\n * relationships never dangle.\n *\n * The list scrolls horizontally when the tabs overflow (e.g. on mobile) and the\n * pill slide respects `prefers-reduced-motion`.\n *\n * ```tsx\n * <Tabs.Root defaultValue=\"overview\">\n * <Tabs.List aria-label=\"Account sections\">\n * <Tabs.Tab value=\"overview\">Overview</Tabs.Tab>\n * <Tabs.Tab value=\"activity\">Activity</Tabs.Tab>\n * </Tabs.List>\n * <Tabs.Panel value=\"overview\">Workspace stats and activity.</Tabs.Panel>\n * <Tabs.Panel value=\"activity\">Recent activity.</Tabs.Panel>\n * </Tabs.Root>\n * ```\n */\nexport function Root({ color = \"primary\", className, ...rest }: RootProps) {\n return (\n <BaseTabs.Root\n {...rest}\n data-color={color}\n className={mergeClassName(styles.Tabs, className)}\n />\n );\n}\n\n/**\n * Requires an accessible name so the underlying `tablist` is never nameless.\n * Provide exactly one of `aria-label` or `aria-labelledby`.\n */\ntype TabsListAccessibleName =\n | { \"aria-label\": string; \"aria-labelledby\"?: never }\n | { \"aria-labelledby\": string; \"aria-label\"?: never };\n\nexport type ListProps = Omit<\n BaseTabs.List.Props,\n \"render\" | \"aria-label\" | \"aria-labelledby\"\n> &\n TabsListAccessibleName;\n\n/**\n * Groups the `Tabs.Tab` buttons into the pill track. The sliding indicator is\n * rendered internally so it can never go missing.\n */\nexport function List({ children, className, ...rest }: ListProps) {\n return (\n <BaseTabs.List {...rest} className={mergeClassName(styles.List, className)}>\n {children}\n <Indicator />\n </BaseTabs.List>\n );\n}\n\nexport type TabProps = Omit<BaseTabs.Tab.Props, \"render\">;\n\n/**\n * An individual tab. Pass an icon and label as children; mark decorative icons\n * with `aria-hidden` so they aren't announced.\n *\n * ```tsx\n * <Tabs.Tab value=\"transactions\">\n * <Receipt size={18} aria-hidden />\n * Transaksjoner\n * </Tabs.Tab>\n * ```\n */\nexport function Tab({ className, ...rest }: TabProps) {\n return (\n <BaseTabs.Tab {...rest} className={mergeClassName(styles.Tab, className)} />\n );\n}\n\nexport type IndicatorProps = Omit<BaseTabs.Indicator.Props, \"render\">;\n\n/**\n * The sliding pill behind the active tab. `Tabs.List` already renders one, so\n * you only need this when composing a custom list.\n */\nexport function Indicator({ className, ...rest }: IndicatorProps) {\n return (\n <BaseTabs.Indicator\n {...rest}\n className={mergeClassName(styles.Indicator, className)}\n />\n );\n}\n\nexport type PanelProps = Omit<BaseTabs.Panel.Props, \"render\">;\n\n/**\n * Content shown when the `Tabs.Tab` with the matching `value` is active.\n * Optional — omit it to use `Tabs` purely as a bar that toggles content you\n * render elsewhere (drive it with `value`/`onValueChange`).\n */\nexport function Panel({ className, ...rest }: PanelProps) {\n return (\n <BaseTabs.Panel\n {...rest}\n className={mergeClassName(styles.Panel, className)}\n />\n );\n}\n","/*\n * Design tokens come from src/theme/tokens.css, generated from src/theme/tokens\n * by `pnpm tokens:css`. It is a plain stylesheet rather than runtime-injected\n * CSS variables, so this component renders correctly without a provider.\n * `--lea-spacing` is the 0.5rem base unit, multiplied to match `spacing(n)`.\n */\n\n/*\n * Each variant overrides the local properties below; the defaults are\n * `outline`. `.Item` and `.Header` only read them, so hover and active states\n * are one rule each rather than one per variant.\n */\n.Root {\n --accordion-gap: var(--lea-spacing);\n --accordion-item-bg: transparent;\n --accordion-item-border: var(--lea-palette-border-subtle);\n --accordion-item-radius: var(--lea-radius-2xl);\n --accordion-header-radius: var(--lea-radius-2xl);\n --accordion-hover-border: var(--lea-palette-border-strong);\n --accordion-hover-bg: transparent;\n --accordion-active-bg: var(--lea-color-purple-50);\n\n display: flex;\n width: 100%;\n flex-direction: column;\n gap: var(--accordion-gap);\n}\n\n.Root[data-variant=\"solid\"] {\n --accordion-item-bg: var(--lea-palette-bg-subtle);\n --accordion-item-border: transparent;\n --accordion-hover-border: transparent;\n --accordion-hover-bg: var(--lea-color-neutral-100);\n --accordion-active-bg: var(--lea-color-neutral-200);\n}\n\n/* No surface of their own, so hover and pressed lighten whatever the accordion\n sits on with translucent white; the hint of text colour keeps them visible\n on white. */\n.Root[data-variant=\"divided\"],\n.Root[data-variant=\"ghost\"] {\n --accordion-highlight: color-mix(\n in srgb,\n var(--lea-color-white) calc(var(--lea-opacity-highlight) * 100%),\n transparent\n );\n --accordion-item-border: transparent;\n --accordion-header-radius: var(--lea-radius-sm);\n --accordion-hover-border: transparent;\n --accordion-hover-bg: color-mix(\n in srgb,\n var(--lea-palette-text-base) calc(var(--lea-opacity-hover) * 100%),\n var(--accordion-highlight)\n );\n --accordion-active-bg: color-mix(\n in srgb,\n var(--lea-palette-text-base) calc(var(--lea-opacity-pressed) * 100%),\n var(--accordion-highlight)\n );\n}\n\n.Root[data-variant=\"divided\"] {\n --accordion-gap: 0;\n --accordion-item-radius: 0;\n}\n\n.Item {\n border: 1px solid var(--accordion-item-border);\n border-radius: var(--accordion-item-radius);\n background-color: var(--accordion-item-bg);\n}\n\n.Root[data-variant=\"divided\"] > .Item:not(:last-child) {\n border-block-end-color: var(--lea-palette-border-subtle);\n}\n\n/*\n * The row lives on the header rather than the trigger so a control rendered\n * beside the trigger (a Switch, say) sits inside the same hover outline.\n */\n.Header {\n display: flex;\n align-items: center;\n gap: calc(var(--lea-spacing) * 2);\n padding: calc(var(--lea-spacing) * 1.7) calc(var(--lea-spacing) * 2);\n border: 1px solid transparent;\n border-radius: var(--accordion-header-radius);\n margin: 0;\n transition: border-color var(--lea-duration-emphasis)\n var(--lea-easing-standard),\n background-color var(--lea-duration-emphasis) var(--lea-easing-standard);\n}\n\n@media (hover: hover) {\n .Header:has(.Trigger:hover:not([data-disabled])) {\n border-color: var(--accordion-hover-border);\n background-color: var(--accordion-hover-bg);\n }\n}\n\n.Header:has(.Trigger:active:not([data-disabled])) {\n background-color: var(--accordion-active-bg);\n}\n\n.Trigger {\n display: flex;\n min-width: 0;\n flex: 1;\n align-items: center;\n justify-content: space-between;\n gap: var(--lea-spacing);\n padding: 0;\n border: none;\n margin: 0;\n background-color: transparent;\n color: var(--lea-palette-text-base);\n cursor: pointer;\n font-family: inherit;\n /* label-lg with room to wrap: the label styles have a tight line height. */\n font-size: var(--lea-font-step-0);\n font-weight: var(--lea-font-weight-medium);\n line-height: var(--lea-line-height-normal);\n text-align: left;\n}\n\n.Trigger:focus-visible {\n outline: 2px solid var(--lea-palette-text-base);\n outline-offset: 0.125rem;\n}\n\n.Trigger[data-disabled] {\n color: var(--lea-palette-text-muted);\n cursor: not-allowed;\n}\n\n.Label {\n min-width: 0;\n}\n\n.Icon {\n flex-shrink: 0;\n transition: transform var(--lea-duration-emphasis) var(--lea-easing-standard);\n}\n\n.Trigger[data-panel-open] .Icon {\n transform: rotate(180deg);\n}\n\n/* Arrow before the title, so it stays next to the text it belongs to. */\n.Root[data-icon-position=\"start\"] .Trigger {\n justify-content: flex-start;\n}\n\n.Root[data-icon-position=\"start\"] .Icon {\n order: -1;\n}\n\n.Panel {\n height: var(--accordion-panel-height);\n overflow: hidden;\n transition: height var(--lea-duration-emphasis) var(--lea-easing-standard);\n}\n\n.Panel[data-starting-style],\n.Panel[data-ending-style] {\n height: 0;\n}\n\n.Content {\n padding-inline: calc(var(--lea-spacing) * 2);\n padding-block: var(--lea-spacing);\n color: var(--lea-palette-text-base);\n font-size: var(--lea-text-body-md-font-size);\n font-weight: var(--lea-text-body-md-font-weight);\n line-height: var(--lea-text-body-md-line-height);\n letter-spacing: var(--lea-text-body-md-letter-spacing);\n}\n\n@media (prefers-reduced-motion: reduce) {\n .Header,\n .Icon,\n .Panel {\n transition-duration: 0.01ms;\n }\n}\n","\"use client\";\n\nimport { Accordion as BaseAccordion } from \"@base-ui/react/accordion\";\nimport { ChevronDown } from \"lucide-react\";\n\nimport { mergeClassName } from \"../../utils/merge-class-name\";\nimport styles from \"./accordion.module.css\";\n\nexport type Variant = \"outline\" | \"solid\" | \"divided\" | \"ghost\";\n\nexport type IconPosition = \"start\" | \"end\";\n\nexport type RootProps = BaseAccordion.Root.Props & {\n /**\n * Surface treatment of each item.\n * - `\"outline\"` — transparent cards with a light `border.subtle` border\n * (default). Hovering outlines the header.\n * - `\"solid\"` — borderless cards filled light grey (`bg.subtle`). Hovering\n * darkens the header instead of outlining it.\n * - `\"divided\"` — a flush list with no cards, items separated by thin lines.\n * Suits long FAQ lists.\n * - `\"ghost\"` — no border or fill; only the hover tint shows. Use it on\n * tinted backgrounds.\n * @default \"outline\"\n */\n variant?: Variant;\n /**\n * Which side of the title the expand arrow sits on. Use `\"start\"` when the\n * header also holds a control (such as a `Switch`), so the arrow stays next\n * to the title it belongs to.\n * @default \"end\"\n */\n iconPosition?: IconPosition;\n};\n\n/**\n * A set of collapsible panels built on Base UI's accessible `Accordion`\n * primitive, styled with Lea's design tokens.\n *\n * Heading semantics, `aria-expanded`, `aria-controls` and the unique ids\n * linking each trigger to its panel are generated by Base UI, so the\n * relationships can never dangle and consumers never supply ids by hand.\n * Only one panel opens at a time unless you pass `multiple`.\n *\n * ```tsx\n * <Accordion.Root defaultValue={[\"shipping\"]}>\n * <Accordion.Item value=\"shipping\">\n * <Accordion.Header>\n * <Accordion.Trigger>How long does shipping take?</Accordion.Trigger>\n * </Accordion.Header>\n * <Accordion.Panel>Three to five business days.</Accordion.Panel>\n * </Accordion.Item>\n * </Accordion.Root>\n * ```\n *\n * For the common title-and-content case, reach for `SimpleAccordion` instead.\n */\nexport function Root({\n variant = \"outline\",\n iconPosition = \"end\",\n className,\n ...rest\n}: RootProps) {\n return (\n <BaseAccordion.Root\n {...rest}\n data-variant={variant}\n data-icon-position={iconPosition}\n className={mergeClassName(styles.Root, className)}\n />\n );\n}\n\nexport type ItemProps = BaseAccordion.Item.Props;\n\n/**\n * One panel of the accordion, pairing a `Header` with a `Panel`. Give it a\n * `value` to open it initially or to control it programmatically.\n */\nexport function Item({ className, ...rest }: ItemProps) {\n return (\n <BaseAccordion.Item\n {...rest}\n className={mergeClassName(styles.Item, className)}\n />\n );\n}\n\nexport type HeaderProps = BaseAccordion.Header.Props;\n\n/**\n * The heading that labels the panel. Renders an `<h3>` and must wrap a\n * `Trigger` so the accordion stays navigable by heading.\n *\n * Anything rendered after the `Trigger` sits on the same row, which is where a\n * per-item control belongs. It must go beside the trigger rather than inside\n * it, because the trigger is a `<button>` and nesting controls is invalid.\n *\n * ```tsx\n * <Accordion.Header>\n * <Accordion.Trigger>Analyse</Accordion.Trigger>\n * <Switch aria-label=\"Analyse-informasjonskapsler\" />\n * </Accordion.Header>\n * ```\n */\nexport function Header({ className, ...rest }: HeaderProps) {\n return (\n <BaseAccordion.Header\n {...rest}\n className={mergeClassName(styles.Header, className)}\n />\n );\n}\n\nexport type TriggerProps = BaseAccordion.Trigger.Props;\n\n/**\n * The button that opens and closes its panel. Pass the question or label as\n * children; the chevron is rendered internally and hidden from assistive\n * technology.\n */\nexport function Trigger({ children, className, ...rest }: TriggerProps) {\n return (\n <BaseAccordion.Trigger\n {...rest}\n className={mergeClassName(styles.Trigger, className)}\n >\n <span className={styles.Label}>{children}</span>\n <ChevronDown className={styles.Icon} size={20} aria-hidden />\n </BaseAccordion.Trigger>\n );\n}\n\nexport type PanelProps = BaseAccordion.Panel.Props;\n\n/**\n * The collapsible content of an item. Padding sits on an inner element so the\n * open/close height animation stays smooth.\n */\nexport function Panel({ children, className, ...rest }: PanelProps) {\n return (\n <BaseAccordion.Panel\n {...rest}\n className={mergeClassName(styles.Panel, className)}\n >\n <div className={styles.Content}>{children}</div>\n </BaseAccordion.Panel>\n );\n}\n","\"use client\";\n\nimport type { ReactNode } from \"react\";\n\nimport * as Accordion from \"./accordion\";\n\nexport type SimpleAccordionItem = {\n /** The heading shown on the row. */\n title: ReactNode;\n /** The collapsible body revealed when the row is opened. */\n content: ReactNode;\n /**\n * A control rendered on the row beside the title, typically a `Switch`.\n * It sits outside the trigger, so operating it doesn't open the panel.\n */\n action?: ReactNode;\n /**\n * Identifies the item for `defaultValue` / `value`. Defaults to the item's\n * position, so only set it when you open or control items programmatically.\n * Only meaningful inside `items`.\n */\n value?: string;\n /** Whether this item can be opened. Only meaningful inside `items`. */\n disabled?: boolean;\n};\n\n/**\n * The single-item form. `value` and `disabled` are left to `Accordion.Root`\n * (they'd otherwise collide with the root's own props of the same name); the\n * lone item always has the value `\"0\"`, so `defaultValue={[\"0\"]}` opens it.\n */\ntype SingleItemProps = Omit<SimpleAccordionItem, \"value\" | \"disabled\"> & {\n items?: never;\n};\n\ntype MultipleItemsProps = {\n items: SimpleAccordionItem[];\n title?: never;\n content?: never;\n action?: never;\n};\n\n// The root props inherit every global HTML attribute, two of which (`title`\n// and the RDFa `content`) share a name with ours and would narrow our\n// `ReactNode` values to `string`. Drop them so our own types win.\nexport type SimpleAccordionProps = Omit<\n Accordion.RootProps,\n \"children\" | \"title\" | \"content\"\n> &\n (SingleItemProps | MultipleItemsProps);\n\n/**\n * The props-driven form of `Accordion` for the common case: a title and some\n * content, with an optional control on the row.\n *\n * Pass `title` and `content` for a single collapsible panel, or `items` for\n * several. Everything `Accordion.Root` accepts — `variant`, `iconPosition`,\n * `multiple`, `defaultValue` — is forwarded. Compose `Accordion.Root` by hand\n * when you need markup the `title` / `content` pair can't express.\n *\n * ```tsx\n * <SimpleAccordion\n * iconPosition=\"start\"\n * title=\"Nødvendige\"\n * content={<Text>Alltid påskrudd.</Text>}\n * action={<Switch aria-label=\"Nødvendige\" checked disabled />}\n * />\n *\n * <SimpleAccordion\n * multiple\n * items={[\n * { title: \"Levering\", content: \"Tre til fem virkedager.\" },\n * { title: \"Retur\", content: \"30 dagers angrerett.\" },\n * ]}\n * />\n * ```\n */\nexport function SimpleAccordion({\n items,\n title,\n content,\n action,\n ...rest\n}: SimpleAccordionProps) {\n const entries: SimpleAccordionItem[] = items ?? [\n { title, content, action } as SimpleAccordionItem,\n ];\n\n return (\n <Accordion.Root {...rest}>\n {entries.map((item, index) => {\n const itemValue = item.value ?? String(index);\n return (\n <Accordion.Item\n key={itemValue}\n value={itemValue}\n disabled={item.disabled}\n >\n <Accordion.Header>\n <Accordion.Trigger>{item.title}</Accordion.Trigger>\n {item.action}\n </Accordion.Header>\n <Accordion.Panel>{item.content}</Accordion.Panel>\n </Accordion.Item>\n );\n })}\n </Accordion.Root>\n );\n}\n","/*\n * The four brand colours. Blue and orange have no semantic token of their\n * own, so they are steps of their scales: a brand stripe is not a status, and\n * must not follow `status.info` or `status.warning` when those change.\n */\n.BrandDivider {\n display: flex;\n width: 100%;\n height: var(--lea-spacing);\n flex-shrink: 0;\n background: linear-gradient(to right,\n var(--lea-color-blue-400) 25%,\n var(--lea-palette-tertiary-base) 25%,\n var(--lea-palette-tertiary-base) 50%,\n var(--lea-color-orange-400) 50%,\n var(--lea-color-orange-400) 75%,\n var(--lea-palette-primary-base) 75%\n );\n}\n\n.BrandDivider[data-size=\"sm\"] {\n height: calc(var(--lea-spacing) * 0.5);\n}\n\n.BrandDivider[data-size=\"md\"] {\n height: calc(var(--lea-spacing) * 1);\n}\n\n.BrandDivider[data-size=\"lg\"] {\n height: calc(var(--lea-spacing) * 1.5);\n}\n\n","import styles from \"./brand-divider.module.css\";\n\n/**\n *\n * Brand Divider in Lea colors\n *\n */\n\nexport type BrandDividerProps = {\n /**\n * The size of the divider.\n */\n size?: \"sm\" | \"md\" | \"lg\";\n};\n\nexport const BrandDivider = ({ size = \"sm\" }: BrandDividerProps) => {\n return (\n <div aria-hidden=\"true\" className={styles.BrandDivider} data-size={size} />\n );\n};\n",".AppHeader {\n display: flex;\n flex-direction: column;\n width: 100%;\n}\n\n.AppHeader:not([data-brand-divider]) {\n border-bottom: 1px solid var(--lea-palette-border-base);\n}\n\n.AppHeaderContent {\n display: flex;\n align-items: center;\n justify-content: center;\n gap: calc(var(--lea-spacing) * 2);\n padding-block: var(--lea-spacing);\n padding-inline: calc(var(--lea-spacing) * 2);\n}\n\n.AppHeaderContent[data-fluid] {\n max-width: none;\n}\n\n.AppHeader[data-has-children] .AppHeaderContent {\n justify-content: space-between;\n}\n\n.AppHeaderLogo {\n display: flex;\n flex-shrink: 0;\n}\n\n.AppHeaderActions {\n display: flex;\n align-items: center;\n gap: var(--lea-spacing);\n}\n","import { Children, type ReactNode } from \"react\";\n\nimport { Container } from \"../layout/container\";\nimport styles from \"./app-header.module.css\";\nimport { BrandDivider } from \"./brand-divider\";\n\nexport type AppHeaderProps = {\n /**\n * Shows the brand divider under the header. Without it, the header gets a\n * bottom border instead.\n * @default true\n */\n brandDivider?: boolean;\n /**\n * Lets the content span the full width instead of stopping at the `lg`\n * breakpoint. The side padding stays.\n * @default false\n */\n fluid?: boolean;\n /**\n * Content for the right-hand side, e.g. buttons. Without children the logo\n * is centred.\n */\n children?: ReactNode;\n /**\n * The logo to display in the header.\n */\n logo?: ReactNode;\n /**\n * Additional classes to apply to the header.\n */\n className?: string;\n};\n\nexport const AppHeader = ({\n brandDivider = true,\n fluid = false,\n children,\n logo,\n className,\n}: AppHeaderProps) => {\n const hasChildren = Children.toArray(children).length > 0;\n\n return (\n <header\n className={[styles.AppHeader, className].filter(Boolean).join(\" \")}\n data-brand-divider={brandDivider || undefined}\n data-has-children={hasChildren || undefined}\n >\n <Container\n className={styles.AppHeaderContent}\n data-fluid={fluid || undefined}\n >\n <div className={styles.AppHeaderLogo}>\n {logo ? logo : <img src=\"/leabank-logo.png\" alt=\"Logo\" width={100} />}\n </div>\n {hasChildren && (\n <div className={styles.AppHeaderActions}>{children}</div>\n )}\n </Container>\n {brandDivider && <BrandDivider size=\"sm\" />}\n </header>\n );\n};\n","import {\n createContext,\n useContext,\n useMemo,\n type ReactNode,\n} from \"react\";\n\nimport { COUNTRIES, type Country, type Currency } from \"./countries\";\n\nexport interface CountryContextValue {\n country: Country;\n locale: string;\n currency: Currency;\n}\n\nconst CountryContext = createContext<CountryContextValue | null>(null);\n\nexport interface CountryProviderProps {\n country: Country;\n children: ReactNode;\n}\n\n/**\n * Supplies the active Lea Bank country to locale-aware formatting hooks.\n */\nexport function CountryProvider({ country, children }: CountryProviderProps) {\n const value = useMemo<CountryContextValue>(() => {\n const config = COUNTRIES[country];\n\n return {\n country: config.country,\n locale: config.locale,\n currency: config.currency,\n };\n }, [country]);\n\n return (\n <CountryContext.Provider value={value}>{children}</CountryContext.Provider>\n );\n}\n\n/**\n * Reads the active country, locale, and default currency from the nearest\n * `CountryProvider`.\n */\nexport function useCountry(): CountryContextValue {\n const context = useContext(CountryContext);\n\n if (!context) {\n throw new Error(\n \"Country hooks must be used within a <CountryProvider>.\",\n );\n }\n\n return context;\n}\n","import { useCallback, useMemo } from \"react\";\n\nimport { type Currency } from \"./country/countries\";\nimport { useCountry } from \"./country/country-context\";\n\nexport type FormatCurrencyOptions = Omit<\n Intl.NumberFormatOptions,\n \"style\" | \"currency\"\n> & {\n currency?: Currency;\n};\n\n/**\n * Returns a locale-aware currency formatter using the active country's locale\n * and default currency. Pass `currency` in options to override per call.\n */\nexport function useFormatCurrency() {\n const { locale, currency: defaultCurrency } = useCountry();\n\n const defaultFormatter = useMemo(\n () =>\n new Intl.NumberFormat(locale, {\n style: \"currency\",\n currency: defaultCurrency,\n }),\n [locale, defaultCurrency],\n );\n\n return useCallback(\n (value: number, options?: FormatCurrencyOptions) => {\n const { currency = defaultCurrency, ...formatOptions } = options ?? {};\n\n if (\n currency === defaultCurrency &&\n Object.keys(formatOptions).length === 0\n ) {\n return defaultFormatter.format(value);\n }\n\n return new Intl.NumberFormat(locale, {\n style: \"currency\",\n currency,\n ...formatOptions,\n }).format(value);\n },\n [defaultCurrency, defaultFormatter, locale],\n );\n}\n","import { useCallback, useMemo } from \"react\";\n\nimport { useCountry } from \"./country/country-context\";\n\nconst DEFAULT_DATE_OPTIONS: Intl.DateTimeFormatOptions = {\n year: \"numeric\",\n month: \"short\",\n day: \"numeric\",\n};\n\nfunction toDate(value: Date | number | string): Date {\n return value instanceof Date ? value : new Date(value);\n}\n\n/**\n * Returns a locale-aware date formatter using the active country's locale.\n */\nexport function useFormatDate() {\n const { locale } = useCountry();\n\n const defaultFormatter = useMemo(\n () => new Intl.DateTimeFormat(locale, DEFAULT_DATE_OPTIONS),\n [locale],\n );\n\n return useCallback(\n (value: Date | number | string, options?: Intl.DateTimeFormatOptions) => {\n const date = toDate(value);\n\n if (!options) {\n return defaultFormatter.format(date);\n }\n\n return new Intl.DateTimeFormat(locale, options).format(date);\n },\n [defaultFormatter, locale],\n );\n}\n","import { useCallback, useMemo } from \"react\";\n\nimport { useCountry } from \"./country/country-context\";\n\n/**\n * Returns a locale-aware plain-number formatter using the active country's\n * locale.\n */\nexport function useFormatNumber() {\n const { locale } = useCountry();\n\n const defaultFormatter = useMemo(\n () => new Intl.NumberFormat(locale),\n [locale],\n );\n\n return useCallback(\n (value: number, options?: Intl.NumberFormatOptions) => {\n if (!options) {\n return defaultFormatter.format(value);\n }\n\n return new Intl.NumberFormat(locale, options).format(value);\n },\n [defaultFormatter, locale],\n );\n}\n\n/**\n * Returns a locale-aware percentage formatter using the active country's\n * locale.\n */\nexport function useFormatPercentage() {\n const { locale } = useCountry();\n\n const defaultFormatter = useMemo(\n () =>\n new Intl.NumberFormat(locale, {\n style: \"percent\",\n minimumFractionDigits: 2,\n maximumFractionDigits: 2,\n }),\n [locale],\n );\n\n return useCallback(\n (value: number, options?: Intl.NumberFormatOptions) => {\n if (!options) {\n return defaultFormatter.format(value);\n }\n\n return new Intl.NumberFormat(locale, {\n style: \"percent\",\n ...options,\n }).format(value);\n },\n [defaultFormatter, locale],\n );\n}\n","import { useCallback } from \"react\";\n\nimport { useCountry } from \"../country/country-context\";\nimport {\n isValidBankAccount,\n isValidNationalId,\n isValidPhoneNumber,\n validateBankAccount,\n validateNationalId,\n validatePhoneNumber,\n type ValidationResult,\n} from \"../../validation\";\n\n/**\n * Returns a national-id validator bound to the active country (from\n * `CountryProvider`). The returned function reports a boolean; use\n * {@link useValidateNationalId}'s `.validate` for the normalized value.\n */\nexport function useValidateNationalId() {\n const { country } = useCountry();\n\n const isValid = useCallback(\n (value: string): boolean => isValidNationalId(country, value),\n [country],\n );\n\n const validate = useCallback(\n (value: string): ValidationResult => validateNationalId(country, value),\n [country],\n );\n\n return Object.assign(isValid, { validate });\n}\n\n/**\n * Returns a phone-number validator bound to the active country.\n */\nexport function useValidatePhoneNumber() {\n const { country } = useCountry();\n\n const isValid = useCallback(\n (value: string): boolean => isValidPhoneNumber(country, value),\n [country],\n );\n\n const validate = useCallback(\n (value: string): ValidationResult => validatePhoneNumber(country, value),\n [country],\n );\n\n return Object.assign(isValid, { validate });\n}\n\n/**\n * Returns a bank-account validator bound to the active country.\n */\nexport function useValidateBankAccount() {\n const { country } = useCountry();\n\n const isValid = useCallback(\n (value: string): boolean => isValidBankAccount(country, value),\n [country],\n );\n\n const validate = useCallback(\n (value: string): ValidationResult => validateBankAccount(country, value),\n [country],\n );\n\n return Object.assign(isValid, { validate });\n}\n","\"use client\";\n\nimport { type ReactNode } from \"react\";\nimport { LanguageContext } from \"../i18n/language-context\";\nimport { DEFAULT_LANGUAGE, type Language } from \"../i18n/languages\";\n\nexport type LeaProviderProps = {\n /** Language for the library's built-in translations and date locales. @default \"no\" */\n language?: Language;\n children: ReactNode;\n};\n\n/**\n * Sets the language of the library's own texts (`createTranslation`) and of\n * the components that format by locale. That is all it does: no component\n * needs it to render, and without it the language is Norwegian.\n */\nexport function LeaProvider({\n language = DEFAULT_LANGUAGE,\n children,\n}: LeaProviderProps) {\n return (\n <LanguageContext.Provider value={language}>\n {children}\n </LanguageContext.Provider>\n );\n}\n","/**\n * Viewport widths in pixels where layouts may change. Mobile-first: each value\n * is the `min-width` at which the breakpoint starts. The values match MUI's\n * defaults, so the MUI wrappers and the CSS Modules switch at the same widths.\n *\n * CSS custom properties can't be used in `@media`, so CSS Modules write the\n * pixel value literally; tests/tokens.test.ts checks it against this scale.\n */\nexport const breakpoints = {\n xs: 0,\n sm: 600,\n md: 900,\n lg: 1200,\n xl: 1536,\n} as const;\n\nexport type Breakpoint = keyof typeof breakpoints;\n","export type FormatDecimals = { value: number; decimalPlaces?: number };\n\n/**\n\n * Formats a number to a fixed number of decimal places (default is 2)\n * by using exponential notation\n *\n * ⚠️ Note: We avoid using `toFixed` for rounding because it can introduce rounding errors.\n * \n * @param value - The number to format.\n * @param decimalPlaces - Number of decimal places to show (default: 2).\n * @returns The number with fixed decimal places.\n */\nexport const fixDecimals = ({ value, decimalPlaces = 2 }: FormatDecimals) => {\n return Number(\n Math.round(parseFloat(value + \"e\" + decimalPlaces)) + \"e-\" + decimalPlaces\n );\n};\n","import { fixDecimals, FormatDecimals } from \"./formatDecimal\";\n\n/**\n * Formats a number to a fixed number of decimal places (default is 2).\n *\n * Ensures that string representation of number always has the set number of decimals (even eg. .00)\n *\n * @param value - The number or string to format.\n * @param decimalPlaces - Number of decimal places to show (default: 2).\n * @returns A string representation of the number with fixed decimal places.\n */\nexport const fixDecimalsToString = ({\n value,\n decimalPlaces = 2,\n}: FormatDecimals) => {\n return fixDecimals({ value, decimalPlaces }).toFixed(decimalPlaces);\n};\nexport const formatDecimalString = ({\n value,\n decimalPlaces = 2,\n}: FormatDecimals): string => {\n return fixDecimals({ value, decimalPlaces }) % 1 === 0\n ? fixDecimalsToString({ value, decimalPlaces: 0 }).replace(\".\", \",\")\n : fixDecimalsToString({ value, decimalPlaces }).replace(\".\", \",\");\n};\n","import { formatDecimalString } from \"./formatDecimalString\";\n\nexport const formatPercentage = (value: number, decimalPlaces: number = 2) => {\n return formatDecimalString({ value, decimalPlaces }) + \"%\";\n};\n","export function parseExpirationDate(expirationDate: string): {\n month: string;\n year: string;\n} {\n const match = expirationDate.match(/^([0-9]{2})([0-9]{2})$/);\n if (!match) return { month: \"\", year: \"\" };\n return { month: match[1], year: match[2] };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GC8Ba,MAAkB,EAC7B,UACA,UACA,eACA,cACA,aACA,cAAW,SAEX,MAAM,KAAK,EAAE,QAAQ,EAAM,IAAI,GAAG,MAAM;CACtC,IAAM,IAAS,IAAI,IAAS,KAAK,KAAK,GAChC,IAAW,IAAQ,EAAW,CAAC;CACrC,OAAO;EACL,IAAI;EACJ,GAAG,KAAK,IAAI,CAAK,IAAI;EACrB,GAAG,KAAK,IAAI,CAAK,IAAI;EACrB,SAAS,EAAU,CAAC;EACpB,OAAO,IAAI,KAAM;EACjB,GAAI,IAAW,EAAE,QAAQ,EAAS,CAAC,EAAE,IAAI,CAAC;EAC1C,GAAI,IAAW,EAAE,OAAO,IAAI,KAAM,IAAI,IAAI,MAAM,IAAI,IAAI,CAAC;CAC3D;AACF,CAAC,GAYU,MAAqB,EAChC,cACA,aAAU,gBACV,WAAQ,MAAY,iBAAiB,MAAO,IAC5C,cAAW,MAAY,iBAAiB,MAAM,IAC9C,qBAAkB,MAAY,aAE9B,EAAU,KAAK,MACb,kBAAC,EAAO,MAAR;CAEE,SAAS;EAAE,GAAG;EAAG,GAAG;EAAG,OAAO;EAAG,SAAS;CAAE;CAC5C,SACE,MAAY,iBACR;EACE,GAAG,CAAC,GAAG,EAAE,CAAC;EACV,GAAG;GAAC;GAAG,EAAE;GAAG,EAAE,IAAI;EAAE;EACpB,OAAO;GAAC;GAAG;GAAG;EAAG;EACjB,SAAS;GAAC;GAAG;GAAG;EAAC;EACjB,QAAQ,EAAE,QAAQ,OAAqB,KAAA,IAAd,CAAC,GAAG,EAAE,IAAI;CACrC,IACA;EACE,GAAG,CAAC,GAAG,EAAE,CAAC;EACV,GAAG,CAAC,GAAG,EAAE,CAAC;EACV,OAAO;GAAC;GAAG;GAAG;EAAG;EACjB,SAAS;GAAC;GAAG;GAAG;EAAC;CACnB;CAEN,YAAY;EACV;EACA,MAAM;EACN,OAAO,MAAY,iBAAiB;GAAC;GAAG;GAAM;EAAC,IAAI;GAAC;GAAG;GAAK;EAAC;EAC7D;CACF;CACA,OAAO;EACL,UAAU;EACV,OAAO,EAAE;EACT,QAAQ,EAAE;EACV,cAAc,EAAE,QAAQ,QAAQ;EAChC,iBAAiB,IAAkB,iBAAiB,EAAE;EACtD,eAAe;CACjB;AACD,GAhCM,EAAE,EAgCR,CACF,GAUU,MAAkB,EAC7B,SACA,aACA,cACA,kBAEA,kBAAC,QAAD;CACE,WAAW,CAAC,EAAO,OAAO,CAAS,CAAC,CAAC,OAAO,OAAO,CAAC,CAAC,KAAK,GAAG;CAC7D,OAAO;EAAE,OAAO;EAAM,QAAQ;CAAK;CAElC,UAAA,KAAY,kBAAC,GAAD;EAAO,MAAM;EAAU,aAAa;EAAG,eAAA;CAAa,CAAA;AAC7D,CAAA,GC9GF,KAAM,IAMC,MAAW,EACtB,SACA,eAAY,KACZ,UACA,mBAEA,kBAAC,QAAD;CACE,GAAK,KAAS,OAEV,EAAE,eAAe,GAAK,IADtB;EAAE,MAAM;EAAe,cAAc;CAAM;CAE/C,WAAW,CAAC,EAAO,SAAS,CAAS,CAAC,CAAC,OAAO,OAAO,CAAC,CAAC,KAAK,GAAG;CAC/D,OAAO;EAAE,OAAO;EAAM,QAAQ;CAAK;CAEnC,UAAA,kBAAC,OAAD;EACE,WAAW,EAAO;EAClB,SAAS,GAAG,KAAM,EAAE,GAAG,KAAM,EAAE,GAAG,GAAI,GAAG;EAEzC,UAAA,kBAAC,UAAD;GACE,IAAI;GACJ,IAAI;GACJ,IAAI,KAAM,KAAa;GACvB,MAAK;GACL,QAAO;GACP,aAAa;GACb,iBAAgB;EACjB,CAAA;CACE,CAAA;AACD,CAAA,GC3CK,KAAY;CAAC;CAAM;CAAM;CAAM;AAAI,GAKnC,KAAmB,MCAnB,KAAkB,EAAA,IAAwC,GAG1D,WAA8B,EAAW,EAAe;;;ACkBrE,SAAgB,EAA+C,GAAW;CACxE,OAAO,WAAmD;EACxD,IAAM,IAAW,GAAY,GACvB,IAAS,CAAC;EAKhB,OAJA,OAAQ,KAAK,CAAM,CAAC,CAAiB,SAAS,MAAQ;GACpD,IAAM,IAAM,EAAO;GACnB,EAAO,KAAO,EAAI,MAAa,EAAA;EACjC,CAAC,GACM;CACT;AACF;;;ACvCA,IAAa,KAAqB,EAAkB;CAClD,SAAS;EACP,IAAI;EACJ,IAAI;EACJ,IAAI;EACJ,IAAI;CACN;CACA,SAAS;EACP,IAAI;EACJ,IAAI;EACJ,IAAI;EACJ,IAAI;CACN;CACA,MAAM;EAAE,IAAI;EAAU,IAAI;EAAS,IAAI;EAAU,IAAI;CAAa;CAClE,WAAW;EACT,IAAI;EACJ,IAAI;EACJ,IAAI;EACJ,IAAI;CACN;AACF,CAAC,GCWK,KAAiB,GAQV,MAAc,EACzB,WACA,UAAO,IACP,WAAQ,WACR,eACqB;CACrB,IAAM,IAAuB,EAAiB,GACxC,IAAS,GAAmB,GAE5B,IAAO,KAAK,IAAI,GAAG,KAAK,MAAM,IAAO,GAAI,CAAC,GAC1C,IAAa,IAAO,KAAM,GAC1B,IAAY,KAAK,MAAM,IAAO,EAAG,GACjC,IAAQ,GAER,IAAY,QAEd,GAAe;EACb,OAAO;EACP;EACA,aAAa,MAAM,KAAO,IAAI,IAAK;EACnC,YAAY,MAAM,KAAK,IAAI,GAAG,KAAK,MAAM,IAAO,EAAG,CAAC,IAAK,IAAI;CAC/D,CAAC,GACH,CAAC,GAAO,CAAI,CACd,GAEM,IAAe,IAAuB,IAAI;CAEhD,OACE,kBAAC,QAAD;EACE,MAAK;EACL,cAAY,KAAS,EAAO;EAC5B,WAAW,EAAO;EAClB,cAAY;EACZ,OAAO;GAAE,OAAO;GAAM,QAAQ;EAAK;EALrC,UAAA,CAOE,kBAAC,GAAD;GAAiB,MAAK;GAAtB,UAAA;IACG,MAAW,aACV,kBAAC,EAAO,MAAR;KAEE,SAAS,EAAE,SAAS,EAAE;KACtB,SAAS,EAAE,SAAS,EAAE;KACtB,MAAM,EAAE,SAAS,EAAE;KACnB,YAAY,EAAE,UAAU,EAAa;KACrC,WAAW,EAAO;KAElB,UAAA,kBAAC,QAAD;MAAM,WAAW,EAAO;MAAM,OAAO,EAAE,aAAa,EAAK;KAAI,CAAA;IAClD,GARP,SAQO;IAGd,MAAW,aACV,kBAAC,EAAO,MAAR;KAEE,SAAS,EAAE,SAAS,EAAE;KACtB,SAAS,EAAE,SAAS,EAAE;KACtB,MAAM,EAAE,SAAS,EAAE;KACnB,YAAY,EAAE,UAAU,EAAa;KACrC,WAAW,EAAO;KAElB,UAAA,kBAAC,IAAD;MAAe;MAAiB;KAAY,CAAA;IACjC,GARP,SAQO;IAGd,MAAW,UACV,kBAAC,EAAO,MAAR;KAEE,SAAS,EAAE,SAAS,EAAE;KACtB,SAAS,EAAE,SAAS,EAAE;KACtB,MAAM,EAAE,SAAS,EAAE;KACnB,YAAY,EAAE,UAAU,EAAa;KACrC,WAAW,EAAO;KAElB,UAAA,kBAAC,EAAO,MAAR;MACE,SAAS,MAA+B,EAAE,OAAO,EAAE;MACnD,SAAS,IAAuB,CAAC,IAAI,EAAE,OAAO;OAAC;OAAG;OAAM;MAAC,EAAE;MAC3D,YAAY;OACV,UAAU;OACV,MAAM;OACN,OAAO;QAAC;QAAG;QAAK;OAAC;MACnB;MACA,OAAO,EAAE,SAAS,OAAO;MAEzB,UAAA,kBAAC,IAAD;OAAsB;OAAM,UAAU;MAAY,CAAA;KACvC,CAAA;IACF,GAnBP,MAmBO;GAEA;EAEhB,CAAA,GAAA,CAAC,KAAwB,MAAW,UACnC,kBAAC,IAAD;GAA8B;GAAW,SAAQ;EAAQ,CAAA,CAEvD;;AAEV,GCrIa,KAAS;CACpB,QAAQ;EACN,IAAI;EACJ,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK;CACP;CACA,MAAM;EACJ,IAAI;EACJ,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK;CACP;CACA,MAAM;EACJ,IAAI;EACJ,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK;CACP;CACA,QAAQ;EACN,IAAI;EACJ,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK;CACP;CACA,OAAO;EACL,IAAI;EACJ,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK;CACP;CACA,KAAK;EACH,IAAI;EACJ,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK;CACP;CACA,OAAO;EACL,IAAI;EACJ,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK;CACP;CACA,SAAS;EACP,IAAI;EACJ,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK;EACL,KAAK;CACP;CACA,OAAO;CACP,OAAO;AACT,GCxGM,EAAE,YAAQ,UAAM,UAAM,WAAO,SAAK,YAAS,WAAO,cAAU,IASrD,KAAmB;CAC9B,IAAI;EACF,MAAM;EACN,QAAQ,EAAQ;EAChB,OAAO,GAAM;EACb,UAAU,EAAQ;EAClB,QAAQ,GAAO;EACf,WAbW,GAAa,MAAoB;GAC9C,IAAM,CAAC,GAAG,GAAG,KAAK;IAAC;IAAG;IAAG;GAAC,CAAC,CAAC,KAAK,MAAM,SAAS,EAAI,MAAM,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;GAExE,OAAO,QAAQ,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAQ;EAC3C,EASa,CAAM,EAAQ,MAAM,EAAG;CAClC;CACA,MAAM;EACJ,MAAM,EAAQ;EACd,QAAQ,EAAQ;EAChB,OAAO,EAAQ;EACf,QAAQ,GAAO;EACf,UAAU;CACZ;CACA,QAAQ;EACN,MAAM,EAAQ;EACd,QAAQ,EAAQ;EAChB,QAAQ,EAAQ;EAChB,QAAQ,GAAO;EACf,UAAU;CACZ;CACA,SAAS;EACP,MAAM,GAAO;EACb,OAAO,GAAO;EACd,QAAQ,GAAO;EACf,UAAU;CACZ;CACA,WAAW;EACT,MAAM,EAAQ;EACd,OAAO,EAAQ;EACf,QAAQ,EAAQ;EAChB,UAAU;CACZ;CACA,UAAU;EACR,MAAM,GAAK;EACX,OAAO,GAAK;EACZ,QAAQ,GAAK;EACb,UAAU;CACZ;CACA,QAAQ;EACN,OAAO;GACL,MAAM,GAAI;GACV,QAAQ,GAAI;EACd;EACA,SAAS;GACP,MAAM,GAAM;GACZ,QAAQ,GAAM;EAChB;EACA,MAAM;GACJ,MAAM,GAAK;GACX,QAAQ,GAAK;EACf;EACA,SAAS;GACP,MAAM,GAAK;GACX,QAAQ,GAAK;EACf;CACF;AACF,GCjCM,KAAU;CACd,IAAI;EAAE,KAAK;EAAI,OAAO;EAAI,MAAM;EAAI,OAAO;CAAG;CAC9C,IAAI;EAAE,KAAK;EAAK,OAAO;EAAK,MAAM;EAAI,OAAO;CAAI;AACnD,GAEM,KAAiB,IAKjB,KAAkB;CACtB,GAAQ,QAAQ;CAChB,GAAQ,SAAS;CACjB,GAAO,KAAK;CACZ,GAAO,OAAO;AAChB,GAEa,MAAkB,EAC7B,UAAO,MACP,WAAQ,WACR,eACyB;CACzB,IAAM,IAAuB,EAAiB,GACxC,IAAS,GAAmB,GAC5B,EAAE,QAAK,UAAO,SAAM,aAAU,GAAQ,IAEtC,IAAY,QAEd,GAAe;EACb,OAAO;EACP;EACA,aAAa,MAAM,KAAO,IAAI,IAAK;EACnC,YAAY,MAAM,IAAK,IAAI,IAAK;EAChC,WAAW,MAAM,GAAgB,IAAI,GAAgB;EACrD,UAAU;CACZ,CAAC,GACH,CAAC,CAAK,CACR;CAEA,OACE,kBAAC,OAAD;EACE,MAAK;EACL,cAAY,KAAS,EAAO;EAC5B,WAAW,EAAO;EAClB,cAAY;EACZ,OAAO;GAAE,OAAO;GAAK,QAAQ;EAAI;EALnC,UAAA;GAOE,kBAAC,QAAD;IAAM,WAAW,EAAO;IAAM,OAAO;KAAE,OAAO;KAAO,QAAQ;IAAM;GAAI,CAAA;GAEtE,CAAC,KACA,kBAAC,IAAD;IAA8B;IAAW,SAAQ;GAAgB,CAAA;GAGnE,kBAAC,EAAO,KAAR;IACE,SAAS,MAA+B;KAAE,OAAO;KAAG,QAAQ;IAAI;IAChE,SACE,IAAuB,CAAC,IAAI;KAAE,OAAO;MAAC;MAAG;MAAM;KAAC;KAAG,QAAQ,CAAC,KAAK,CAAC;IAAE;IAEtE,YAAY;KACV,UAAU;KACV,MAAM;KACN,OAAO;MAAC;MAAG;MAAM;KAAC;IACpB;IACA,OAAO,EAAE,SAAS,OAAO;IAEzB,UAAA,kBAAC,IAAD;KACE,MAAM;KACN,UAAU;KACV,WAAW,EAAO;IACnB,CAAA;GACS,CAAA;EACT;;AAET,GCxFM,KAAU;CACd,IAAI;EAAE,WAAW;EAAI,QAAQ;EAAI,SAAS;CAAG;CAC7C,IAAI;EAAE,WAAW;EAAK,QAAQ;EAAK,SAAS;CAAG;AACjD,GAEa,MAAkB,EAAE,UAAO,MAAM,eAAiC;CAC7E,IAAM,EAAE,cAAW,WAAQ,eAAY,GAAQ,IACzC,IAAS,GAAmB,GAE5B,IAAa;EAAE,OAAO;EAAQ,QAAQ;CAAO;CAEnD,OACE,kBAAC,OAAD;EACE,WAAW,EAAO;EAClB,OAAO;GAAE,OAAO;GAAW,QAAQ;EAAU;EAF/C,UAAA;GAIE,kBAAC,QAAD;IAAM,WAAW,EAAO;IAAW,OAAO;GAAa,CAAA;GACvD,kBAAC,QAAD;IACE,WAAW,EAAO;IAClB,OAAO;KAAE,GAAG;KAAY,gBAAgB;IAAO;GAChD,CAAA;GACD,kBAAC,QAAD;IAAM,WAAW,EAAO;IAAa,OAAO;GAAa,CAAA;GACzD,kBAAC,IAAD;IACE,MAAM;IACN,OAAO,KAAS,EAAO;IACvB,WAAW,EAAO;GACnB,CAAA;EACE;;AAET,GCVM,KAAU;CAAE,IAAI;CAAI,IAAI;AAAI,GAQrB,MAAmB,EAC9B,YACA,UAAO,MACP,WAAQ,WACR,kBAAe,GACf,iBACA,mBAC0B;CAC1B,IAAM,IAAuB,EAAiB,GACxC,IAAS,GAAmB,GAC5B,CAAC,GAAM,KAAW,EAAS,CAAC,CAAO,GACnC,IAAe,EAAsB,IAAU,KAAK,IAAI,IAAI,IAAI;CAEtE,QAAgB;EACd,IAAI,GAAS;GAEX,AADA,EAAa,UAAU,KAAK,IAAI,GAChC,EAAQ,EAAK;GACb;EACF;EAEA,IAAM,IACJ,EAAa,WAAW,OAEpB,IADA,KAAK,IAAI,IAAI,EAAa,SAE1B,IAAY,KAAK,IAAI,GAAG,IAAe,CAAO;EAEpD,IAAI,MAAc,GAAG;GACnB,EAAQ,EAAI;GACZ;EACF;EAEA,IAAM,IAAQ,OAAO,iBAAiB,EAAQ,EAAI,GAAG,CAAS;EAC9D,aAAa,OAAO,aAAa,CAAK;CACxC,GAAG,CAAC,GAAS,CAAY,CAAC;CAE1B,IAAM,IAAO,GAAQ,IACf,IAAW,IAAuB,IAAI;CAE5C,OACE,kBAAC,OAAD;EACE,MAAK;EACL,aAAU;EACV,WAAW,EAAO;EAClB,OAAO;GAAE,OAAO;GAAM,QAAQ;EAAK;EAJrC,UAAA,CAME,kBAAC,GAAD;GAAiB,MAAK;GACnB,UAAA,IACC,kBAAC,EAAO,KAAR;IAEE,eAAA;IACA,SAAS,EAAE,SAAS,EAAE;IACtB,SAAS,EAAE,SAAS,EAAE;IACtB,MAAM,EAAE,SAAS,EAAE;IACnB,YAAY,EAAE,YAAS;IACvB,WAAW,EAAO;IAElB,UAAA,kBAAC,IAAD;KAAsB;KAAa;IAAQ,CAAA;GACjC,GATN,OASM,IAEZ,kBAAC,EAAO,KAAR;IAEE,eAAA;IACA,SAAS,EAAE,SAAS,EAAE;IACtB,SAAS,EAAE,SAAS,EAAE;IACtB,MAAM,EAAE,SAAS,EAAE;IACnB,YAAY,EAAE,YAAS;IACvB,WAAW,EAAO;IAElB,UAAA,kBAAC,IAAD,EAAsB,QAAO,CAAA;GACnB,GATN,OASM;EAEC,CAAA,GACjB,kBAAC,QAAD;GAAM,WAAW,EAAO;GACrB,UAAA,IAAQ,KAAa,EAAO,OAAS,KAAgB,EAAO;EACzD,CAAA,CACH;;AAET,GClHa,KACF,GAAc,OACtB,MACC,CAAC,GAAM,OAAO,KAAc,aAAa,EAAU,CAAK,IAAI,CAAS,CAAC,CACnE,OAAO,OAAO,CAAC,CACf,KAAK,GAAG;;;;;;;;;GGsCT,MACJ,MAEA,EAAiD,CAAM,MACtD,EAAO,MAAM,QAAQ,QAAQ,EAAO,MAAM,MAAM,OAE7C,MAAkB,MAAsB,EAAM,eAAe;AAOnE,SAAgB,GAAW,EACzB,aAAU,IACV,aACA,cACA,WACA,iBACA,0BACA,QACA,GAAG,KACe;CAClB,IAAM,IAAa,GAAQ,KAAY,IACjC,IAAS,GAAc,CAAM,GAE7B,IAAS;EACb,aAAa,KAAW,KAAA;EACxB,gBAAgB,KAAW,KAAA;CAC7B;CAsBA,OApBa,EAAU;EACrB,SAAS;EACT,QAAQ,IAAS,IAAS,KAAA;EAC1B;EACA,gBAAgB;EAChB,OAAO;GACL,GAAG;GACH,GAAG;GACH,iBAAiB,KAAc,KAAA;GAC/B,iBAAiB,IAAa,KAAK,KAAA;GACnC,WACE,OAAO,KAAc,aACjB,EAAU,EAAE,UAAU,EAAW,CAAC,IAClC;GACN,SAAS,IAAa,KAAiB,EAAK;EAC9C;CACF,CAEI,KAGF,kBAAC,IAAD;EACE,GAAI;EACJ,GAAI;EACC;EACG;EACM;EACS;EACvB,UAAU;EACC;CACZ,CAAA;AAEL;AAOA,SAAgB,GAAW,EACzB,aAAU,SACV,WAAQ,WACR,UAAO,MACP,cACA,GAAG,KACe;CAClB,OACE,kBAAC,IAAD;EACE,GAAI;EACJ,gBAAc;EACd,cAAY;EACZ,aAAW;EACX,WAAW,EAAe,GAAO,QAAQ,CAAS;CACnD,CAAA;AAEL;;;ACvHA,SAAgB,GAAa,EAC3B,aACA,cACA,GAAG,KACiB;CACpB,OACE,kBAAC,IAAD;EACE,GAAI;EACJ,WAAW,EAAe,GAAO,cAAc,CAAS;EAF1D,UAAA,CAIG,GACD,kBAAC,GAAD;GAAY,eAAA;GAAY,WAAW,GAAO;EAAQ,CAAA,CACxC;;AAEhB;;;ACSA,SAAgB,GAAO,EACrB,cACA,YACA,aAAU,IACV,iBACA,aACA,GAAG,KACW;CACd,OACE,kBAAA,GAAA,EAAA,UAAA,CACE,kBAAC,IAAD;EACE,GAAI;EACK;EACT,mBAAiB,KAAW,KAAa,QAAQ,KAAA;EACjD,iBAAe,KAAW,QAAQ,KAAA;EAJpC,UAAA;GAMG,IAAU,kBAAC,QAAD;IAAM,WAAW,GAAO;IAAS,eAAA;GAAa,CAAA,IAAI;GAC5D;GACA;EACS;CACX,CAAA,GAAA,KAAgB,QACf,kBAAC,QAAD;EAAM,MAAK;EAAS,WAAW,GAAO;EACnC,UAAA,IAAU,IAAe;CACtB,CAAA,CAER,EAAA,CAAA;AAEN;;;AClEA,IAAa,KAAgB,EAAkB,EAC7C,OAAO;CACL,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;AACN,EACF,CAAC;;;ACsBD,SAAgB,GAAW,EACzB,aAAU,IACV,cACA,aACA,GAAG,KACe;CAClB,OACE,kBAAC,IAAD;EACE,GAAI;EACK;EACT,WAAW,EAAe,GAAO,YAAY,CAAS;EAErD,UAAA,IAAU,kBAAC,QAAD;GAAM,WAAW,GAAO;GAAS,eAAA;EAAa,CAAA,IAAI;CACnD,CAAA;AAEhB;;;AC3BA,SAAgB,GAAY,EAC1B,UACA,aAAU,SACV,WAAQ,aACR,GAAG,KACgB;CACnB,IAAM,IAAI,GAAc;CAExB,OACE,kBAAC,IAAD;EACE,GAAI;EACK;EACF;EACP,cAAY,KAAS,EAAE;EAEvB,UAAA,kBAAC,GAAD,EAAG,eAAA,GAAa,CAAA;CACN,CAAA;AAEhB;;;AC/BA,eAAsB,GACpB,GAC2B;CAC3B,OAAO,OAAO,KAAS,aAAa,EAAK,IAAI;AAC/C;AAEA,SAAgB,GACd,GACA,GACA,GACM;CACN,IAAM,IACJ,aAAgB,OACZ,IACA,IAAI,KAAK,CAAC,CAAgB,GAAG,IAAW,EAAE,MAAM,EAAS,IAAI,KAAA,CAAS,GAEtE,IAAM,IAAI,gBAAgB,CAAI,GAC9B,IAAS,SAAS,cAAc,GAAG;CAKzC,AAJA,EAAO,OAAO,GACd,EAAO,WAAW,GAClB,EAAO,MAAM,YACb,EAAO,MAAM,GACb,IAAI,gBAAgB,CAAG;AACzB;;;AC5BA,IAAa,KAAoB,EAAkB,EACjD,UAAU;CACR,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;AACN,EACF,CAAC,GCoBY,MAAmB,EAC9B,SACA,aACA,aACA,eACA,oBACA,SAAS,GACT,aACA,GAAG,QACuB;CAC1B,IAAM,IAAS,GAAkB,GAC3B,CAAC,GAAS,KAAc,EAAS,EAAK,GACtC,IAAU,KAAe,GAEzB,IAAc,YAAY;EAC9B,EAAW,EAAI;EACf,IAAI;GAGF,AADA,GAAa,MADU,GAAoB,CAAI,GACxB,GAAU,CAAQ,GACzC,IAAa;EACf,SAAS,GAAO;GACd,IAAkB,CAAK;EACzB,UAAU;GACR,EAAW,EAAK;EAClB;CACF;CAEA,OACE,kBAAC,IAAD;EAAQ,GAAI;EAAe;EAAS,SAAS;EAC1C,UAAA,KAAY,EAAO;CACd,CAAA;AAEZ;;;AEpCA,SAAgB,GAAS,EAAE,SAAM,aAAU,cAAW,YAAwB;CAC5E,OACE,kBAAC,IAAD;EACE,QAAQ,kBAAC,KAAD,EAAS,QAAO,CAAA;EACxB,OAAM;EACN,WAAW,EAAe,GAAO,UAAU,CAAS;EAC7C;EAEN;CACS,CAAA;AAEhB;;;AChCA,IAAa,KAAY;CACvB,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,OAAO;CACP,OAAO;CACP,OAAO;CACP,OAAO;CACP,OAAO;AACT,mCE2BM,MAAmB,MACvB,qBAAqB,EAAK,WAAW,KAAK,GAAG,EAAE;AAiBjD,SAAgB,GAAK,EACnB,cACA,eACA,UACA,UACA,aACA,WACA,QACA,cACA,UACA,GAAG,KACS;CACZ,OAAO,EAAU;EACf;EACA;EACA,gBAAgB;EAChB,OAAO;GACL,GAAG;GACH,mBAAmB;GACnB,oBAAoB;GACpB,cAAc;GACd,cAAc,MAAU,YAAY,IAAQ,KAAA;GAC5C,WAAW,EAAe,GAAO,MAAM,CAAS,CAAC,CAAC,CAAC,CAAC;GACpD,OAAO;IACL,GAAI,KAAS,QAAQ,MAAU,YAC3B,EAAE,OAAO,GAAgB,CAAK,EAAE,IAChC,KAAA;IACJ,GAAI,KAAY,OAA2C,KAAA,IAApC,EAAE,UAAU,GAAU,GAAU;IACvD,GAAG;GACL;EACF;CACF,CAAC;AACH;;;;;GEjFM,MAAU,MACd,OAAO,KAAY,YAAY,OAAO,KAAY,UAcvC,MAAa,EACxB,UACA,UACA,aAAU,IACV,cACA,GAAG,QAEH,kBAAC,OAAD;CACE,GAAI;CACJ,WAAW,CAAC,GAAO,WAAW,CAAS,CAAC,CAAC,OAAO,OAAO,CAAC,CAAC,KAAK,GAAG;CACjE,gBAAc,KAAW,KAAA;CAH3B,UAAA,CAKE,kBAAC,OAAD;EAAK,WAAW,GAAO;EACpB,UAAA,GAAO,CAAK,IACX,kBAAC,IAAD;GAAM,QAAQ,kBAAC,QAAD,CAAO,CAAA;GAAG,OAAM;GAC3B,UAAA;EACG,CAAA,IAEN;CAEC,CAAA,GACL,kBAAC,OAAD;EAAK,WAAW,GAAO;EACpB,UAAA,GAAO,CAAK,IACX,kBAAC,IAAD;GAAM,QAAQ,kBAAC,QAAD,CAAO,CAAA;GAAG,YAAW;GAChC,UAAA;EACG,CAAA,IAEN;CAEC,CAAA,CACF;;;;;;;AEDP,SAAgB,GAAK,EACnB,WACA,QACA,cACA,UACA,aAAU,YACV,GAAG,KACS;CACZ,OAAO,EAAU;EACf;EACA;EACA,OAAO;GACL,GAAG;GACH,cAAc;GACd,gBAAgB;GAChB,WAAW,EAAe,GAAO,MAAM,CAAS,CAAC,CAAC,CAAC,CAAC;EACtD;CACF,CAAC;AACH;AAWA,SAAgB,GAAY,EAC1B,WACA,QACA,cACA,GAAG,KACgB;CACnB,OAAO,EAAU;EACf;EACA;EACA,OAAO;GACL,GAAG;GACH,WAAW,EAAe,GAAO,SAAS,CAAS,CAAC,CAAC,CAAC,CAAC;EACzD;CACF,CAAC;AACH;;;;;;GE/Fa,KAAgB,EAAkB,EAC7C,QAAQ;CAAE,IAAI;CAAS,IAAI;CAAW,IAAI;CAAU,IAAI;AAAW,EACrE,CAAC;;;ACsDD,SAAgB,GAAK,EACnB,UACA,WAAQ,WACR,aAAU,UACV,UAAO,MACP,SACA,aACA,gBACA,cAAW,IACX,cACA,aACA,GAAG,KACS;CACZ,IAAM,IAAS,GAAc,GAEvB,IACJ,MACC,OAAO,KAAU,WAAW,GAAG,EAAO,OAAO,GAAG,MAAU,EAAO;CAEpE,OACE,kBAAC,QAAD;EACE,GAAI;EACM;EACV,WAAW,CAAC,GAAO,MAAM,CAAS,CAAC,CAAC,OAAO,OAAO,CAAC,CAAC,KAAK,GAAG;EAC5D,cAAY;EACZ,gBAAc;EACd,aAAW;EACX,iBAAe,IAAW,KAAK,KAAA;EAPjC,UAAA;GASG,KAAQ,QAAQ,kBAAC,QAAD;IAAM,WAAW,GAAO;IAAO,UAAA;GAAW,CAAA;GAC3D,kBAAC,QAAD;IAAM,WAAW,GAAO;IAAQ,UAAA;GAAY,CAAA;GAC3C,KACC,kBAAC,UAAD;IACE,MAAK;IACL,cAAY;IACZ,WAAW,GAAO;IACR;IACV,UAAU,MAAa,KAAK,KAAK,KAAA;IACjC,SAAS;IAET,UAAA,kBAAC,GAAD,EAAS,eAAA,GAAa,CAAA;GAChB,CAAA;EAEN;;AAEV;;;;;;;;GErBM,MAAW,MACf,KAAS,QAAQ,MAAU,MAAS,MAAU,IAE1C,MAAY,MAAgC;CAChD,IAAM,CAAC,GAAM,IAAQ,YAAY,EAAU,MAAM,GAAG;CAIpD,OAAO;EAAE;EAAM;EAAO,YAAY;CAAO;AAC3C,GAEM,KACJ,+FAGI,KAAS,IAGT,KAAc;AAwBpB,SAAgB,GAAQ,EACtB,UACA,WACA,eAAY,OACZ,oBAAiB,SACjB,aACA,cACA,gBACA,oBAAiB,QACjB,cACA,YACe;CACf,IAAM,CAAC,GAAM,KAAW,EAAS,EAAK,GAChC,IAAc,EAAM,GACpB,IAAU,EAAM,GAEhB,IACJ,kBAAC,UAAD;EACE,MAAK;EACL,cAAY;EACZ,WAAW,CAAC,GAAO,SAAS,CAAS,CAAC,CAAC,OAAO,OAAO,CAAC,CAAC,KAAK,GAAG;EACxD;EACP,gBAAc;EAEb,UAAA,KAAe,kBAAC,QAAD;GAAM,eAAA;GAAY,WAAW,GAAO;EAAO,CAAA;CACrD,CAAA,GAGJ,IAAU,KAAY,GAGtB,KAAQ,MACZ,IAAW,IAAO,kBAAC,QAAD;EAAM,WAAW,GAAO;EAAa,UAAA;CAAW,CAAA;CAEpE,IAAI,GAAQ,CAAK,GAAG,OAAO,EAAK,CAAO;CAIvC,KAFuB,MAAW,IAAW,UAAU,cAEhC,SAAS;EAC9B,IAAM,IAAY,GAAU,MAAM,MAAM,GAKlC,KAAiB,MAAyC;GAC9D,IAAI,EAAM,QAAQ,SAAS,EAAM,UAAU;GAC3C,IAAM,IAAW,EAAM,cAAc,iBAAiB,EAAQ,GACxD,IAAO,EAAS,EAAS,SAAS;GACxC,CAAI,KAAQ,QAAQ,EAAM,WAAW,OACnC,EAAM,eAAe,GACrB,EAAQ,EAAK;EAEjB;EAEA,OACE,kBAAC,EAAQ,MAAT;GAAoB;GAAM,cAAc;GAAxC,UAAA,CACG,EACC,kBAAC,EAAQ,SAAT;IACE,QAAQ;IACR,IAAI;IACJ,aAAA;IACA,OAAO;GACR,CAAA,CACH,GACA,kBAAC,EAAQ,QAAT,EAAA,UACE,kBAAC,EAAQ,YAAT;IACE,GAAI,GAAS,CAAS;IACtB,WAAW,GAAO;IAElB,UAAA,kBAAC,EAAQ,OAAT;KAEE,mBAAiB;KACjB,WAAW;KACX,WAAW,GAAO;KAClB,gBAAc;KALhB,UAAA,CAOE,kBAAC,EAAQ,OAAT,EAAe,WAAW,GAAO,MAAQ,CAAA,GACzC,kBAAC,EAAQ,aAAT;MAAqB,QAAQ,kBAAC,OAAD,CAAM,CAAA;MAChC,UAAA;KACkB,CAAA,CACR;;GACG,CAAA,EACN,CAAA,CACJ;;CAElB;CAEA,IAAM,IACJ,CAAC,GAAU,MAAM,qBAAqB,KAAQ,CAAO,CAAC,CACnD,OAAO,OAAO,CAAC,CACf,KAAK,GAAG,KAAK,KAAA;CAElB,OACE,kBAAC,EAAY,MAAb;EAAwB;EAAM,cAAc;EAA5C,UAAA,CACG,EACC,kBAAC,EAAY,SAAb;GACE,QAAQ;GACR,OAAO;GAGP,oBAAkB;EACnB,CAAA,CACH,GACA,kBAAC,EAAY,QAAb,EAAA,UACE,kBAAC,EAAY,YAAb;GACE,GAAI,GAAS,CAAS;GACtB,WAAW,GAAO;GAElB,UAAA,kBAAC,EAAY,OAAb;IACE,IAAI;IACJ,MAAK;IACL,WAAW,GAAO;IAClB,gBAAc;IAJhB,UAAA,CAME,kBAAC,EAAY,OAAb,EAAmB,WAAW,GAAO,MAAQ,CAAA,GAC5C,CACgB;;EACG,CAAA,EACN,CAAA,CACJ;;AAEtB;;;;;;;;;GEtMM,KAA6B,CAAC,WAAW,SAAS,GAElD,KAA+C;CACnD,SAAS,kBAAC,GAAD;EAAa,MAAK;EAAM,eAAA;CAAa,CAAA;CAC9C,MAAM,kBAAC,GAAD;EAAM,MAAK;EAAM,eAAA;CAAa,CAAA;CACpC,SAAS,kBAAC,IAAD;EAAe,MAAK;EAAM,eAAA;CAAa,CAAA;CAChD,OAAO,kBAAC,GAAD;EAAa,MAAK;EAAM,eAAA;CAAa,CAAA;AAC9C;AAMA,SAAgB,GAAa,EAC3B,aACA,UACA,aAAU,YACV,UAAO,MACP,SACA,WACA,YACA,eACA,SACA,aACA,GAAG,KACU;CACb,IAAM,IACJ,MAAa,KAAS,GAAa,SAAS,CAAK,IAAI,SAAS,YAE1D,IAAY;EAChB,GAAG;EACH,MACE,MACC,MAAqB,WAAW,MAAqB,YAClD,UACA;EACN,cAAc,KAAS;EACvB,gBAAgB;EAChB,aAAa;CACf,GAEM,IAAe,MAAS,KAAA,IAAY,GAAW,KAAoB,GACnE,IACJ,MACC,KACC,kBAAC,IAAD;EACE,MAAK;EACL,OAAO;EACP,SAAS;EACT,WAAW,GAAO;CACnB,CAAA;CAaL,OAAO;EAAE;EAAW,SATlB,kBAAA,GAAA,EAAA,UAAA;GACG,MAAiB,MAAS,KAAgB,QACzC,kBAAC,OAAD;IAAK,WAAW,GAAO;IAAO,UAAA;GAAkB,CAAA;GAElD,kBAAC,OAAD;IAAK,WAAW,GAAO;IAAU;GAAc,CAAA;GAC9C,KAAkB,kBAAC,OAAD;IAAK,WAAW,GAAO;IAAS,UAAA;GAAoB,CAAA;EACvE,EAAA,CAGgB;CAAQ;AAC9B;;;ACtFA,SAAgB,GAAM,EAAE,cAAW,GAAG,KAAqB;CACzD,IAAM,EAAE,cAAW,eAAY,GAAa,CAAK;CAEjD,OACE,kBAAC,OAAD;EACE,GAAI;EACJ,WAAW;GAAC,GAAO;GAAO,GAAO;GAAQ;EAAS,CAAC,CAChD,OAAO,OAAO,CAAC,CACf,KAAK,GAAG;EAEV,UAAA;CACE,CAAA;AAET;AAKA,SAAgB,GAAW,EAAE,cAAW,GAAG,KAAyB;CAClE,OACE,kBAAC,OAAD;EACE,GAAI;EACJ,WAAW,CAAC,GAAO,OAAO,CAAS,CAAC,CAAC,OAAO,OAAO,CAAC,CAAC,KAAK,GAAG;CAC9D,CAAA;AAEL;;;;;;;;;;;;;;;;;;;;;;;;;IElCa,KAAO,EAAW,MAOlB,KAAU,EAAW,SAIrB,KAAS,EAAW;AAMjC,SAAgB,GAAS,EAAE,cAAW,GAAG,KAAuB;CAC9D,OACE,kBAAC,EAAW,UAAZ;EACE,GAAI;EACJ,WAAW,EAAe,GAAO,UAAU,CAAS;CACrD,CAAA;AAEL;AAKA,SAAgB,GAAS,EAAE,cAAW,GAAG,KAAuB;CAC9D,OACE,kBAAC,EAAW,UAAZ;EACE,GAAI;EACJ,WAAW,EAAe,GAAO,UAAU,CAAS;CACrD,CAAA;AAEL;AAoBA,SAAgB,GAAM,EACpB,UAAO,MACP,uBACA,cACA,GAAG,KACU;CACb,OACE,kBAAC,EAAW,OAAZ;EACE,GAAI;EACJ,aAAW;EACX,8BAA4B,KAAsB,KAAA;EAClD,WAAW,EAAe,GAAO,OAAO,CAAS;CAClD,CAAA;AAEL;AASA,SAAgB,GAAO,EAAE,cAAW,GAAG,KAAqB;CAC1D,OACE,kBAAC,OAAD;EACE,GAAI;EACJ,WAAW,CAAC,GAAO,QAAQ,CAAS,CAAC,CAAC,OAAO,OAAO,CAAC,CAAC,KAAK,GAAG;CAC/D,CAAA;AAEL;AAQA,SAAgB,GAAM,EAAE,cAAW,GAAG,KAAoB;CACxD,OACE,kBAAC,EAAW,OAAZ;EACE,GAAI;EACJ,WAAW,EAAe,GAAO,OAAO,CAAS;CAClD,CAAA;AAEL;AAKA,SAAgB,GAAY,EAAE,cAAW,GAAG,KAA0B;CACpE,OACE,kBAAC,EAAW,aAAZ;EACE,GAAI;EACJ,WAAW,EAAe,GAAO,aAAa,CAAS;CACxD,CAAA;AAEL;AAKA,SAAgB,GAAQ,EAAE,cAAW,GAAG,KAAsB;CAC5D,OACE,kBAAC,OAAD;EACE,GAAI;EACJ,WAAW,CAAC,GAAO,SAAS,CAAS,CAAC,CAAC,OAAO,OAAO,CAAC,CAAC,KAAK,GAAG;CAChE,CAAA;AAEL;AASA,SAAgB,GAAO,EAAE,cAAW,GAAG,KAAqB;CAC1D,OACE,kBAAC,OAAD;EACE,GAAI;EACJ,WAAW,CAAC,GAAO,QAAQ,CAAS,CAAC,CAAC,OAAO,OAAO,CAAC,CAAC,KAAK,GAAG;CAC/D,CAAA;AAEL;AAOA,IAAa,KAAQ,EAAW;AAehC,SAAgB,GAAY,EAAE,UAAO,cAAW,GAAG,KAA0B;CAC3E,IAAM,IAAI,GAAc;CAExB,OACE,kBAAC,EAAW,OAAZ;EACE,GAAI;EACJ,cAAY,KAAS,EAAE;EACvB,WAAW,EAAe,GAAO,aAAa,CAAS;EAEvD,UAAA,kBAAC,GAAD;GAAG,MAAM;GAAI,eAAA;EAAa,CAAA;CACV,CAAA;AAEtB;;;;;;;;;;;;;;;;;;;;;;;;;IEnLM,KAAkB;CACtB,MAAM;CACN,OAAO;CACP,KAAK;CACL,QAAQ;AACV;AAmBA,SAAgB,GAAwB,EACtC,UAAO,SACP,GAAG,KACkB;CACrB,OAAO,kBAAC,EAAW,MAAZ;EAAiB,GAAI;EAAM,gBAAgB,GAAgB;CAAQ,CAAA;AAC5E;AAMA,IAAa,KAAU,EAAW,SAIrB,KAAS,EAAW;AAMjC,SAAgB,GAAS,EAAE,cAAW,GAAG,KAAuB;CAC9D,OACE,kBAAC,EAAW,UAAZ;EACE,GAAI;EACJ,WAAW,EAAe,GAAO,UAAU,CAAS;CACrD,CAAA;AAEL;AAQA,SAAgB,GAAS,EAAE,cAAW,GAAG,KAAuB;CAC9D,OACE,kBAAC,EAAW,UAAZ;EACE,GAAI;EACJ,WAAW,EAAe,GAAO,UAAU,CAAS;CACrD,CAAA;AAEL;AASA,SAAgB,GAAM,EAAE,cAAW,GAAG,KAAoB;CACxD,OACE,kBAAC,EAAW,OAAZ;EACE,GAAI;EACJ,WAAW,EAAe,GAAO,OAAO,CAAS;CAClD,CAAA;AAEL;AAQA,SAAgB,GAAO,EAAE,cAAW,GAAG,KAAqB;CAC1D,OACE,kBAAC,OAAD;EACE,GAAI;EACJ,eAAA;EACA,WAAW,CAAC,GAAO,QAAQ,CAAS,CAAC,CAAC,OAAO,OAAO,CAAC,CAAC,KAAK,GAAG;CAC/D,CAAA;AAEL;AASA,SAAgB,GAAO,EAAE,cAAW,GAAG,KAAqB;CAC1D,OACE,kBAAC,OAAD;EACE,GAAI;EACJ,WAAW,CAAC,GAAO,QAAQ,CAAS,CAAC,CAAC,OAAO,OAAO,CAAC,CAAC,KAAK,GAAG;CAC/D,CAAA;AAEL;AAQA,SAAgB,GAAM,EAAE,cAAW,GAAG,KAAoB;CACxD,OACE,kBAAC,EAAW,OAAZ;EACE,GAAI;EACJ,WAAW,EAAe,GAAO,OAAO,CAAS;CAClD,CAAA;AAEL;AAKA,SAAgB,GAAY,EAAE,cAAW,GAAG,KAA0B;CACpE,OACE,kBAAC,EAAW,aAAZ;EACE,GAAI;EACJ,WAAW,EAAe,GAAO,aAAa,CAAS;CACxD,CAAA;AAEL;AAQA,SAAgB,GAAQ,EAAE,cAAW,GAAG,KAAsB;CAC5D,OACE,kBAAC,EAAW,SAAZ;EACE,GAAI;EACJ,WAAW,EAAe,GAAO,SAAS,CAAS;CACpD,CAAA;AAEL;AAOA,IAAa,KAAQ,EAAW;AAehC,SAAgB,GAAY,EAAE,UAAO,cAAW,GAAG,KAA0B;CAC3E,IAAM,IAAI,GAAc;CAExB,OACE,kBAAC,EAAW,OAAZ;EACE,GAAI;EACJ,cAAY,KAAS,EAAE;EACvB,WAAW,EAAe,GAAO,aAAa,CAAS;EAEvD,UAAA,kBAAC,GAAD;GAAG,MAAM;GAAI,eAAA;EAAa,CAAA;CACV,CAAA;AAEtB;;;;AElLA,SAAgB,GAAU,EACxB,UAAO,MACP,WACA,cACA,GAAG,KACc;CACjB,OAAO,EAAU;EACf;EACA,OAAO;GACL,GAAG;GACH,aAAa;GACb,WAAW,EAAe,GAAO,WAAW,CAAS,CAAC,CAAC,CAAC,CAAC;EAC3D;CACF,CAAC;AACH;;;ACfA,SAAgB,GAAY,EAC1B,WAAQ,IACR,cACA,GAAG,KACgB;CACnB,IAAM,EAAE,cAAW,eAAY,GAAa,CAAK;CAEjD,OACE,kBAAC,OAAD;EACE,GAAI;EACJ,eAAY;EACZ,WAAW,CAAC,GAAO,OAAO,CAAS,CAAC,CAAC,OAAO,OAAO,CAAC,CAAC,KAAK,GAAG;EAE7D,UAAA,kBAAC,IAAD;GAAW,WAAW,GAAO;GAAQ,cAAY,KAAS,KAAA;GACvD,UAAA;EACQ,CAAA;CACR,CAAA;AAET;;;ACHA,SAAgB,GAAa,EAC3B,UACA,gBACA,aACA,eACA,SACA,uBACA,oBACA,GAAG,KACiB;CACpB,OACE,kBAAC,IAAD;EAAa,GAAI;EACf,UAAA,kBAAC,IAAD,EAAA,UAAA,CACE,kBAAC,IAAD,CAAkB,CAAA,GAClB,kBAAC,IAAD,EAAA,UACE,kBAAC,IAAD;GAAoB;GAA0B;GAA9C,UAAA,CACE,kBAAC,IAAD,EAAA,UAAA,CACE,kBAAC,IAAD,EAAA,UAAe,EAAoB,CAAA,GAClC,CAAC,KAAmB,kBAAC,IAAD,EAAoB,OAAO,EAAa,CAAA,CAChD,EAAA,CAAA,GACf,kBAAC,IAAD,EAAA,UAAA,CACG,KAAe,QACd,kBAAC,IAAD;IAAoB,aAAW,KAAY,QAAQ,KAAA;IAChD,UAAA;GACiB,CAAA,GAErB,CACa,EAAA,CAAA,CACJ;EACC,CAAA,EAAA,CAAA,CACJ,EAAA,CAAA;CACJ,CAAA;AAEjB;;;AC3CA,SAAgB,GAAa,EAC3B,UACA,gBACA,aACA,eACA,UAAO,SACP,GAAG,KACiB;CACpB,OACE,kBAAC,IAAD;EAAa,GAAI;EAAY;EAC3B,UAAA,kBAAC,IAAD,EAAA,UAAA,CACE,kBAAC,IAAD,CAAkB,CAAA,GAClB,kBAAC,IAAD,EAAA,UACE,kBAAC,IAAD,EAAA,UAAA;GAEG,MAAS,YAAY,kBAAC,IAAD,CAAgB,CAAA;GACtC,kBAAC,IAAD,EAAA,UAAA,CACE,kBAAC,IAAD,EAAA,UAAe,EAAoB,CAAA,GACnC,kBAAC,IAAD,EAAoB,OAAO,EAAa,CAAA,CAC3B,EAAA,CAAA;GACf,kBAAC,IAAD,EAAA,UAAA,CACG,KAAe,QACd,kBAAC,IAAD;IAAoB,aAAW,KAAY,QAAQ,KAAA;IAChD,UAAA;GACiB,CAAA,GAErB,CACa,EAAA,CAAA;GACf,MAAS,SAAS,kBAAC,IAAD,CAAgB,CAAA;EACvB,EAAA,CAAA,EACC,CAAA,CACJ,EAAA,CAAA;CACJ,CAAA;AAEjB;;;;;;;;;;;;;GGjDa,MAAoD,MAC/D,kBAAA,GAAA,EAAA,UAAG,EAAM,SAAW,CAAA;AAYtB,SAAgB,GAAY,EAC1B,cAAc,GACd,oBAAoB,KACD;CACnB,OACE,kBAAC,EAAW,SAAZ;EAAoB,WAAW,GAAO;EACpC,UAAA,kBAAC,EAAW,OAAZ;GAAkB,WAAW,GAAO;GAApC,UAAA,CACE,kBAAC,EAAW,WAAZ,EAAsB,WAAW,GAAO,UAAY,CAAA,GACpD,kBAAC,EAAW,OAAZ;IACE,WAAW,GAAO;IAClB,cAAY;IACZ,oBAAkB;GACnB,CAAA,CACe;;CACA,CAAA;AAExB;AAUA,SAAgB,GAAY,EAAE,QAAK,QAAK,WAAQ,aAA4B;CAC1E,IAAM,IAAY,QACV,IAAI,KAAK,aAAa,GAAQ,CAAM,GAC1C,CAAC,GAAQ,CAAM,CACjB;CAEA,OAEE,kBAAC,OAAD;EAAK,WAAW,GAAO;EAAO,eAAA;EAA9B,UAAA,CACE,kBAAC,QAAD,EAAA,UAAO,EAAU,OAAO,CAAG,EAAQ,CAAA,GACnC,kBAAC,QAAD,EAAA,UAAO,EAAU,OAAO,CAAG,EAAQ,CAAA,CAChC;;AAET;AAUA,SAAgB,GAAiB,EAC/B,OACA,UACA,eACwB;CACxB,OACE,kBAAC,KAAD;EACM;EACJ,WAAW,GAAO;EAClB,gBAAc,IAAQ,KAAK,KAAA;EAC3B,MAAM,IAAQ,UAAU,KAAA;EAEvB;CACA,CAAA;AAEP;;;ACNA,SAAgB,GAAa,EAC3B,UACA,QACA,QACA,UAAO,GACP,OAAO,GACP,iBACA,kBACA,WACA,WACA,SACA,cAAW,IACX,eACA,WAAQ,IACR,cACA,GAAG,KACiB;CACpB,IAAM,IAAU,EAAM,GAChB,IAAU,EAAM,GAChB,IAAe,EAAM,GACrB,IAAc,KAAc,OAAsB,KAAA,IAAf,GAEnC,CAAC,GAAmB,KAAwB,EAChD,KAAgB,CAClB,GACM,IAAQ,KAAa,GAKrB,CAAC,GAAO,KAAY,EAAwB,GAE5C,KAAU,MAAiB;EAG/B,AAFA,EAAS,KAAA,CAAS,GACd,MAAc,KAAA,KAAW,EAAqB,CAAI,GAClD,MAAS,KAAO,IAAgB,CAAI;CAC1C;CAEA,OACE,kBAAC,OAAD;EACE,GAAI;EACJ,WAAW,CAAC,GAAO,cAAc,CAAS,CAAC,CAAC,OAAO,OAAO,CAAC,CAAC,KAAK,GAAG;EAFtE,UAAA;GAIE,kBAAC,SAAD;IAAO,IAAI;IAAS,SAAS;IAAS,WAAW,GAAO;IACrD,UAAA;GACI,CAAA;GAMP,kBAAC,EAAY,MAAb;IACE,IAAI;IACE;IACN,OAAO,MAAU,KAAA,IAAoB,IAAR;IAI7B,iBAAA;IACA,gBAAgB,MAAS;KACvB,AAAI,KAAQ,QAAQ,KAAQ,KAAO,KAAQ,IAAK,EAAO,CAAI,IACtD,EAAS,CAAI;IACpB;IACA,mBAAmB,MAAS;KAC1B,AAAI,KAAQ,OAAM,EAAS,KAAA,CAAS,IAC/B,EAAO,KAAK,IAAI,KAAK,IAAI,GAAM,CAAG,GAAG,CAAG,CAAC;IAChD;IACK;IACA;IACC;IACE;IACA;IACE;IAEV,UAAA,kBAAC,EAAY,OAAb;KACE,WAAW,GAAO;KAClB,oBAAkB;KAClB,gBAAc,KAAS,KAAA;KACvB,gBAAc,IAAQ,KAAK,KAAA;IAC5B,CAAA;GACe,CAAA;GAClB,kBAAC,GAAM,MAAP;IAAY,SAAS;IAAO,QAAQ;IAClC,UAAA,kBAAC,EAAW,MAAZ;KACS;KACP,eAAe;KACV;KACA;KACC;KACE;KACA;KACE;KACV,mBAAiB;KACjB,WAAW,GAAO;KAVpB,UAAA,CAYE,kBAAC,IAAD,EAAa,oBAAkB,EAAc,CAAA,GAC7C,kBAAC,IAAD;MAAkB;MAAU;MAAa;MAAgB;KAAS,CAAA,CACnD;;GACP,CAAA;GACX,KAAc,QACb,kBAAC,IAAD;IAAkB,IAAI;IAAqB;IACxC,UAAA;GACe,CAAA;EAEjB;;AAET;;;;;;;;;;;;;;;;;GG7La,KAA0B,EAAkB,EACvD,iBAAiB;CACf,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;AACN,EACF,CAAC,GCQY,MAAoB,EAAE,mBACjC,kBAAC,QAAD;CAAM,eAAA;CAAuB;CAC1B,UAAA;AACG,CAAA;AAgBR,SAAgB,GAAgB,EAC9B,OACA,UACA,aAAU,IACV,eACuB;CACvB,OACE,kBAAC,KAAD;EACM;EACJ,WAAW,GAAO;EAClB,gBAAc,IAAQ,KAAK,KAAA;EAC3B,gBAAc,KAAW,CAAC,IAAQ,KAAK,KAAA;EACvC,MAAM,IAAQ,UAAU,IAAU,WAAW,KAAA;EAE5C;CACA,CAAA;AAEP;AAOA,SAAgB,GACd,GACA,GACA,GAC0C;CAC1C,IAAM,IACJ,CAAC,KAAS,KAAW,QAAQ,MAAY,MAAS,MAAY;CAChE,OAAO;EAAE,SAAS,IAAc,IAAU;EAAY,SAAS;CAAY;AAC7E;AAwBA,SAAgB,GAAgB,EAC9B,OACA,YACA,YACA,aACA,UACA,aACA,eACuB;CACvB,IAAM,IAAS,GAAwB,GACjC,IAAa,KAAW,QAAQ,MAAY;CAElD,OACE,kBAAC,OAAD;EACE,WAAW,GAAO;EAClB,gBAAc,IAAQ,KAAK,KAAA;EAC3B,iBAAe,IAAW,KAAK,KAAA;EAHjC,UAAA,CAOE,kBAAC,QAAD,EAAA,UAAA,CACG,KAAW,OAKV,kBAAC,QAAD;GAAU;GAAK;EAAe,CAAA,IAJ9B,kBAAC,SAAD;GAAW;GAAa;GACrB;EACI,CAAA,GAIR,KAAY,kBAAC,IAAD,CAAmB,CAAA,CAC5B,EAAA,CAAA,GACL,KACC,kBAAC,IAAD;GACE,OAAO;GACP,WAAW,EAAO;GAClB,aAAa,kBAAC,GAAD;IAAU,MAAM;IAAI,eAAA;GAAa,CAAA;GAE9C,OAAO,EAAE,OAAO,UAAU;EAC3B,CAAA,CAEA;;AAET;;;;;;;;;;;;;;;GGlIa,KAAwB,EAAkB;CACrD,WAAW;EACT,IAAI;EACJ,IAAI;EACJ,IAAI;EACJ,IAAI;CACN;CACA,SAAS;EACP,IAAI;EACJ,IAAI;EACJ,IAAI;EACJ,IAAI;CACN;CACA,MAAM;EAAE,IAAI;EAAQ,IAAI;EAAS,IAAI;EAAQ,IAAI;CAAQ;CACzD,OAAO;EAAE,IAAI;EAAQ,IAAI;EAAS,IAAI;EAAS,IAAI;CAAS;CAC5D,OAAO;EAAE,IAAI;EAAO,IAAI;EAAS,IAAI;EAAY,IAAI;CAAS;AAChE,CAAC;;;AChBD,SAAgB,GACd,GACA,GACA;CACA,QAAQ,MAAmC;EACpC,KAEL,OAAO,iBAAiB;GACtB,IAAM,IAAS,SAAS;GACpB,EAAK,MAAM,MAAQ,EAAI,SAAS,SAAS,CAAM,CAAC,KACpD,EAAO,CAAK;EACd,CAAC;CACH;AACF;;;ACgFA,IAAM,MAAQ,GAAG,MACf,EAAM,OAAO,OAAO,CAAC,CAAC,KAAK,GAAG,KAAK,KAAA;AAErC,SAAgB,GAAW,EACzB,UACA,eACA,WAAQ,IACR,YACA,cAAW,IACX,cAAW,IACX,gBACA,WACA,OACA,cAAc,GACd,mBAAmB,GACnB,oBAAoB,GACpB,cACA,UACA,QACA,eACA,eACA,UACA,YAAS,IACT,eAAY,IACZ,aAAU,IACV,uBAAoB,IACpB,aACA,sBACkB;CAClB,IAAM,IAAS,GAAsB,GAC/B,KAAc,EAAM,GACpB,KAAU,KAAM,IAChB,IAAU,EAAM,GAChB,IAAe,EAAM,GACrB,IAAW,KAAS,MACpB,IAAU,GAAa,GAAY,GAAS,CAAK,GACjD,IAAgB,EAAQ,WAAW,MACnC,KAAW,MAAU,KAAA,GAErB,IAAS,EAAuB,IAAI,GACpC,IAAW,EAAuB,IAAI,GACtC,KAAa,GAAe,GAAQ,CAAC,GAAQ,CAAQ,CAAC,GAKtD,CAAC,IAAU,MAAe,EAAS,EAAK,GAIxC,IAAa,EAAO,EAAK,GAEzB,KACJ,kBAAC,EAAS,OAAV;EACE,GAAI;EACC;EACL,IAAI;EACM;EACA;EAGV,aAAa,KAAe;EAC5B,cAAY;EAIZ,mBAAiB,MAAmB,IAAW,IAAU,KAAA;EACzD,gBAAc,KAAS,KAAA;EACvB,oBAAkB,GAAK,KAAiB,GAAc,CAAe;EACrE,WACE,KAAW,EAAO,YAAY,GAAK,EAAY,SAAS,EAAO,OAAO;EAExE,eAAe;GACb,EAAW,UAAU;EACvB;EACA,UAAU,MAAU;GAClB,IAAM,IAAU,EAAM;GAOtB,AALE,KACA,EAAW,WACX,EAAQ,mBAAmB,EAAQ,gBAEnC,EAAQ,OAAO,GACjB,EAAW,UAAU;EACvB;EACA,YAAY,MAAU;GAIpB,AACE,EAAM,QAAQ,YACd,EAAM,cAAc,aAAa,eAAe,MAAM,UAEtD,EAAM,qBAAqB;EAC/B;CACD,CAAA;CAGH,OACE,kBAAC,OAAD;EACE,WAAW,GAAK,EAAY,OAAO,EAAO,OAAO,CAAS;EACnD;EAFT,UAAA;GAIG,EACC,kBAAA,GAAA,EAAA,UAAA,CACE,kBAAC,EAAS,YAAV;IACE,KAAK;IACL,WAAW,GAAK,EAAY,KAAK,EAAO,GAAG;IAC3C,gBAAc,IAAQ,KAAK,KAAA;IAC3B,kBAAgB,IAAW,KAAK,KAAA;IAChC,eAAa,IAAS,KAAK,KAAA;IAC3B,QAAQ;IACR,wBAAwB,GAAY,EAAI;IACxC,4BAA4B,GAAY,EAAK;IAR/C,UAAA,CAUE,kBAAC,OAAD;KAAK,WAAW,GAAK,EAAY,OAAO,EAAO,KAAK;KAApD,UAAA,CACG,KACC,kBAAC,SAAD;MACE,IAAI;MACJ,SAAS;MACT,WAAW,GAAK,EAAY,OAAO,EAAO,KAAK;MAHjD,UAAA,CAKG,GACA,KAAY,kBAAC,IAAD,CAAmB,CAAA,CAC3B;KAER,CAAA,GAAA,KACC,kBAAC,EAAS,OAAV;MAAgB,WAAW,EAAO;MAAlC,UAAA,CACG,GACA,EACa;KAEhB,CAAA,IAAA,EAEC;IACH,CAAA,IAAA,KAAa,MACb,kBAAC,OAAD;KAAK,WAAW,EAAO;KAAvB,UAAA,CACG,KACC,kBAAC,EAAS,OAAV;MACE,WAAW,GAAK,EAAO,QAAQ,EAAO,KAAK;MAC3C,cAAY,EAAO;MAGnB,UAAU;MAEV,UAAA,kBAAC,GAAD,EAAG,eAAA,GAAa,CAAA;KACF,CAAA,GAEjB,KACC,kBAAC,EAAS,SAAV;MACE,WAAW,GAAK,EAAO,QAAQ,EAAO,OAAO;MAC7C,UAAU;MAIV,SAAS,GAAO,MACd,kBAAC,UAAD;OACE,GAAI;OACJ,MAAM,KAAA;OACN,iBAAc;OACd,iBAAe,KAAA;OACf,cAAY,EAAM,OAAO,EAAO,QAAQ,EAAO;MAChD,CAAA;MAGH,UAAA,kBAAC,GAAD,EAAa,eAAA,GAAa,CAAA;KACV,CAAA,CAEjB;IAEY,CAAA,CAAA;GACrB,CAAA,GAAA,kBAAC,EAAS,QAAV,EAAA,UACE,kBAAC,EAAS,YAAV;IACE,QAAQ;IACR,MAAK;IACL,OAAM;IACN,YAAY;IACZ,WAAW,EAAW;IAEtB,UAAA,kBAAC,EAAS,OAAV;KACE,KAAK;KACL,WAAW,GAAK,EAAW,OAAO,EAAO,KAAK;KAC9C,iBAAe,KAAW,KAAK,KAAA;KAC/B,QAAQ;KACR,4BAA4B,GAAY,EAAK;KAE5C;IACa,CAAA;GACG,CAAA,EACN,CAAA,CACjB,EAAA,CAAA,CACJ;GACC,KACC,kBAAC,IAAD;IACE,IAAI;IACG;IACP,SAAS,EAAQ;IAEhB,UAAA,EAAQ;GACM,CAAA;GAElB;EACE;;AAET;;;ACnPA,IAAM,MAAc,GAAiB,MAAoB,EAAE,UAAU,EAAE;AAUvE,SAAS,GAAW,EAAE,kBAAe,YAAS,iBAA+B;CAC3E,IAAM,IAAS,GAAsB;CAErC,OACE,kBAAA,GAAA,EAAA,UAAA,CACE,kBAAC,EAAS,OAAV;EAAgB,WAAW,EAAW;EACnC,UAAA,IAAU,EAAO,UAAW,KAAiB,EAAO;CACvC,CAAA,GAChB,kBAAC,EAAS,MAAV;EAAe,WAAW,EAAW;EACjC,WAAA,MACA,kBAAC,EAAS,MAAV;GAEE,OAAO;GACP,UAAU,EAAO,YAAY,IAAa,CAAM;GAChD,WAAW,EAAW;GAEtB,UAAA,kBAAC,QAAD;IAAM,WAAW,EAAW;IAAW,UAAA,EAAO;GAAY,CAAA;EAC7C,GANR,EAAO,KAMC;CAEJ,CAAA,CACf,EAAA,CAAA;AAEN;AAEA,SAAS,GAAyC,EAChD,YACA,UACA,kBAAe,IACf,kBACA,kBACA,YACA,SACA,GAAG,KAC8B;CACjC,IAAM,IAAe,MAAU,KAAA,GACzB,CAAC,GAAU,KAAe,EAAqB,CAAY,GAC3D,IAAU,IAAe,IAAQ,GAEjC,IAAS,EAAQ,MAAM,MAAW,EAAO,UAAU,CAAO,KAAK;CAErE,OACE,kBAAC,IAAD;EACE,GAAI;EACJ,WAAA;EACA,SAAA;EACA,mBAAA;EACA,aAAa,MACX,kBAAC,EAAS,MAAV;GACE,OAAO;GACP,OAAO;GACP,gBAAgB,MAAS;IACvB,IAAM,IAAY,GAAM,SAAS;IAC7B,MAAc,MACb,KAAc,EAAY,CAAS,GACxC,IAAgB,CAAS;GAC3B;GACA,oBAAoB;GACd;GACN,UAAU,EAAM;GAChB,UAAU,EAAM;GAGhB,sBAAsB;GAErB;EACY,CAAA;EAGjB,UAAA,kBAAC,IAAD;GAA2B;GAAwB;EAAU,CAAA;CACnD,CAAA;AAEhB;AAEA,SAAS,GAA2C,EAClD,YACA,UACA,kBAAe,CAAC,GAChB,kBACA,SAAM,GACN,QACA,kBACA,YACA,SACA,UAAU,GACV,GAAG,KACgC;CACnC,IAAM,IAAa,GAAc,GAC3B,IAAe,MAAU,KAAA,GACzB,CAAC,GAAU,KAAe,EAAkB,CAAY,GACxD,IAAW,IAAe,IAAQ,GAElC,CAAC,GAAO,KAAY,EAAS,EAAE,GAG/B,IAAkB,EACrB,KAAK,MAAS,EAAQ,MAAM,MAAW,EAAO,UAAU,CAAI,CAAC,CAAC,CAC9D,QAAQ,MAAW,MAAW,KAAA,CAAS,GAEpC,IAAQ,MAAQ,KAAA,KAAa,EAAS,UAAU,GAChD,IAAQ,EAAS,UAAU,GAC3B,IAAY,CAAC,EAAM,YAAY,CAAC;CAEtC,OACE,kBAAC,IAAD;EACE,GAAI;EAGJ,WAAW,KAAO;EAClB,SAAA;EACA,QAAQ,EAAgB,SAAS;EACjC,OAAO,EAAgB,KAAK,MAC1B,kBAAC,EAAS,MAAV;GAEE,WAAW,GAAW;GACtB,cAAW;GACX,gBAAa;GACb,aAAU;GALZ,UAAA,CAOE,kBAAC,QAAD;IAAM,WAAW,GAAW;IAAQ,UAAA,EAAO;GAAY,CAAA,GACtD,KACC,kBAAC,EAAS,YAAV;IACE,WAAW,GAAW;IACtB,cAAY,GAAG,EAAW,OAAO,GAAG,EAAO;IAE3C,UAAA,kBAAC,GAAD,EAAS,eAAA,GAAa,CAAA;GACH,CAAA,CAEV;EAfR,GAAA,EAAO,KAeC,CAChB;EACD,aAAa,MACX,kBAAC,EAAS,MAAV;GACE,UAAA;GACA,OAAO;GACP,OAAO;GACP,YAAY;GACZ,oBAAoB;GAKpB,eAAe,GAAM,MAAY;IAC/B,AAAI,CAAC,KAAQ,EAAQ,WAAW,gBAAc,EAAQ,OAAO;GAC/D;GACA,gBAAgB,GAAM,MAAY;IAChC,AAAI,EAAQ,WAAW,gBAAc,EAAS,EAAE;IAChD,IAAM,IAAa,EAAK,KAAK,MAAW,EAAO,KAAK;IAGhD,EAAW,SAAS,KAAO,EAAW,SAAS,EAAS,UAG1D,MAAQ,KAAA,KACR,EAAW,SAAS,KACpB,EAAW,SAAS,EAAS,WAG1B,KAAc,EAAY,CAAU,GACzC,IAAgB,CAAU;GAC5B;GACA,oBAAoB;GACd;GACN,UAAU,EAAM;GAChB,UAAU,EAAM;GAChB,sBAAsB;GAErB;EACY,CAAA;EAGjB,UAAA,kBAAC,IAAD;GACiB;GACN;GACT,aAAa,MAAW;IACtB,IAAM,IAAa,EAAS,SAAS,EAAO,KAAc;IAC1D,OAAQ,KAAS,CAAC,KAAgB,KAAS;GAC7C;EACD,CAAA;CACS,CAAA;AAEhB;AAsCA,SAAgB,GACd,GACA;CACA,OAAO,EAAM,WACX,kBAAC,IAAD,EAAsB,GAAI,EAAQ,CAAA,IAElC,kBAAC,IAAD,EAAoB,GAAI,EAAQ,CAAA;AAEpC;;;;;GErSa,KACX,kBAAC,OAAD;CAAK,WAAW,GAAO;CAAM,SAAQ;CAAY,eAAA;CAC/C,UAAA,kBAAC,QAAD;EACE,GAAE;EACF,MAAK;EACL,QAAO;EACP,aAAa;EACb,eAAc;EACd,gBAAe;EACf,YAAY;CACb,CAAA;AACE,CAAA,GASM,MAAe,EAAE,iBAC5B,kBAAC,QAAD;CACE,WAAW,GAAO;CAClB,gBAAc,IAAU,KAAK,KAAA;CAC7B,eAAA;CAEC,UAAA;AACG,CAAA;;;;GEgCF,MAAQ,GAAG,MACf,EAAM,OAAO,OAAO,CAAC,CAAC,KAAK,GAAG,KAAK,KAAA;AAkBrC,SAAgB,GAAS,EACvB,UACA,eACA,WAAQ,IACR,YACA,mBACA,oBACA,SACA,UACA,cAAW,IACX,cAAW,IACX,OACA,WACA,YACA,cAAc,GACd,mBAAmB,GACnB,oBAAoB,GACpB,cACA,UACA,UACgB;CAChB,IAAM,IAAe,EAAM,GACrB,IAAW,KAAS,MACpB,IAAgB,KAAc,MAC9B,IAAO,CAAC,KAAY,CAAC,GAErB,IACJ,kBAAC,GAAa,MAAd;EAGE,cAAA;EACA,QAAQ,kBAAC,UAAD,EAAQ,MAAK,SAAU,CAAA;EAC3B;EACJ,UAAU;EACD;EACO;EAChB,kBAAkB,MAAS,IAAkB,CAAI;EAC3C;EACC;EACG;EACA;EACF;EACC;EACT,cAAY;EACZ,mBAAiB;EACjB,oBAAkB,GAAK,KAAiB,GAAc,CAAe;EACrE,gBAAc,IAAQ,KAAO,KAAA;EAE7B,WAAW,IAAO,GAAK,GAAO,KAAK,CAAS,IAAI,GAAO;EACvD,OAAO,IAAO,IAAQ,KAAA;EAErB,UAAA;CACgB,CAAA;CAKrB,OAFI,IAAa,IAGf,kBAAC,OAAD;EAAK,WAAW,GAAK,GAAO,UAAU,CAAS;EAAU;EAAzD,UAAA,CACG,IACC,kBAAC,SAAD;GAAO,WAAW,GAAU;GAAK,gBAAc,IAAQ,KAAK,KAAA;GAA5D,UAAA,CACG,GACD,kBAAC,QAAD;IAAM,WAAW,GAAU;IAA3B,UAAA,CACG,GACA,KAAY,kBAAC,IAAD,EAAkB,WAAW,GAAU,SAAW,CAAA,CAC3D;GACD,CAAA,CAAA;EAEP,CAAA,IAAA,GAED,KACC,kBAAC,IAAD;GAAiB,IAAI;GAAqB;GACvC,UAAA;EACc,CAAA,CAEhB;;AAET;;;AChJA,IAAa,WAAmC,EAAE,OAAO,GAAM,IAElD,KAAS,OAA0C;CAC9D,OAAO;CACP;AACF;;;ACbA,SAAS,GAAW,GAAyB;CAC3C,IAAI,IAAM,GACN,IAAS,EAAO,SAAS,KAAM;CAEnC,KAAK,IAAM,KAAQ,GAAQ;EACzB,IAAI,IAAQ,OAAO,CAAI;EAMvB,AALI,MACF,KAAS,GACL,IAAQ,MAAG,KAAS,KAE1B,KAAO,GACP,IAAS,CAAC;CACZ;CAEA,OAAO,IAAM,MAAO;AACtB;AAMA,SAAgB,GAAyB,GAAwB;CAC/D,IAAI,IAAS,EAAM,QAAQ,OAAO,EAAE;CAMpC,IAJI,EAAO,WAAW,OACpB,IAAS,EAAO,MAAM,CAAC,IAGrB,EAAO,WAAW,IACpB,OAAO;CAGT,IAAM,IAAQ,OAAO,EAAO,MAAM,GAAG,CAAC,CAAC,GACjC,IAAM,OAAO,EAAO,MAAM,GAAG,CAAC,CAAC;CAMrC,OAJI,IAAQ,KAAK,IAAQ,MAAM,IAAM,KAAK,IAAM,KACvC,KAGF,GAAW,CAAM;AAC1B;AAEA,IAAM,KAA2B;AAMjC,SAAgB,GAAyB,GAAwB;CAC/D,IAAM,IAAa,EAAM,QAAQ,OAAO,EAAE,CAAC,CAAC,YAAY;CAExD,IAAI,CAAC,6BAA6B,KAAK,CAAU,GAC/C,OAAO;CAGT,IAAM,IAAM,OAAO,EAAW,MAAM,GAAG,CAAC,CAAC,GACnC,IAAQ,OAAO,EAAW,MAAM,GAAG,CAAC,CAAC,GACrC,IAAY,OAAO,EAAW,MAAM,GAAG,CAAC,CAAC,GACzC,IAAc,EAAW,IAEzB,IACJ,MAAgB,MACZ,OACA,MAAgB,MACd,OACA,MAAgB,MACd,MACA;CAEV,IAAI,MAAgB,MAClB,OAAO;CAGT,IAAM,IAAO,IAAc,GACrB,IAAO,IAAI,KAAK,GAAM,IAAQ,GAAG,CAAG;CAE1C,IACE,EAAK,YAAY,MAAM,KACvB,EAAK,SAAS,MAAM,IAAQ,KAC5B,EAAK,QAAQ,MAAM,GAEnB,OAAO;CAGT,IAAM,IAAiB,OACrB,GAAG,EAAW,MAAM,GAAG,CAAC,IAAI,EAAW,MAAM,GAAG,EAAE,GACpD;CAEA,OAAO,EAAW,QAAQ,GAAyB,IAAiB;AACtE;AAEA,IAAM,KAAe;CAAC;CAAG;CAAG;CAAG;CAAG;CAAG;CAAG;CAAG;CAAG;AAAC,GACzC,KAAe;CAAC;CAAG;CAAG;CAAG;CAAG;CAAG;CAAG;CAAG;CAAG;CAAG;AAAC;AAElD,SAAS,GAAsB,GAAkB,GAA2B;CAE1E,IAAM,IADM,EAAQ,QAAQ,GAAK,GAAQ,MAAM,IAAM,IAAS,EAAO,IAAI,CACvD,IAAM;CACxB,OAAO,MAAc,IAAI,IAAI,KAAK;AACpC;AAKA,SAAgB,GAA2B,GAAwB;CACjE,IAAM,IAAS,EAAM,QAAQ,OAAO,EAAE;CAEtC,IAAI,EAAO,WAAW,IACpB,OAAO;CAGT,IAAM,IAAU,EAAO,MAAM,EAAE,CAAC,CAAC,IAAI,MAAM,GACrC,IAAM,OAAO,EAAO,MAAM,GAAG,CAAC,CAAC,GAC/B,IAAQ,OAAO,EAAO,MAAM,GAAG,CAAC,CAAC,GAGjC,IAAU,IAAM,KAAK,IAAM,KAAK,GAChC,IAAY,IAAQ,KAAK,IAAQ,KAAK;CAE5C,IAAI,IAAY,KAAK,IAAY,MAAM,IAAU,KAAK,IAAU,IAC9D,OAAO;CAGT,IAAM,IAAK,GAAsB,EAAQ,MAAM,GAAG,CAAC,GAAG,EAAY;CAClE,IAAI,MAAO,MAAM,MAAO,EAAQ,IAC9B,OAAO;CAGT,IAAM,IAAK,GAAsB,EAAQ,MAAM,GAAG,EAAE,GAAG,EAAY;CAKnE,OAJI,MAAO,MAAM,MAAO,EAAQ;AAKlC;AAEA,IAAM,KAAsB,2BACtB,KAA6C;CAAE,GAAG;CAAK,GAAG;CAAK,GAAG;AAAI;AAM5E,SAAgB,GAAyB,GAAwB;CAC/D,IAAM,IAAa,EAAM,QAAQ,UAAU,EAAE,CAAC,CAAC,YAAY;CAE3D,IAAI,CAAC,uBAAuB,KAAK,CAAU,GACzC,OAAO;CAGT,IAAM,IAAS,EAAW,MAAM,EAAE,GAC9B,IAAa,EAAW,MAAM,GAAG,EAAE,GAEjC,IAAS,EAAW;CAS1B,OARI,KAAU,OACZ,IAAa,GAAmB,KAAU,EAAW,MAAM,CAAC,IAG1D,EAAW,WAAW,KAInB,GAAoB,OAAO,CAAU,IAAI,QAAQ;AAC1D;AAEA,IAAM,KAAsE;CAC1E,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;AACN;AAKA,SAAgB,GAAkB,GAAkB,GAAwB;CAC1E,OAAO,GAAuB,EAAQ,CAAC,CAAK;AAC9C;AAMA,SAAgB,GACd,GACA,GACkB;CAKlB,OAJK,GAAkB,GAAS,CAAK,IAI9B,EAAM,EAAM,QAAQ,UAAU,EAAE,CAAC,CAAC,YAAY,CAAC,IAH7C,EAAQ;AAInB;AASA,IAAa,KAAwD;CACnE,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;AACN,GAIM,KAAS,WAET,KAAsE;CAE1E,KAAK,MAAU,EAAM,QAAQ,OAAO,EAAE;CAGtC,KAAK,MACH,EACG,QAAQ,IAAQ,GAAG,CAAC,CACpB,YAAY,CAAC,CACb,QAAQ,gBAAgB,EAAE;CAC/B,KAAK,MAAU,EAAM,QAAQ,OAAO,EAAE;CACtC,KAAK,MAAU,EAAM,YAAY,CAAC,CAAC,QAAQ,cAAc,EAAE;AAC7D;AAaA,SAAgB,GAAoB,GAAkB,GAAuB;CAC3E,OAAO,GAAwB,EAAQ,CAAC,CAAK;AAC/C;AAOA,SAAgB,GACd,GACA,GACA,GACS;CACT,IAAM,IAAQ,GAAoB,GAAS,KAAK,EAAE,GAC5C,IAAS,GAAoB,GAAS,KAAK,EAAE;CAEnD,OAAO,MAAU,MAAM,MAAU,KAAU,GAAkB,GAAS,CAAK;AAC7E;;;AC7PA,IAAa,KAAkB;CAC7B,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;AACN;;;ACKA,SAAgB,GACd,GACA,GACkB;CAGlB,IAAM,IAAU,EAAM,QAAQ,OAAO,EAAE;CACvC,IAAI,MAAY,IACd,OAAO,EAAQ;CAGjB,IAAM,IAAS,GAA2B,GAAS,CAAO;CAK1D,OAJI,CAAC,KAAU,CAAC,EAAO,QAAQ,IACtB,EAAQ,IAGV,EAAM,EAAO,MAAM;AAC5B;AAKA,SAAgB,GACd,GACA,GACS;CACT,OAAO,GAAoB,GAAS,CAAK,CAAC,CAAC;AAC7C;AAQA,IAAM,KAAiB,OAAO,YAC5B,OAAO,QAAQ,EAAe,CAAC,CAAC,KAAK,CAAC,GAAS,OAAa,CAC1D,GACI,OAAO,OAAO,EAAQ,GAAG,CAC/B,CAAC,CACH;AAMA,SAAgB,GAAgB,GAA2C;CACzE,OAAO,OAAO,UAAU,eAAe,KAAK,IAAiB,CAAO;AACtE;AAaA,SAAgB,GACd,GACA,GACkB;CAClB,IAAM,IAAU,EAAM,QAAQ,OAAO,EAAE;CACvC,IAAI,MAAY,IACd,OAAO,EAAQ;CAGjB,IAAM,IAAS,GAA2B,GAAS,CAAO;CAU1D,OARE,CAAC,KACD,CAAC,EAAO,QAAQ,KAChB,EAAO,YAAY,KACnB,CAAC,GAAe,EAAQ,CAAC,KAAK,EAAO,cAAc,IAE5C,EAAQ,IAGV,EAAM,EAAO,MAAM;AAC5B;AAQA,SAAgB,GACd,GACA,GACA,GACS;CACT,IAAM,IAAQ,GAAoB,GAAS,KAAK,EAAE,GAC5C,IAAS,GAAoB,GAAS,KAAK,EAAE;CAEnD,OAAO,EAAM,SAAS,EAAO,SAAS,EAAM,eAAe,EAAO;AACpE;;;ACnHA,IAAa,MAAY,MAA2B;CAClD,IAAI,IAAY;CAEhB,KAAK,IAAM,KAAS,GAClB,KAAa,IAAY,KAAK,OAAO,CAAK,KAAK;CAGjD,OAAO;AACT,GAEa,MAAkC,MAC7C,EAAM,QAAQ,WAAW,MAAS,OAAO,EAAK,WAAW,CAAC,IAAI,EAAE,CAAC,GCP7D,KAAwC;CAC5C,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;AACN;AAEA,SAAS,GAAU,GAAuB;CACxC,OAAO,EAAM,QAAQ,UAAU,EAAE,CAAC,CAAC,YAAY;AACjD;AAMA,SAAgB,GAAY,GAAe,GAA4B;CACrE,IAAM,IAAO,GAAU,CAAK;CAE5B,IAAI,CAAC,2BAA2B,KAAK,CAAI,GACvC,OAAO;CAGT,IAAM,IAAc,EAAK,MAAM,GAAG,CAAC;CAEnC,IAAI,KAAW,MAAgB,GAC7B,OAAO;CAGT,IAAM,IAAiB,GAAa;CAMpC,OALI,KAAkB,EAAK,WAAW,IAC7B,KAIF,GAAS,GADG,EAAK,MAAM,CAAC,IAAI,EAAK,MAAM,GAAG,CAAC,CACO,CAAC,MAAM;AAClE;AAEA,IAAM,KAAqB;CAAC;CAAG;CAAG;CAAG;CAAG;CAAG;CAAG;CAAG;CAAG;CAAG;AAAC;AAKxD,SAAgB,GAAwB,GAAwB;CAC9D,IAAM,IAAS,EAAM,QAAQ,OAAO,EAAE;CAEtC,IAAI,EAAO,WAAW,IACpB,OAAO;CAGT,IAAM,IAAU,EAAO,MAAM,EAAE,CAAC,CAAC,IAAI,MAAM,GAKrC,IAJM,GAAmB,QAC5B,GAAK,GAAQ,MAAM,IAAM,IAAS,EAAQ,IAC3C,CAEgB,IAAM,IAClB,IAAU,MAAc,IAAI,IAAI,KAAK;CAE3C,OAAO,IAAU,MAAM,MAAY,EAAQ;AAC7C;AAOA,SAAgB,GAAsB,GAAwB;CAC5D,IAAM,IAAS,EAAM,QAAQ,OAAO,EAAE;CACtC,OAAO,EAAO,UAAU,MAAM,EAAO,UAAU;AACjD;AASA,SAAgB,GACd,GACA,GACkB;CAClB,IAAM,IAAa,GAAU,CAAK,GAC5B,IAAgB,iBAAiB,KAAK,CAAU;CAEtD,QAAQ,GAAR;EACE,KAAK;EACL,KAAK,MACH,OAAO,GAAY,GAAY,CAAO,IAAI,EAAM,CAAU,IAAI,EAAQ;EACxE,KAAK,MAIH,OAHI,IACK,GAAY,GAAY,IAAI,IAAI,EAAM,CAAU,IAAI,EAAQ,IAE9D,GAAwB,CAAU,IACrC,EAAM,EAAW,QAAQ,OAAO,EAAE,CAAC,IACnC,EAAQ;EACd,KAAK,MAIH,OAHI,IACK,GAAY,GAAY,IAAI,IAAI,EAAM,CAAU,IAAI,EAAQ,IAE9D,GAAsB,CAAU,IACnC,EAAM,EAAW,QAAQ,OAAO,EAAE,CAAC,IACnC,EAAQ;CAChB;AACF;AAKA,SAAgB,GAAmB,GAAkB,GAAwB;CAC3E,OAAO,GAAoB,GAAS,CAAK,CAAC,CAAC;AAC7C;;;AC/GA,IAAM,MAAa,MACjB,EAAM,QAAQ,OAAO,EAAE,CAAC,CAAC,YAAY;AAGvC,SAAgB,GAAgC,GAAwB;CACtE,IAAM,IAAY,GAAU,CAAK;CACjC,IAAI,CAAC,kBAAkB,KAAK,CAAS,GACnC,OAAO;CAGT,IAAM,IAAO,EAAU,MAAM,GAAG,EAAE,GAC5B,IAAa,OAAO,EAAU,GAAG,EAAE,CAAC,GACpC,IAAU;EAAC;EAAG;EAAG;CAAC,GACpB,IAAM;CAEV,KAAK,IAAI,IAAQ,EAAK,SAAS,GAAG,IAAc,GAAG,KAAS,GAAG,KAE7D,AADA,KAAO,OAAO,EAAK,EAAM,IAAI,EAAQ,IAAc,EAAQ,SAC3D;CAGF,QAAQ,KAAM,IAAM,MAAO,OAAO;AACpC;AAGA,SAAgB,GAA0B,GAAwB;CAChE,IAAM,IAAY,GAAU,CAAK;CAMjC,OALK,yBAAyB,KAAK,CAAS,IAKrC,GAAS,GADM,EAAU,MAAM,CAAC,EAAE,MAAM,EAAU,MAAM,GAAG,CAAC,GACzC,MAAM,IAJvB;AAKX;AAGA,SAAgB,GAAyB,GAAiC;CACxE,IAAM,IAAa,GAAU,CAAK;CAElC,OAAO,GAAgC,CAAU,KAC/C,GAA0B,CAAU,IAClC,EAAM,CAAU,IAChB,EAAQ;AACd;AAGA,SAAgB,GAAwB,GAAwB;CAC9D,OAAO,GAAyB,CAAK,CAAC,CAAC;AACzC;;;AC9CA,IAAM,KACJ,wIAMW,KAA0C;CACrD;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF;AAKA,SAAgB,GAAc,GAAiC;CAC7D,IAAM,IAAU,EAAM,KAAK;CAE3B,IAAI,CAAC,GAAc,KAAK,CAAO,GAC7B,OAAO,EAAQ;CAGjB,IAAM,IAAU,EAAQ,YAAY,GAAG;CAQvC,OAPI,KAAW,KACE,EAAQ,MAAM,IAAU,CAAC,CAAC,CAAC,YACtC,CAAA,CAAO,SAAS,MAAM,IACjB,EAAQ,IAIZ,EAAM,EAAQ,YAAY,CAAC;AACpC;AAKA,SAAgB,GAAa,GAAwB;CACnD,OAAO,GAAc,CAAK,CAAC,CAAC;AAC9B;AAWA,SAAgB,GACd,GACA,IAA6B,IACnB;CACV,IAAM,IAAU,EAAM,QAAQ,GAAG;CAEjC,IAAI,IAAU,GACZ,OAAO,CAAC;CAGV,IAAM,IAAY,EAAM,MAAM,GAAG,CAAO,GAClC,IAAa,EAAM,MAAM,IAAU,CAAC,CAAC,CAAC,YAAY;CAOxD,OAJI,EAAW,SAAS,GAAG,KAAK,EAAQ,SAAS,CAAU,IAClD,CAAC,IAGH,EACJ,QAAQ,MAAW,EAAO,WAAW,CAAU,CAAC,CAAC,CACjD,KAAK,MAAW,GAAG,EAAU,GAAG,GAAQ;AAC7C;AAOA,SAAgB,GACd,GACA,GACS;CACT,IAAM,KAAS,KAAK,GAAA,CAAI,KAAK,CAAC,CAAC,YAAY,GACrC,KAAU,KAAK,GAAA,CAAI,KAAK,CAAC,CAAC,YAAY;CAE5C,OAAO,MAAU,MAAM,MAAU;AACnC;AAUA,IAAM,KAAkB;CACtB;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF,GAKM,KAAoB,6JAwC1B;AAGA,SAAS,GAAa,GAAW,GAAmB;CAClD,IAAM,IAAI,MAAM,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAE,IAAI,GAAG,MACjD,MAAM,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAE,IAAI,GAAG,MACvC,MAAM,IAAI,IAAI,MAAM,IAAI,IAAI,CAC9B,CACF;CACA,KAAK,IAAI,IAAI,GAAG,KAAK,EAAE,QAAQ,KAC7B,KAAK,IAAI,IAAI,GAAG,KAAK,EAAE,QAAQ,KAAK;EAClC,IAAM,IAAO,EAAE,IAAI,OAAO,EAAE,IAAI,KAAK,IAAI;EAMzC,AALA,EAAE,EAAE,CAAC,KAAK,KAAK,IACb,EAAE,IAAI,EAAE,CAAC,KAAK,GACd,EAAE,EAAE,CAAC,IAAI,KAAK,GACd,EAAE,IAAI,EAAE,CAAC,IAAI,KAAK,CACpB,GACI,IAAI,KAAK,IAAI,KAAK,EAAE,IAAI,OAAO,EAAE,IAAI,MAAM,EAAE,IAAI,OAAO,EAAE,IAAI,OAChE,EAAE,EAAE,CAAC,KAAK,KAAK,IAAI,EAAE,EAAE,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,IAAI,KAAK,CAAC;CAEnD;CAEF,OAAO,EAAE,EAAE,OAAO,CAAC,EAAE;AACvB;AAGA,SAAS,GACP,GACA,GACA,GACoB;CACpB,IAAI,GACA,IAAe,IAAQ,GACvB,IAAM;CACV,KAAK,IAAM,KAAa,GAAY;EAClC,IAAM,IAAW,GAAa,GAAO,CAAS;EAC9C,AAAI,IAAW,IACb,CAAC,GAAM,GAAc,KAAO;GAAC;GAAW;GAAU;EAAK,IAC9C,MAAa,KAAgB,MAAc,MACpD,IAAM;CAEV;CACA,OAAO,IAAM,KAAA,IAAY;AAC3B;AAaA,SAAgB,GACd,GACA,IAA6B,IACT;CACpB,IAAM,IAAU,EAAM,KAAK,GACrB,IAAK,EAAQ,YAAY,GAAG;CAClC,IAAI,IAAK,GAAG;CAEZ,IAAM,IAAQ,EAAQ,MAAM,GAAG,CAAE,GAC3B,IAAS,EACZ,MAAM,IAAK,CAAC,CAAC,CACb,YAAY,CAAC,CACb,QAAQ,QAAQ,EAAE;CACrB,IAAI,CAAC,8BAA8B,KAAK,CAAM,GAAG;CAEjD,IAAM,IAAQ,CAAC,GAAG,GAAS,GAAG,EAAe;CAC7C,IAAI,EAAM,SAAS,CAAM,GAAG;CAE5B,IAAM,KAAW,MACf,KAAS,MAAU,KAAU,CAAC,GAAgB,SAAS,CAAK,IACxD,GAAG,EAAM,GAAG,MACZ,KAAA,GACA,KAAU,MAAkB,EAAM,MAAM,GAAG,EAAM,QAAQ,GAAG,CAAC,GAC7D,KAAS,MAAkB,EAAM,MAAM,EAAM,QAAQ,GAAG,IAAI,CAAC,GAE7D,IAAM,EAAO,QAAQ,GAAG;CAG9B,IAAI,IAAM,GAAG;EAEX,IAAM,IAAO,GAAQ,GAAQ,CADd,GAAG,IAAI,IAAI,EAAQ,IAAI,CAAM,CAAC,CAChB,GAAO,EAAO,UAAU,IAAI,IAAI,CAAC;EAC9D,OAAO,EAAQ,EAAQ,MAAM,MAAU,EAAO,CAAK,MAAM,CAAI,CAAC;CAChE;CAEA,IAAM,IAAO,EAAO,MAAM,GAAG,CAAG,GAC1B,IAAM,EAAO,MAAM,IAAM,CAAC;CAKhC,IAAI,GAAkB,SAAS,CAAG,GAEhC,OAAO,EAAQ,GAAQ,GADP,EAAM,QAAQ,MAAU,EAAM,CAAK,MAAM,CAC1B,GAAS,CAAC,CAAC;CAM5C,IAAM,IAAO,GAAQ,GAAQ,GAAO,EAAO,UAAU,IAAI,IAAI,CAAC;CAC9D,IAAI,GAAM,OAAO,EAAQ,CAAI;CAE7B,IAAM,IAAW,GAAQ,GAAK,IAAmB,CAAC;CAClD,OAAO,IAAW,EAAQ,GAAG,EAAK,GAAG,GAAU,IAAI,KAAA;AACrD;;;;AElQA,SAAgB,GAAK,EACnB,WAAQ,aACR,WACA,QACA,cACA,GAAG,KACS;CACZ,OAAO,EAAU;EACf;EACA;EACA,gBAAgB;EAChB,OAAO;GACL,GAAG;GACH,cAAc;GACd,WAAW,EAAe,GAAO,MAAM,CAAS,CAAC,CAAC,CAAC,CAAC;EACtD;CACF,CAAC;AACH;;;;;;;;;IEdM,KAAc,EAAuC,IAAI,GAEzD,WAAuB;CAC3B,IAAM,IAAU,EAAW,EAAW;CACtC,IAAI,CAAC,GACH,MAAU,MAAM,4CAA4C;CAE9D,OAAO;AACT,GAEM,MAAkB,GAAG,MACzB,EAAM,OAAO,OAAO,CAAC,CAAC,KAAK,GAAG,GAenB,MAAQ,EACnB,aAAU,MACV,SAAM,KACN,cACA,UACA,aACA,GAAG,QACY;CACf,IAAM,IAAU;CAEhB,OACE,kBAAC,GAAY,UAAb;EAAsB,OAAO,EAAE,WAAQ;EACrC,UAAA,kBAAC,GAAD;GACE,GAAI;GACJ,WAAW,GAAe,GAAO,MAAM,CAAS;GAChD,OAAO;IAAE,UAAU;IAAK,GAAG;GAAM;GAEhC;EACM,CAAA;CACW,CAAA;AAE1B,GAaa,MAAQ,EACnB,SACA,SAAM,KACN,cACA,UACA,aACA,GAAG,QACY;CACf,IAAM,EAAE,eAAY,GAAe,GAC7B,IAAS,IAAO,SAAS,MAAY,OAAO,WAAW;CAE7D,OACE,kBAAC,MAAD;EACE,GAAI;EACJ,WAAW,GAAe,GAAO,MAAM,CAAS;EAChD,OAAO;GAAE,UAAU,IAAO,IAAM;GAAG,GAAG;EAAM;EAH9C,UAAA,CAKE,kBAAC,QAAD;GAAM,WAAW,GAAO;GAAQ,eAAa;GAC1C,UAAA;EACG,CAAA,GACN,kBAAC,OAAD;GAAK,WAAW,GAAO;GACpB,UAAA,OAAO,KAAa,WAAW,kBAAC,IAAD,EAAO,YAAe,CAAA,IAAI;EACvD,CAAA,CACH;;AAER;;;AE7EA,SAAgB,GAAW,EACzB,UACA,kBAAe,IACf,kBACA,aAAU,IACV,oBAAiB,GACjB,kBAAe,SACf,uBAAoB,IACpB,SACA,WACA,QACA,GAAG,KACe;CAClB,IAAM,IAAS,GAAoB,GAC7B,IAAe,MAAU,KAAA,GACzB,CAAC,GAAU,KAAe,EAAS,CAAY,GAC/C,IAAU,IAAe,IAAQ,GAEjC,IAAW,EAAgC,IAAI,GAC/C,KAAY,MAAqC;EAErD,IADA,EAAS,UAAU,GACf,OAAO,KAAQ,YAAY,OAAO,EAAI,CAAO;EACjD,AAAI,MAAK,EAAI,UAAU;CACzB,GAIM,CAAC,GAAY,KAAiB,EAAiB,GAC/C,IACJ,KAAqB,CAAC,EAAM,WAAW,IAAa,KAAA,GAEhD,KAAU,MAAiB;EAG/B,AAFK,KAAc,EAAY,CAAI,GACnC,EAAc,KAAA,CAAS,GACvB,IAAgB,CAAI;CACtB,GAEM,UAAyB;EACzB,KAAc,SAClB,EAAO,CAAU,GAEjB,EAAS,SAAS,MAAM;CAC1B,GAIM,CAAC,GAAM,KAAW,EAAS,EAAK,GAEhC,IAAc,QACZ,GAA0B,GAAS,CAAO,CAAC,CAAC,MAAM,GAAG,CAAc,GACzE;EAAC;EAAS;EAAS;CAAc,CACnC;CAEA,OACE,kBAAC,IAAD;EACE,GAAI;EACJ,KAAK;EACL,SAAS,MAAU;GAGjB,AAFI,KACF,EAAc,GAAuB,GAAS,CAAO,CAAC,GACxD,IAAS,CAAK;EAChB;EACA,iBACE,KACE,kBAAC,OAAD;GAAK,MAAK;GAAS,WAAW,GAAO;GAClC,UAAA,KAAmB,QAClB,kBAAC,KAAD,EAAA,UAAA;IACG,EAAO;IAAY;IACpB,kBAAC,IAAD;KACE,QAAQ,kBAAC,UAAD,EAAQ,MAAK,SAAU,CAAA;KAC/B,OAAM;KACN,cAAY,GAAG,EAAO,IAAI,GAAG;KAC7B,SAAS;KAER,UAAA;IACG,CAAA;IAAC;GAEN,EAAA,CAAA;EAEF,CAAA;EAGT,WAAA;EACA,YAAY;GACV,MAAM;GACN;GACA;GACA,gBAAgB;GAChB,YAAY;EACd;EACA,aAAa,MACX,kBAAC,GAAiB,MAAlB;GACE,OAAO;GAEP,QAAQ;GACR,MAAM,KAAQ,EAAY,SAAS;GACnC,cAAc;GACd,OAAO;GACP,eAAe;GACf,UAAU,EAAM;GAChB,UAAU,EAAM;GAChB,sBAAsB;GAErB;EACoB,CAAA;EAGzB,UAAA,kBAAC,GAAiB,MAAlB;GAAuB,WAAW,EAAW;GACzC,WAAA,MACA,kBAAC,GAAiB,MAAlB;IAEE,OAAO;IACP,WAAW,EAAW;IAEtB,UAAA,kBAAC,QAAD;KAAM,WAAW,EAAW;KAAW,UAAA;IAAiB,CAAA;GACnC,GALhB,CAKgB;EAEJ,CAAA;CACb,CAAA;AAEhB;AAEA,IAAM,KAAsB,EAAkB;CAC5C,YAAY;EACV,IAAI;EACJ,IAAI;EACJ,IAAI;EACJ,IAAI;CACN;CACA,KAAK;EACH,IAAI;EACJ,IAAI;EACJ,IAAI;EACJ,IAAI;CACN;AACF,CAAC,GCpHK,MAAQ,GAAG,MACf,EAAM,OAAO,OAAO,CAAC,CAAC,KAAK,GAAG,KAAK,KAAA,GAG/B,KACJ,OAAO,WAAa,MAAc,IAAY;AAOhD,SAAS,GAAY,GAAkB,GAAkB;CACvD,IAAM,IAAa,EAA2B,IAAI,GAE5C,UAAe;EACnB,IAAM,IAAU,EAAW;EAC3B,IAAI,CAAC,GAAS;EAGd,EAAQ,MAAM,SAAS;EACvB,IAAM,IAAW,iBAAiB,CAAO,GACnC,IACJ,KAAW,OAIP,WAHA,WAAW,EAAS,UAAU,IAAI,IAClC,WAAW,EAAS,UAAU,IAC9B,WAAW,EAAS,aAAa,GAEjC,IAAU,EAAQ;EAExB,AADA,EAAQ,MAAM,SAAS,GAAG,KAAK,IAAI,GAAS,CAAG,EAAE,KACjD,EAAQ,MAAM,YAAY,IAAU,IAAM,SAAS;CACrD;CAsBA,OApBA,SAAyB;EACvB,AAAI,KAAS,EAAO;CACtB,CAAC,GAED,QAAgB;EACd,IAAM,IAAU,EAAW;EAC3B,IAAI,CAAC,KAAW,CAAC,GAAS;EAE1B,EAAQ,iBAAiB,SAAS,CAAM;EAExC,IAAM,IACJ,OAAO,iBAAmB,MAAc,OAAO,IAAI,eAAe,CAAM;EAE1E,OADA,GAAU,QAAQ,CAAO,SACZ;GAEX,AADA,EAAQ,oBAAoB,SAAS,CAAM,GAC3C,GAAU,WAAW;EACvB;CAEF,GAAG,CAAC,GAAS,CAAO,CAAC,GAEd;AACT;AAoBA,SAAgB,GAAM,EACpB,UACA,eACA,WAAQ,IACR,YACA,UACA,iBACA,kBACA,mBACA,iBACA,eAAY,IACZ,SACA,YACA,YACA,cACA,UACA,QACA,OACA,cAAW,IACX,cAAW,IACX,gBACA,oBAAoB,GACpB,GAAG,KACU;CACb,IAAM,IAAc,EAAM,GACpB,IAAU,KAAM,GAChB,IAAe,EAAM,GACrB,IAAW,KAAS,MACpB,IAAU,GAAa,GAAY,GAAS,CAAK,GACjD,IAAgB,EAAQ,WAAW,MAInC,KAAc,GADH,KAAa,KAAQ,MACI,CAAO,GAE3C,KAAc,MAAqC;EAEvD,IADA,GAAY,UAAU,GAClB,OAAO,KAAQ,YAAY,OAAO,EAAI,CAAO;EACjD,AAAI,MAAK,EAAI,UAAU;CACzB;CAYA,OACE,kBAAC,OAAD;EAAK,WAAW,GAAK,EAAO,OAAO,CAAS;EAAU;EAAtD,UAAA,CACE,kBAAC,OAAD;GACE,WAAW,EAAO;GAClB,gBAAc,IAAQ,KAAK,KAAA;GAC3B,iBAAe,IAAW,KAAK,KAAA;GAC/B,kBAAgB,IAAW,KAAK,KAAA;GAChC,UAdgB,MAAsC;IAC3C,EAAM,OACV,QAAQ,gDAAgD,KAEnE,EAAM,cAAc,cAA2B,iBAAiB,CAAC,EAAE,MAAM;GAC3E;GAII,UAAA;IAOG,KAAkB,QACjB,kBAAC,QAAD;KAAM,WAAW,EAAO;KAAW,iBAAc;KAC9C,UAAA;IACG,CAAA;IAER,kBAAC,OAAD;KAAK,WAAW,EAAO;KAAvB,UAAA,CACG,KACC,kBAAC,SAAD;MAAO,SAAS;MAAS,WAAW,EAAO;MAA3C,UAAA,CACG,GACA,KAAY,kBAAC,IAAD,CAAmB,CAAA,CAC3B;KAET,CAAA,GAAA,kBAAC,IAAD;MACE,GAAI;MACJ,KAAK;MACL,IAAI;MACG;MACO;MACd,gBAAgB,MAAS,IAAgB,CAAI;MACnC;MACA;MAGV,aAAa,KAAe;MAC5B,gBAAc;MACd,oBAAkB,GAChB,KAAiB,GACjB,CACF;MACA,WAAW,EAAO;MAClB,QACE,IAAY,kBAAC,YAAD,EAAU,MAAM,KAAQ,KAAW,EAAI,CAAA,IAAI,KAAA;KAE1D,CAAA,CACE;;IACJ,KAAgB,QACf,kBAAC,QAAD;KAAM,WAAW,EAAO;KAAW,iBAAc;KAC9C,UAAA;IACG,CAAA;GAEL;EACJ,CAAA,GAAA,KACC,kBAAC,IAAD;GACE,IAAI;GACG;GACP,SAAS,EAAQ;GAEhB,UAAA,EAAQ;EACM,CAAA,CAEhB;;AAET;;;;;;;;;;;;;;;GExJM,MAAQ,GAAG,MACf,EAAM,OAAO,OAAO,CAAC,CAAC,KAAK,GAAG,KAAK,KAAA;AAcrC,SAAS,GAAkB,EACzB,SACA,iBACA,GAAG,KACsB;CAKzB,OAJA,QAAgB;EACd,EAAa,MAAS,QAAQ,QAAQ,QAAQ;CAChD,GAAG,CAAC,GAAM,CAAY,CAAC,GAEhB,kBAAC,OAAD,EAAK,GAAI,EAAQ,CAAA;AAC1B;AAEA,SAAgB,GAAY,EAC1B,UACA,eACA,WAAQ,IACR,cAAW,IACX,cAAW,IACX,gBACA,mBACA,iBACA,MAAM,GACN,iBACA,WACA,SACA,OACA,cAAc,GACd,mBAAmB,GACnB,oBAAoB,GACpB,cACA,UACA,QACA,aACA,UACA,kBACA,WACA,YACA,mBAAgB,IAChB,eACA,eACmB;CACnB,IAAM,IAAc,EAAM,GACpB,KAAY,KAAM,GAClB,IAAU,EAAM,GAChB,IAAe,EAAM,GACrB,IAAW,KAAS,MACpB,IAAgB,KAAc,MAE9B,CAAC,GAAc,MAAmB,EAAS,EAAK,GAChD,IAAO,KAAY,GACnB,CAAC,GAAM,KAAW,EAAe,QAAQ,GAEzC,KAAS,EAAuB,IAAI,GACpC,KAAW,EAAuB,IAAI,GAItC,KAAa,GAAe,GAAQ,CAAC,IAAQ,EAAQ,CAAC;CAE5D,OACE,kBAAC,OAAD;EACE,WAAW,GAAK,EAAY,OAAO,EAAO,OAAO,CAAS;EACnD;EAFT,UAAA,CAIE,kBAAC,EAAW,MAAZ;GACE,IAAI;GACE;GACI;GACH;GACQ;GACT;GACN,eAAe,MAAS;IAEtB,AADI,MAAa,KAAA,KAAW,GAAgB,CAAI,GAChD,IAAe,CAAI;GACrB;GACU;GACA;GAGV,sBAAsB;GAfxB,UAAA,CAiBE,kBAAC,OAAD;IACE,KAAK;IACL,WAAW,GAAK,EAAY,KAAK,EAAO,GAAG;IAC3C,gBAAc,IAAQ,KAAK,KAAA;IAC3B,iBAAe,IAAW,KAAK,KAAA;IAC/B,kBAAgB,IAAW,KAAK,KAAA;IAChC,wBAAsB,IAAc,KAAK,KAAA;IACzC,eAAa,IAAS,KAAK,KAAA;IAC3B,aAAW,IAAO,KAAK,KAAA;IACvB,mBAAiB,IAAO,IAAO,KAAA;IAC/B,QAAQ;IAVV,UAAA;KAYE,kBAAC,EAAW,SAAZ;MAEO;MACL,cAAc;MACd,QAAQ,kBAAC,OAAD,CAAM,CAAA;MACd,cAAY;MACZ,mBAAiB,MAAmB,IAAW,IAAU,KAAA;MACzD,oBAAkB,GAChB,KAAiB,GACjB,CACF;MACA,gBAAc,KAAS,KAAA;MACvB,iBAAe,KAAY,KAAA;MAC3B,WAAW,EAAO;MAElB,UAAA,kBAAC,QAAD;OAAM,WAAW,EAAO;OAAS,UAAA;MAAgB,CAAA;KAC/B,CAAA;KACnB,KAAkB,QACjB,kBAAC,QAAD;MAAM,WAAW,EAAY;MAAW,iBAAc;MACnD,UAAA;KACG,CAAA;KAER,kBAAC,OAAD;MAAK,WAAW,GAAK,EAAY,OAAO,EAAO,KAAK;MAApD,UAAA,CACG,KACC,kBAAC,QAAD;OAAM,IAAI;OAAS,WAAW,EAAO;OAArC,UAAA,CACG,GACA,KAAY,kBAAC,IAAD,CAAmB,CAAA,CAC5B;MAER,CAAA,GAAA,kBAAC,OAAD;OACE,WAAW,EAAO;OAClB,eAAa,KAAiB,KAAA;OAE7B,UAAA,IACG,IACA,KACE,kBAAC,QAAD;QAAM,WAAW,EAAO;QAAa,eAAA;QAClC,UAAA;OACG,CAAA;MAET,CAAA,CACF;;KACJ,KAAgB,QACf,kBAAC,QAAD;MAAM,WAAW,EAAO;MAAe,UAAA;KAAmB,CAAA;KAE5D,kBAAC,GAAD;MAAa,WAAW,EAAO;MAAM,eAAA;KAAa,CAAA;IAC/C;GACL,CAAA,GAAA,kBAAC,EAAW,QAAZ,EAAA,UACE,kBAAC,EAAW,YAAZ;IACE,MAAK;IACL,OAAM;IACN,YAAY;IACZ,sBAAsB;IACtB,WAAW,EAAW;IACtB,SAAS,GAAO,MACd,kBAAC,IAAD;KACE,GAAI;KACJ,MAAM,EAAM;KACZ,cAAc;IACf,CAAA;IAGH,UAAA,kBAAC,EAAW,OAAZ;KACE,KAAK;KACL,WAAW,EAAW;KACtB,QAAQ;KAER,UAAA,kBAAC,EAAW,MAAZ;MAAiB,WAAW,EAAW;MACpC;KACc,CAAA;IACD,CAAA;GACG,CAAA,EACN,CAAA,CACJ;EAChB,CAAA,GAAA,KACC,kBAAC,IAAD;GAAiB,IAAI;GAAqB;GACvC,UAAA;EACc,CAAA,CAEhB;;AAET;AAUA,SAAgB,GAAgB,EAC9B,WACA,aACA,eACuB;CACvB,OACE,kBAAC,EAAW,MAAZ;EACE,OAAO,EAAO;EACd,OAAO,EAAO;EACd,UAAU,KAAY,EAAO;EAC7B,WAAW,EAAW;EAJxB,UAAA,CAMG,GACD,kBAAC,EAAW,UAAZ;GAAqB,WAAW,EAAW;GACxC,UAAA,EAAO;EACW,CAAA,CACN;;AAErB;;;ACrSA,IAAM,KAAW,GAGX,KACJ,OAAO,WAAa,MAAc,IAAY;AAQhD,SAAS,GAAc,EAAE,UAAO,cAAW,eAAgC;CACzE,IAAM,IAAe,EAAuB,IAAI,GAC1C,IAAa,EAAuB,IAAI,GACxC,CAAC,GAAc,KAAmB,EAAS,EAAM,MAAM,GAEvD,IAAY,QAAkB;EAClC,IAAM,IAAY,EAAa,SACzB,IAAU,EAAW;EAC3B,IAAI,CAAC,KAAa,CAAC,GAAS;EAE5B,IAAM,IAAY,EAAU,aAEtB,IAAW,MAAM,KAAK,EAAQ,QAAQ,GACtC,IAAU,EAAS,EAAS,SAAS,IACrC,IAAU,EAAS,MAAM,GAAG,EAAE,GAC9B,IAAa,IAAU,EAAQ,cAAc,KAAW;EAM9D,IAJc,EAAQ,QACnB,GAAK,GAAI,MAAU,IAAM,EAAG,eAAe,IAAQ,IAAI,KAAW,IACnE,CAEE,KAAS,GAAW;GACtB,EAAgB,EAAM,MAAM;GAC5B;EACF;EAEA,IAAI,IAAO,GACP,IAAQ;EACZ,KAAK,IAAI,IAAI,GAAG,IAAI,EAAQ,QAAQ,KAAK;GACvC,IAAM,IAAO,EAAQ,EAAE,CAAC,eAAe,IAAI,IAAI,KAAW;GAC1D,IAAI,IAAO,IAAO,KAAc,GAE9B,AADA,KAAQ,GACR,KAAS;QAET;EAEJ;EACA,EAAgB,CAAK;CACvB,GAAG,CAAC,EAAM,MAAM,CAAC;CASjB,AALA,SAAyB;EACvB,EAAU;CAEZ,GAAG;EAAC;EALa,EAAM,KAAK,MAAS,EAAK,KAAK,CAAC,CAAC,KAAK,GAKvC;EAAU;CAAS,CAAC,GAEnC,QAAgB;EACd,IAAM,IAAY,EAAa;EAC/B,IAAI,CAAC,KAAa,OAAO,iBAAmB,KAAa;EACzD,IAAM,IAAW,IAAI,qBAAqB,EAAU,CAAC;EAErD,OADA,EAAS,QAAQ,CAAS,SACb,EAAS,WAAW;CACnC,GAAG,CAAC,CAAS,CAAC;CAEd,IAAM,IAAc,KAAK,IAAI,EAAM,SAAS,GAAc,CAAC,GAErD,KAAc,MAClB,kBAAC,IAAD;EAEE,MAAK;EACL,OAAO,EAAK;EACZ,OAAO;GAAE,YAAY;GAAG,UAAU;EAAO;EACzC,UAAU,UAAkB,EAAS,EAAK,KAAK,IAAI,KAAA;CACpD,GALM,EAAK,KAKX,GAGG,KAAS,MACb,kBAAC,IAAD;EACE,OAAM;EACN,MAAK;EACL,OAAO,IAAI;EACX,OAAO,EAAE,YAAY,EAAE;CACxB,CAAA;CAGH,OACE,kBAAC,OAAD;EAAK,WAAW,EAAO;EAAvB,UAAA,CAEE,kBAAC,OAAD;GAAK,KAAK;GAAY,eAAA;GAAY,WAAW,EAAO;GAApD,UAAA,CACG,EAAM,KAAK,MAAS,EAAW,CAAI,CAAC,GACpC,EAAM,EAAM,MAAM,CAChB;EAEL,CAAA,GAAA,kBAAC,OAAD;GAAK,KAAK;GAAc,WAAW,EAAO;GAA1C,UAAA,CACG,EAAM,MAAM,GAAG,CAAY,CAAC,CAAC,KAAK,MAAS,EAAW,CAAI,CAAC,GAC3D,IAAc,KAAK,EAAM,CAAW,CAClC;EACF,CAAA,CAAA;;AAET;AA+BA,SAAgB,GAA2C,EACzD,YACA,UACA,kBAAe,CAAC,GAChB,kBACA,gBACA,SAAM,GACN,QACA,cAAW,IACX,QACA,GAAG,KACuB;CAC1B,IAAM,IAAe,MAAU,KAAA,GACzB,CAAC,GAAU,KAAe,EAAkB,CAAY,GACxD,IAAW,IAAe,IAAQ,GAElC,IAAa,EAA2B,IAAI,GAC5C,KAAgC,MAAY;EAEhD,IADA,EAAW,UAAU,GACjB,OAAO,KAAQ,YAAY,OAAO,EAAI,CAAO;EACjD,AAAI,MAAK,EAAI,UAAU;CACzB,GAEM,IAAQ,MAAQ,KAAA,KAAa,EAAS,UAAU,GAChD,IAAQ,EAAS,UAAU,GAE3B,KAAU,MAAkB;EAEhC,AADK,KAAc,EAAY,CAAI,GACnC,IAAgB,CAAI;CACtB,GAEM,KAAgB,MAAkB;EAErB,EAAK,SAAS,EAAS,UACxB,MAAQ,KAAA,KAAa,EAAK,SAAS,KAChC,EAAK,SAAS,EAAS,UACxB,EAAK,SAAS,KAEhC,EAAO,CAAI;CACb,GAEM,KAAgB,MAA0B;EAC1C,EAAS,UAAU,MACvB,EAAO,EAAS,QAAQ,MAAM,MAAM,CAAa,CAAC,GAElD,EAAW,SAAS,MAAM;CAC5B,GAEM,IAAY,CAAC,KAAY,EAAS,SAAS,GAG3C,IAAkB,EAAS,KAC9B,MACC,EAAQ,MAAM,MAAW,EAAO,UAAU,CAAC,KAAK;EAAE,OAAO;EAAG,OAAO;CAAE,CACzE;CAEA,OACE,kBAAC,IAAD;EACE,GAAI;EACJ,KAAK;EACK;EACV,UAAA;EACA,OAAO;EACP,gBAAgB,MAAS,EAAc,KAAQ,CAAC,CAAa;EAC7D,QAAQ,EAAS,SAAS;EAC1B,SACE,IACE,EAAY,CAAQ,IAEpB,kBAAC,IAAD;GACE,OAAO;GACI;GACX,UAAU;EACX,CAAA;EAGL,WAAW,EAAgB,KAAK,MAAW,EAAO,KAAK,CAAC,CAAC,KAAK,IAAI;EAEjE,UAAA,EAAQ,KAAK,MAAW;GACvB,IAAM,IAAa,EAAS,SAAS,EAAO,KAAK;GAEjD,OACE,kBAAC,IAAD;IAEU;IACR,UALa,KAAS,CAAC,KAAgB,KAAS,KAK3B,EAAO;IAG5B,UAAA,kBAAC,IAAD,EAAa,SAAS,EAAa,CAAA;GACpB,GANV,EAAO,KAMG;EAErB,CAAC;CACU,CAAA;AAEjB;;;ACtPA,IAAa,KAA4C;CACvD,IAAI;EAAE,SAAS;EAAM,QAAQ;EAAS,UAAU;CAAM;CACtD,IAAI;EAAE,SAAS;EAAM,QAAQ;EAAS,UAAU;CAAM;CACtD,IAAI;EAAE,SAAS;EAAM,QAAQ;EAAS,UAAU;CAAM;CACtD,IAAI;EAAE,SAAS;EAAM,QAAQ;EAAS,UAAU;CAAM;AACxD,GCUM,KAAiD;CACrD,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;AACN;AAGA,SAAgB,GAAW,GAAoD;CAC7E,OACE,OAAO,KAAS,cAChB,KACA,CAAC,EAAe,CAAI,KACpB,UAAU,MACT,EAAK,SAAS,WAAW,EAAK,SAAS;AAE5C;AAMA,SAAgB,GACd,GACA,GACA,GACQ;CACR,IAAM,EAAE,WAAQ,UAAU,MACxB,GAAU,GAAoB,KAE1B,IACJ,EAAK,SAAS,UACV;EAAE,OAAO;EAAQ,MAAM;EAAQ,aAAa;CAAO,IACnD;EACE,OAAO;EACP,UAAU,EAAK,YAAY;EAC3B,iBAAiB;CACnB;CAQN,OAJa,IAAI,KAAK,aAAa,GAAQ,CAAO,CAAC,CAChD,cAAc,EAAK,SAAS,UAAW,KAAS,IAAK,CAAC,CAAC,CACvD,MAAM,MAAM,EAAE,UAAU,EAAK,SAAS,UAAU,SAAS,WAErD,CAAA,EAAM,SAAS;AACxB;;;;;;GEkBM,MAAQ,GAAG,MACf,EAAM,OAAO,OAAO,CAAC,CAAC,KAAK,GAAG,KAAK,KAAA;AAsBrC,SAAgB,GAAY,EAC1B,UACA,oBAAiB,UACjB,YACA,eACA,WAAQ,IACR,YACA,cAAW,IACX,cAAW,IACX,OACA,gBACA,cACA,SACA,kBAAe,IACf,cACA,UACA,QACA,UACA,iBACA,kBACA,GAAG,KACgB;CACnB,IAAM,IAAW,GAAY,GAEvB,CAAC,GAAY,KAAiB,EAAS,KAAgB,IAAI,GAC3D,IAAe,MAAU,KAAA,IAAoB,IAAR,GACrC,IAAc,GAAW,CAAI,IAC/B,GAAW,GAAM,GAAU,CAAY,IACvC,GACE,KAAc,EAAM,GACpB,IAAU,KAAM,IAChB,IAAU,EAAM,GAChB,KAAe,EAAM,GACrB,IAAS,EAAM,GACf,IAAgB,GAAiB,GAEjC,IAAW,KAAS,MACpB,IAAe,KAAY,MAAmB,WAC9C,IAAU,GAAa,GAAY,GAAS,CAAK,GACjD,KAAgB,EAAQ,WAAW,MAInC,IAAc,GAClB,MAAiB,IACjB,KAAe,QAAQ,MAAgB,MAAM,CAC/C,GAIM,KAAc,MAAsC;EACzC,EAAM,OACV,QAAQ,8BAA8B,KACjD,EAAM,cAAc,cAAc,OAAO,CAAC,EAAE,MAAM;CACpD;CAEA,OACE,kBAAC,EAAgB,MAAjB;EACE,GAAI;EACG;EACO;EACd,gBAAgB,GAAM,MAAY;GAEhC,AADA,EAAc,CAAI,GAClB,IAAgB,GAAM,CAAO;EAC/B;EACA,IAAI;EACM;EACA;EACV,WAAW,GAAK,EAAY,OAAO,CAAS;EACrC;EAZT,UAAA;GAcG,KACC,kBAAC,IAAD;IACE,IAAI;IACJ,SAAS;IACA;IACC;IACH;IACG;IAET,UAAA;GACc,CAAA;GAEnB,kBAAC,OAAD;IACE,WAAW,GAAK,EAAY,KAAK,GAAO,GAAG;IAC3C,gBAAc,IAAQ,KAAK,KAAA;IAC3B,iBAAe,IAAW,KAAK,KAAA;IAC/B,kBAAgB,KAAY,CAAC,IAAe,KAAK,KAAA;IACjD,sBAAoB,IAAe,KAAK,KAAA;IACxC,SAAS;IANX,UAAA;KAQG,KAAa,QACZ,kBAAC,QAAD;MACE,WAAW,EAAY;MACvB,iBAAc;MACd,eAAA;MAEC,UAAA;KACG,CAAA;KAER,kBAAC,OAAD;MAAK,WAAW,EAAY;MAA5B,UAAA,CACG,KAAY,CAAC,KACZ,kBAAC,SAAD;OAAO,SAAS;OAAS,WAAW,EAAY;OAAhD,UAAA,CACG,GACA,KAAY,kBAAC,IAAD,CAAmB,CAAA,CAC3B;MAET,CAAA,GAAA,kBAAC,EAAgB,OAAjB;OACO;OAGL,aAAa,KAAe;OAC5B,gBAAc,KAAS,KAAA;OACvB,oBAAkB;OAClB,WAAW,EAAY;MACxB,CAAA,CACE;;KACJ,KAAe,QAAQ,MAAgB,MACtC,kBAAC,QAAD;MAAM,IAAI;MAAQ,WAAW,GAAO;MACjC,UAAA;KACG,CAAA;KAEP,KACC,kBAAC,QAAD;MAAM,WAAW,GAAO;MAAxB,UAAA,CACE,kBAAC,EAAgB,WAAjB;OACE,cAAY,EAAc;OAC1B,WAAW,GAAO;OAElB,UAAA,kBAAC,GAAD;QAAO,MAAM;QAAI,eAAA;OAAa,CAAA;MACL,CAAA,GAC3B,kBAAC,EAAgB,WAAjB;OACE,cAAY,EAAc;OAC1B,WAAW,GAAO;OAElB,UAAA,kBAAC,GAAD;QAAM,MAAM;QAAI,eAAA;OAAa,CAAA;MACJ,CAAA,CACvB;;IAEL;;GACJ,MACC,kBAAC,IAAD;IACE,IAAI;IACG;IACP,SAAS,EAAQ;IAEhB,UAAA,EAAQ;GACM,CAAA;EAEC;;AAE1B;AAEA,IAAM,KAAmB,EAAkB;CACzC,UAAU;EACR,IAAI;EACJ,IAAI;EACJ,IAAI;EACJ,IAAI;CACN;CACA,UAAU;EACR,IAAI;EACJ,IAAI;EACJ,IAAI;EACJ,IAAI;CACN;AACF,CAAC,GCxQY,KAA2C;CACtD;CACA;CACA;CACA;AACF;AAoBA,SAAgB,GAAU,GAAsB;CAC9C,OAAO,EACJ,YAAY,CAAC,CACb,QAAQ,WAAW,MAClB,OAAO,cAAc,SAAS,EAAK,WAAW,CAAC,CAAC,CAClD;AACJ;AAQA,SAAgB,GAAkB,GAAiC;CACjE,IAAM,IAAe,IAAI,KAAK,aAAa,CAAC,CAAM,GAAG,EAAE,MAAM,SAAS,CAAC,GACjE,IAAM,EAAa,GAEnB,KAAY,GAAmB,OAAoC;EACvE;EACA,UAAU,GAAsB,CAAI;EACpC,MAAM,EAAa,GAAG,CAAI,KAAK;EAC/B,MAAM,GAAU,CAAI;EACpB;CACF,IAEM,IAAS,GAAiB,QAAQ,MAAS,EAAI,SAAS,CAAI,CAAC,CAAC,CAAC,KAClE,MAAS,EAAS,GAAM,EAAI,CAC/B,GAEM,IAAO,EACV,QAAQ,MAAS,CAAC,GAAiB,SAAS,CAAI,CAAC,CAAC,CAClD,KAAK,MAAS,EAAS,GAAM,EAAK,CAAC,CAAC,CACpC,MAAM,GAAG,MAAM,EAAE,KAAK,cAAc,EAAE,MAAM,CAAM,CAAC;CAEtD,OAAO,CAAC,GAAG,GAAQ,GAAG,CAAI;AAC5B;;;;;;;;;;;;;;;;;;;GE/BM,KAAqD;CACzD,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;AACN,GAEM,KAA+C;CACnD,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;AACN;AAsFA,SAAS,GAAqB,GAAsB,GAAuB;CACzE,IAAI,MAAY,MAAM;EACpB,IAAM,IAAS,EAAM,QAAQ,OAAO,EAAE,CAAC,CAAC,MAAM,GAAG,CAAC;EAClD,OAAO;GAAC,EAAO,MAAM,GAAG,CAAC;GAAG,EAAO,MAAM,GAAG,CAAC;GAAG,EAAO,MAAM,GAAG,CAAC;EAAC,CAAC,CAChE,OAAO,OAAO,CAAC,CACf,KAAK,GAAG;CACb;CACA,OAAO,IAAI,GAAU,CAAO,CAAC,CAAC,MAAM,CAAK;AAC3C;AAOA,SAAS,GAAsB,GAAsB,GAAwB;CAC3E,IAAI,MAAY,MAAM,OAAO,GAAqB,GAAS,CAAM;CACjE,IAAM,IAAW,GAAsB,CAAO;CAC9C,OAAO,IAAI,GAAU,CAAO,CAAC,CAC1B,MAAM,IAAI,IAAW,GAAQ,CAAC,CAC9B,QAAQ,IAAI,KAAY,EAAE,CAAC,CAC3B,KAAK;AACV;AAGA,SAAS,GAAY,GAAsB,GAAsB;CAI/D,OADI,WAAW,KAAK,CAAI,IAAU,IAAI,GAAU,CAAO,CAAC,CAAC,MAAM,CAAI,IAC5D,GAAsB,GAAS,EAAK,QAAQ,OAAO,EAAE,CAAC;AAC/D;AAMA,SAAS,GAAQ,GAAsB,GAAsB;CAC3D,IAAM,IAAS,GACb,EAAK,QAAQ,UAAU,EAAE,GACzB,CACF;CAIA,OAHI,KAAU,EAAO,uBAAuB,GAAsB,CAAO,IAChE,GAAsB,GAAS,EAAO,cAAc,IAEtD,GAAY,GAAS,CAAI;AAClC;AAQA,SAAS,GACP,GACA,GACA,EAAE,gBAAa,iBACF;CACb,IAAM,UAAkB;EACtB,IAAM,IAAS,GACb,EAAM,QAAQ,OAAO,EAAE,GACvB,CACF;EACA,OAAO,GAAQ,QAAQ,KAAK,EAAO,YAAY,IAC3C,EAAM,EAAO,MAAM,IACnB,EAAQ;CACd;CAEA,IAAI,KAAc,GAAgB,CAAO,GAAG;EAC1C,IAAM,IAAS,GAAqB,GAAS,CAAK;EAClD,OAAO,EAAO,QACV;GAAE,GAAG;GAAQ,UAAU;EAAM,IAC7B;GAAE,OAAO;GAAO,UAAU,EAAU,CAAC,CAAC;EAAM;CAClD;CAEA,OAAO;EACL,GAAI,IAAc,EAAU,IAAI,GAAoB,GAAS,CAAK;EAClE,UAAU;CACZ;AACF;AAEA,IAAM,KAAiB,EAAkB;CACvC,cAAc;EACZ,IAAI;EACJ,IAAI;EACJ,IAAI;EACJ,IAAI;CACN;CACA,eAAe;EACb,IAAI;EACJ,IAAI;EACJ,IAAI;EACJ,IAAI;CACN;CACA,aAAa;EACX,IAAI;EACJ,IAAI;EACJ,IAAI;EACJ,IAAI;CACN;CACA,SAAS;EACP,IAAI;EACJ,IAAI;EACJ,IAAI;EACJ,IAAI;CACN;CACA,WAAW;EACT,IAAI;EACJ,IAAI;EACJ,IAAI;EACJ,IAAI;CACN;AACF,CAAC,GAEK,MAAQ,GAAG,MACf,EAAM,OAAO,OAAO,CAAC,CAAC,KAAK,GAAG,KAAK,KAAA,GAG/B,MAAc,MAClB,GAAG,EAAO,KAAK,GAAG,EAAO,KAAK,GAAG,EAAO,SAAS,IAAI,EAAO,YAExD,MAAe,GAAkB,MAAqB,EAAE,SAAS,EAAE;AAqBzE,SAAS,GAAc,EACrB,YACA,UACA,aACA,cACA,gBACA,kBACA,aACA,SACA,iBACA,gBACqB;CACrB,IAAM,EAAE,gBAAa,EAAS,UAAU,EAAE,aAAa,OAAO,CAAC,GACzD,CAAC,GAAO,KAAY,EAAS,EAAE,GAG/B,CAAC,GAAU,KAAe,EAAS,EAAK,GAExC,IAAW,EAAQ,MAAM,MAAW,EAAO,SAAS,CAAK,KAAK,MAC9D,IAAc,EAAQ,QAAQ,MAAW,EAAO,MAAM,CAAC,CAAC;CAE9D,OACE,kBAAC,EAAS,MAAV;EACE,OAAO;EACP,OAAO;EACP,gBAAgB,MAAS;GACvB,AAAI,KAAM,EAAS,EAAK,IAAI;EAC9B;EACA,YAAY;EACZ,oBAAoB;EACd;EACQ;EACd,SAAS,GAAQ,MAAS,EAAS,GAAW,CAAM,GAAG,CAAI;EAC3D,oBAAoB,MAAW,EAAO;EACtC,oBAAoB,MAAW,EAAO;EACtC,oBAAoB;EACV;EACV,sBAAsB;EAfxB,UAAA,CAiBE,kBAAC,EAAS,SAAV;GACE,WAAW,EAAO;GAClB,cAAY,IAAW,GAAG,EAAU,IAAI,EAAS,SAAS;GAF5D,UAAA,CAIG,KACC,kBAAA,GAAA,EAAA,UAAA,CACE,kBAAC,QAAD;IAAM,eAAA;IAAY,WAAW,EAAO;IACjC,UAAA,EAAS;GACN,CAAA,GACN,kBAAC,QAAD;IAAM,WAAW,EAAO;IAAxB,UAAA,CAA8B,KAAE,EAAS,QAAe;GACxD,CAAA,CAAA,EAAA,CAAA,GAEJ,kBAAC,GAAD;IAAa,eAAA;IAAY,WAAW,EAAO;GAAU,CAAA,CACrC;EAClB,CAAA,GAAA,kBAAC,EAAS,QAAV,EAAA,UACE,kBAAC,EAAS,YAAV;GACE,QAAQ;GACR,MAAK;GACL,OAAM;GACN,YAAY;GACZ,WAAW,EAAW;GAEtB,UAAA,kBAAC,EAAS,OAAV;IACE,WAAW,EAAO;IAElB,cAAY;IACZ,iBAAe,IAAW,KAAK,KAAA;IAC/B,wBAAwB,EAAY,EAAI;IACxC,4BAA4B,EAAY,EAAK;IAN/C,UAAA;KAQE,kBAAC,OAAD;MAAK,WAAW,EAAO;MAAvB,UAAA,CACE,kBAAC,GAAD,EAAQ,eAAA,GAAa,CAAA,GACrB,kBAAC,EAAS,OAAV;OACE,WAAW,EAAO;OAClB,aAAa;OACb,cAAY;MACb,CAAA,CACE;;KACL,kBAAC,EAAS,OAAV;MAAgB,WAAW,EAAW;MACnC,UAAA;KACa,CAAA;KAChB,kBAAC,EAAS,MAAV;MAAe,WAAW,GAAK,EAAW,MAAM,EAAO,IAAI;MACvD,WAAA,GAAuB,MACvB,kBAAC,GAAD,EAAA,UAAA,CACG,MAAU,MAAM,IAAc,KAAK,MAAU,KAG5C,kBAAC,OAAD;OAAK,MAAK;OAAe,WAAW,EAAO;MAAY,CAAA,GAEzD,kBAAC,EAAS,MAAV;OACE,OAAO;OACP,WAAW,GAAK,EAAW,MAAM,EAAO,OAAO;OAFjD,UAAA;QAIE,kBAAC,QAAD;SAAM,eAAA;SAAY,WAAW,EAAO;SACjC,UAAA,EAAO;QACJ,CAAA;QACN,kBAAC,QAAD;SAAM,WAAW,EAAO;SAAc,UAAA,EAAO;QAAW,CAAA;QACxD,kBAAC,QAAD;SAAM,WAAW,EAAO;SAAxB,UAAA,CAAqC,KACjC,EAAO,QACL;;OACO;MACP,CAAA,CAAA,EAAA,GAlBK,EAAO,IAkBZ;KAEC,CAAA;IACD;;EACG,CAAA,EACN,CAAA,CACJ;;AAEnB;AAiBA,SAAgB,GAAiB,EAC/B,UACA,eACA,UACA,cAAW,IACX,cAAW,IACX,OACA,YACA,mBACA,oBACA,UACA,iBACA,kBACA,WACA,cACA,gBAAa,IACb,oBAAiB,IACjB,cACA,UACA,QACA,oBAAoB,GACpB,GAAG,KACqB;CACxB,IAAM,IAAW,GAAY,GACvB,IAAI,GAAe,GACnB,IAAc,EAAM,GACpB,IAAU,KAAM,GAChB,KAAe,EAAM,GACrB,IAAa,EAAM,GACnB,IAAS,EAAuB,IAAI,GACpC,CAAC,IAAa,KAAkB,EAAS,EAAK,GAG9C,IAAU,KAAa,QAAQ,EAAU,SAAS,IAAI,IAAY,MAClE,IAAQ,GAAS,WAAW,GAC5B,IAAa,GAAS,KAAK,GAAG,GAG9B,IAAU,QAAc;EAC5B,IAAM,IAAM,GAAkB,GAAmB,EAAS,GACpD,IAAQ,GAAY,MAAM,GAAG;EACnC,OAAO,IAAQ,EAAI,QAAQ,MAAW,EAAM,SAAS,EAAO,IAAI,CAAC,IAAI;CACvE,GAAG,CAAC,GAAU,CAAU,CAAC,GAEnB,KAAmB,KAAkB,GAAoB,IACzD,CAAC,GAAc,KAAmB,EACtC,KAAW,CAAC,EAAQ,SAAS,EAAgB,IACzC,EAAQ,KACR,EACN,GACM,IAAiB,KAAW,GAC5B,KAAe;EAAE,aAAa,KAAW;EAAM;CAAW,GAE1D,CAAC,IAAY,MAAiB,EAAiB,KAAgB,EAAE,GACjE,IAAe,KAAS,IAExB,CAAC,IAAS,MAAc,EAAS,EAAK,GAEtC,IAAQ,GAAY,GAAgB,GAAc,EAAY,GAC9D,KAAwB;EAC5B,SAAS;EACT,MAAM,EAAM;EACZ,SAAS,EAAM;CACjB,GAEM,KACJ,KAAkB,MAAW,EAAa,KAAK,MAAM,MAAM,CAAC,GAAK,SAC7D,KAAgB,KAAS,IACzB,KACJ,MACC,KACG,EAAM,WACJ,EAAE,YACF,EAAE,UACJ,KAAA,IACA,KAAgB,MAAkB,MAElC,MAAQ,GAAmB,MAA6B;EAC5D,IAAM,IAAS,GAAY,GAAa,GAAW,EAAY;EAC/D,IAAgB,GAAW;GACzB,SAAS;GACT,MAAM,EAAO;GACb,SAAS,EAAO;EAClB,CAAC;CACH,GAEM,MAAa,GAAmB,MAA6B;EAMjE,AALI,MAAU,KAAA,KAAW,GAAc,CAAS,GAC5C,MAAgB,MACd,MAAY,KAAA,KAAW,EAAgB,CAAW,GACtD,IAAkB,CAAW,IAE/B,GAAK,GAAW,CAAW;CAC7B,GAEM,MAAuB,MAAsB;EAMjD,AALI,MAAY,KAAA,KACd,EAAgB,CAAI,GAEtB,IAAkB,CAAI,GAEtB,GAAK,GAAc,CAAI;CACzB,GAEM,KAAqB,MAAyC;EAClE,IAAM,IAAO,EAAM,OAAO;EAE1B,IAAI,CAAC,GAAS;GACZ,GAAU,GAAqB,GAAgB,CAAI,GAAG,CAAc;GACpE;EACF;EAGA,IAAI,EAAK,SAAS,EAAa,SAAS,GAAG;GAEzC,IAAM,IAAS,GACb,EAAK,QAAQ,UAAU,EAAE,GACzB,CACF,GACM,IACJ,GAAQ,WAAW,EAAQ,SAAS,EAAO,OAAO,IAC9C,EAAO,UACP;GACN,GAAU,GAAQ,GAAa,CAAI,GAAG,CAAW;GACjD;EACF;EAEA,GAAU,GAAY,GAAgB,CAAI,GAAG,CAAc;CAC7D,GAEM,MAAc,MAAwC;EAE1D,IADA,GAAW,EAAI,GACX,GAAS;GACX,IAAM,IAAU,GAAQ,GAAgB,CAAY;GACpD,AAAI,MAAY,KAAc,GAAU,GAAS,CAAc;EACjE;EACA,IAAS,CAAK;CAChB,GAEM,KAAc,IAChB,EAAQ,MAAM,MAAW,EAAO,SAAS,CAAc,IACvD,KAAA;CAeJ,OACE,kBAAC,OAAD;EACE,WAAW,GAAK,EAAY,OAAO,EAAO,OAAO,CAAS;EACnD;EAFT,UAAA,CAIE,kBAAC,OAAD;GACE,KAAK;GACL,WAAW,GAAK,EAAY,KAAK,EAAO,GAAG;GAC3C,gBAAc,KAAgB,KAAK,KAAA;GACnC,iBAAe,IAAW,KAAK,KAAA;GAC/B,qBAAmB,KAAc,KAAK,KAAA;GACtC,UArBc,MAAsC;IACxD,IAAM,IAAS,EAAM;IAChB,EAAM,cAAc,SAAS,CAAM,MACpC,EAAO,QAAQ,eAAe,KAElC,EAAM,cACH,cAA2B,qBAAmB,CAAC,EAC9C,MAAM;GACZ;GAOI,UAAA,CAQG,IACC,MAEE,kBAAC,QAAD;IAAM,WAAW,EAAO;IAAxB,UAAA,CACE,kBAAC,QAAD;KAAM,eAAA;KAAY,WAAW,EAAO;KACjC,UAAA,GAAY;IACT,CAAA,GACN,kBAAC,QAAD;KAAM,IAAI;KAAY,WAAW,EAAO;KAAxC,UAAA,CAA8C,KAC1C,GAAY,QACV;IACF,CAAA,CAAA;GAGR,CAAA,IAAA,kBAAC,IAAD;IACW;IACT,OAAO;IACP,UAAU;IACV,WAAW,EAAE;IACb,aAAa,EAAE;IACf,eAAe,EAAE;IACP;IACV,MAAM;IACN,cAAc;IACd,WAAW;GACZ,CAAA,GAEH,kBAAC,OAAD;IAAK,WAAW,GAAK,EAAY,OAAO,EAAO,KAAK;IAApD,UAAA,CACG,KAAS,QACR,kBAAC,SAAD;KACE,SAAS;KACT,WAAW,GAAK,EAAY,OAAO,EAAO,KAAK;KAFjD,UAAA,CAIG,GACA,KAAY,kBAAC,IAAD,CAAmB,CAAA,CAC3B;IAET,CAAA,GAAA,kBAAC,SAAD;KACE,WAAU;KACV,cAAa;KACb,GAAI;KACC;KACL,IAAI;KACJ,MAAK;KACL,OAAO;KACP,UAAU;KACV,QAAQ;KACE;KACA;KACV,gBAAc;KACd,oBAAkB,GAChB,MAAe,GACf,MAAiB,IACjB,CACF;KACA,WAAW,EAAY;IACxB,CAAA,CACE;GACF,CAAA,CAAA;EACJ,CAAA,GAAA,MACC,kBAAC,IAAD;GAAiB,IAAI;GAAc,OAAO;GACvC,UAAA;EACc,CAAA,CAEhB;;AAET;;;;;GE7nBa,KAAuB,GAAO,QAC9B,KAAoB,GAAO,KAkB3B,MAAe,EAC1B,aAAU,IACV,UAAO,MACP,mBAEA,kBAAC,QAAD;CACE,eAAA;CACA,WAAW,CAAC,GAAO,QAAQ,CAAS,CAAC,CAAC,OAAO,OAAO,CAAC,CAAC,KAAK,GAAG;CAC9D,aAAW;CACX,gBAAc,IAAU,KAAK,KAAA;CAE7B,UAAA,kBAAC,QAAD,EAAM,WAAW,GAAO,IAAM,CAAA;AAC1B,CAAA,qCENF,KAAoB,EAA6C,IAAI,GAG9D,MAAwB,MAAsB;CACzD,IAAM,IAAQ,EAAW,EAAiB;CAC1C,IAAI,CAAC,GACH,MAAU,MACR,IAAI,EAAU,oEAChB;CAEF,OAAO;AACT,GAiEM,MAAQ,GAAG,MACf,EAAM,OAAO,OAAO,CAAC,CAAC,KAAK,GAAG,KAAK,KAAA;AAOrC,SAAgB,GAAqC,EACnD,UACA,YACA,eACA,WAAQ,IACR,UACA,iBACA,kBACA,SACA,cAAW,IACX,cAAW,IACX,WACA,OACA,cAAc,GACd,mBAAmB,GACnB,oBAAoB,GACpB,cACA,UACA,QACA,SACA,aACA,qBACA,iBACA,uBACA,eACyB;CAGzB,IAAM,IAAU,EAAM,GAChB,IAAe,EAAM,GACrB,IAAW,KAAS,MACpB,KAAgB,KAAc,MAE9B,IAAQ,SACL;EAAE;EAAM;CAAS,IACxB,CAAC,GAAM,CAAQ,CACjB;CAEA,OACE,kBAAC,OAAD;EAAK,WAAW,GAAK,GAAO,OAAO,CAAS;EAAU;EAAtD,UAAA;GACG,KACC,kBAAC,IAAD;IACE,IAAI;IACK;IACC;IACH;IACG;IAET,UAAA;GACc,CAAA;GAEnB,kBAAC,GAAkB,UAAnB;IAA4B,OAAO;IACjC,UAAA,kBAAC,IAAD;KACM;KACJ,UAAU;KACJ;KACC;KACO;KACd,gBAAgB,MAAS,IAAgB,CAAS;KACxC;KACA;KACV,cAAY;KACZ,mBAAiB,IAAW,IAAU;KACtC,oBAAkB,GAChB,MAAiB,GACjB,CACF;KACA,gBAAc,IAAQ,KAAO,KAAA;KAC7B,SAAS,MAAU;MAEb,EAAM,cAAc,SAAS,EAAM,aAAa,KACpD,IAAS,CAAK;KAChB;KACA,WAAW;KACX,OAAO;KACP,gBAAc;KAEb;IACa,CAAA;GACU,CAAA;GAC3B,MACC,kBAAC,IAAD;IAAiB,IAAI;IAAqB;IACvC,UAAA;GACc,CAAA;EAEhB;;AAET;;;;;;ICnJM,MAAQ,GAAG,MACf,EAAM,OAAO,OAAO,CAAC,CAAC,KAAK,GAAG,KAAK,KAAA;AAcrC,SAAgB,GAAwC,EACtD,UACA,UACA,cAAW,IACX,SACA,OACA,cAAc,GACd,cACA,UACA,UACe;CACf,IAAM,IAAQ,GAAqB,iBAAiB,GAC9C,IAAO,KAAS,MAEhB,IACJ,kBAAC,GAAU,MAAX;EAGE,cAAA;EACA,QAAQ,kBAAC,UAAD,EAAQ,MAAK,SAAU,CAAA;EAC3B;EACJ,UAAU;EACH;EACG;EACV,cAAY;EACZ,aAAW,KAAQ,EAAM,QAAQ;EACjC,WACE,IAAO,GAAK,IAAsB,CAAS,IAAI;EAEjD,OAAO,IAAO,IAAQ,KAAA;EAEtB,UAAA,kBAAC,GAAU,WAAX;GAAqB,aAAA;GAAY,WAAW;EAAoB,CAAA;CAClD,CAAA;CAKlB,OAFI,IAAa,IAGf,kBAAC,SAAD;EAAO,WAAW,GAAK,GAAU,KAAK,CAAS;EAAU;EAAzD,UAAA,CACG,GACD,kBAAC,QAAD;GAAM,WAAW,GAAU;GAAO,UAAA;EAAY,CAAA,CACzC;;AAEX;AAmCA,SAAgB,GAAoC,EAClD,YACA,aACA,GAAG,KACY;CACf,OACE,kBAAC,IAAD;EAAgB,GAAI;EAAM,kBAAkB,GAAO;EAAnD,UAAA,CACG,GAAS,KAAK,MACb,kBAAC,IAAD;GAEE,OAAO,EAAO;GACd,OAAO,EAAO;GACd,UAAU,EAAO;EAClB,GAJM,OAAO,EAAO,KAAK,CAIzB,CACF,GACA,CACa;;AAEpB;;;;;;;;;;;;;;;;;;IEpJM,MAAQ,GAAG,MACf,EAAM,OAAO,OAAO,CAAC,CAAC,KAAK,GAAG,KAAK,KAAA;AA4CrC,SAAgB,GAAwC,EACtD,UACA,iBAAc,cACd,cAAW,IACX,SACA,cACA,UACA,QACA,eACe;CACf,IAAM,IAAQ,GAAqB,gBAAgB;CAEnD,OACE,kBAAC,SAAD;EACO;EACL,WAAW,GAAK,GAAO,MAAM,CAAS;EAC/B;EACP,oBAAkB;EAClB,aAAW,KAAQ,EAAM,YAAY;EALvC,UAAA,CAOE,kBAAC,GAAU,MAAX;GAIE,cAAA;GACA,QAAQ,kBAAC,UAAD,EAAQ,MAAK,SAAU,CAAA;GACxB;GACG;GACV,WAAW,GAAO;EACnB,CAAA,GACA,CACI;;AAEX;AAYA,IAAa,MAAa,EAAE,cAC1B,kBAAC,IAAD;CAAmB;CAAM,WAAW,GAAO;AAAY,CAAA,GAa5C,MAAQ,EAAE,UAAO,IAAI,cAEzB,kBAAC,GAAD;CAAa;CAAM,eAAA;CAAY,WAAW,GAAO;AAAO,CAAA,GASpD,MAAW,EACtB,aACA,cACA,eAMA,kBAAC,QAAD;CAAM,WAAW,GAAK,GAAO,SAAS,CAAS;CAAU;CACtD;AACG,CAAA,GAIK,MAAS,EAAE,kBACtB,kBAAC,QAAD;CAAM,WAAW,GAAO;CAAQ;AAAe,CAAA,GAIpC,MAAe,EAAE,kBAC5B,kBAAC,QAAD;CAAM,WAAW,GAAO;CAAc;AAAe,CAAA;AA6CvD,SAAgB,GAAqC,EACnD,YACA,aAAU,GACV,SACA,aACA,GAAG,KACa;CAChB,OACE,kBAAC,IAAD;EACE,GAAI;EACJ,UAAU;EACV,kBAAkB,GAAO;EACzB,cAAc,EAAE,wBAAwB,EAAQ;EAChD,oBAAoB,IAAU,IAAI,SAAS,KAAA;EAL7C,UAAA,CAOG,GAAS,KAAK,MACb,kBAAC,IAAD;GAEE,OAAO,EAAO;GACd,UAAU,EAAO;GAHnB,UAAA,CAKE,kBAAC,IAAD,CAAY,CAAA,GACX,EAAO,KACJ;EANC,GAAA,OAAO,EAAO,KAAK,CAMpB,CACP,GACA,CACa;;AAEpB;;;ACpLA,SAAgB,GAAsC,EACpD,YACA,UACA,kBAAe,IACf,kBACA,GAAG,KACkB;CACrB,IAAM,IAAe,MAAU,KAAA,GACzB,CAAC,GAAU,KAAe,EAAqB,CAAY,GAC3D,IAAU,IAAe,IAAQ,GAEjC,IAAS,EAAQ,MAAM,MAAW,EAAO,UAAU,CAAO;CAEhE,OACE,kBAAC,IAAD;EACE,GAAI;EACJ,UAAU;EAGV,OAAO,IAAS,EAAO,QAAQ;EAC/B,gBAAgB,MAAS;GACvB,IAAM,IAAa,KAAQ;GAE3B,AADK,KAAc,EAAY,CAAS,GACxC,IAAgB,CAAS;EAC3B;EACA,QAAQ,KAAU;EAClB,SAAS,GAAQ;EACjB,eAAA;EACA,WAAW,GAAQ,SAAS;EAE3B,UAAA,EAAQ,KAAK,MACZ,kBAAC,IAAD,EAA4C,UAAS,GAA/B,EAAO,KAAwB,CACtD;CACU,CAAA;AAEjB;;;;;;;;;AEfA,SAAgB,GAAO,EACrB,UACA,cAAc,GACd,eACA,WAAQ,IACR,SAAM,GACN,SAAM,KACN,WACA,WACA,cACA,GAAG,KACW;CAGd,IAAM,IAAU,EAAM,GAChB,IAAe,EAAM;CAE3B,OAGE,kBAAC,GAAM,MAAP;EAAY,SAAS;EAAO,QAAQ;EAClC,UAAA,kBAAC,EAAW,MAAZ;GACE,GAAI;GACC;GACA;GACG;GACA;GACR,mBAAiB,KAAS,OAAiB,KAAA,IAAV;GACjC,WAAW,EAAe,GAAO,QAAQ,CAAS;GAPpD,UAAA;IASE,kBAAC,OAAD;KAAK,WAAW,GAAO;KAAvB,UAAA,CACG,KAAS,QACR,kBAAC,OAAD;MAAK,IAAI;MAAS,WAAW,GAAO;MACjC,UAAA;KACE,CAAA,GAEP,kBAAC,EAAW,OAAZ,EAAkB,WAAW,GAAO,MAAQ,CAAA,CACzC;;IACL,kBAAC,IAAD;KACE,cAAY;KACZ,oBAAkB,KAAc,OAAsB,KAAA,IAAf;IACxC,CAAA;IACD,kBAAC,IAAD;KAAkB;KAAU;KAAa;KAAgB;IAAS,CAAA;IACjE,KAAc,QACb,kBAAC,IAAD;KAAkB,IAAI;KAAqB;KACxC,UAAA;IACe,CAAA;GAEL;;CACP,CAAA;AAEhB;;;;;;;AE9EA,SAAgB,GAAO,EAAE,cAAW,GAAG,KAAqB;CAC1D,OACE,kBAAC,GAAW,MAAZ;EACE,GAAI;EACJ,WAAW,EAAe,GAAO,QAAQ,CAAS;EAElD,UAAA,kBAAC,GAAW,OAAZ,EAAkB,WAAW,GAAO,MAAQ,CAAA;CAC7B,CAAA;AAErB;;;;GElCM,MACJ,MAEA,OAAO,KAAU,cAAY;AAU/B,SAAgB,GACd,GACA,GACA,IAAwC,QACzB;CACf,IAAI,MAAU,KAAA,GAAW,OAAO,CAAC;CAEjC,IAAM,IAAU,GAAgB,CAAK,IACjC,OAAO,QAAQ,CAAsC,IACrD,CAAC,CAAC,QAAQ,CAAK,CAAU,GAEvB,IAAwC,CAAC;CAC/C,KAAK,IAAM,CAAC,GAAK,MAAU,GACzB,AAAI,MAAU,KAAA,MAAW,EAAK,MAAM,EAAK,GAAG,OAAS,EAAO,CAAK;CAGnE,OAAO;AACT;;;ACRA,SAAgB,GAAK,EACnB,YACA,QACA,WACA,cACA,UACA,GAAG,KACS;CACZ,OAAO,EAAU;EACf;EACA,OAAO;GACL,GAAG;GACH,WAAW,EAAe,GAAO,MAAM,CAAS,CAAC,CAAC,CAAC,CAAC;GACpD,OAAO;IACL,GAAG,GAAe,WAAW,CAAO;IACpC,GAAG,GAAe,OAAO,CAAG;IAC5B,GAAG;GACL;EACF;CACF,CAAC;AACH;AAaA,IAAM,MAAa,MACjB,MAAS,SAAS,WAAW,QAAQ,EAAK,UAAU;AAatD,SAAgB,GAAS,EACvB,SACA,WACA,cACA,UACA,GAAG,KACa;CAChB,OAAO,EAAU;EACf;EACA,OAAO;GACL,GAAG;GACH,WAAW,EAAe,GAAO,UAAU,CAAS,CAAC,CAAC,CAAC,CAAC;GACxD,OAAO;IAAE,GAAG,GAAe,QAAQ,GAAM,EAAS;IAAG,GAAG;GAAM;EAChE;CACF,CAAC;AACH;;;;AE1CA,SAAgB,GAAM,EACpB,cACA,QACA,UACA,YACA,UAAO,IACP,WACA,cACA,UACA,GAAG,KACU;CACb,OAAO,EAAU;EACf;EACA,OAAO;GACL,GAAG;GACH,cAAc;GACd,gBAAgB;GAChB,aAAa,KAAQ,KAAA;GACrB,WAAW,EAAe,GAAO,OAAO,CAAS,CAAC,CAAC,CAAC,CAAC;GACrD,OAAO;IACL,GAAG,GAAe,aAAa,CAAS;IACxC,GAAG,GAAe,OAAO,CAAG;IAC5B,GAAG;GACL;EACF;CACF,CAAC;AACH;AAeA,SAAgB,GAAO,GAAoB;CACzC,OAAO,kBAAC,IAAD;EAAO,GAAI;EAAO,WAAU;CAAO,CAAA;AAC5C;;;;;;;;;;;;;;GG9EM,KAAe;CACnB;CAAM;CAAM;CAAM;CAAK;CAAM;CAAM;CAAM;CAAM;CAAM;AACvD,GACM,KAAc,KACd,KAAe,KAQf,MAAe,GAAc,MAAqB;CACtD,IAAM,IAAQ,MAAM,KAAK,CAAI,CAAC,CAAC,QAC5B,GAAK,MAEJ,KAAO,MAAS,MAAM,KAAe,GAAa,OAAO,CAAI,MAAM,MACrE,CACF;CAGA,OAFa,KAAK,IAAI,IAAW,GAAe,CAEzC,IAAO,KAAK,MAAM,GAAO,EAAY;AAC9C,GAwCa,MAAkB,EAC7B,UACA,QACA,WAAQ,WACR,UAAO,IACP,iBAAc,GACd,eAAY,IACZ,eACyB;CACzB,IAAM,IAAuB,EAAiB,GAExC,KAAU,IAAO,KAAe,GAChC,IAAgB,IAAI,KAAK,KAAK,GAC9B,IAAW,IAAM,IAAI,KAAK,IAAI,KAAK,IAAI,IAAQ,GAAK,CAAC,GAAG,CAAC,IAAI,GAC7D,KAAiB,MAAkB,KAAiB,IAAI,IAExD,IAAS,EAAe,EAAc,CAAC,CAAC;CAE9C,QAAgB;EACd,IAAM,IAAS,EAAc,CAAQ;EACrC,IAAI,GAAsB;GACxB,EAAO,IAAI,CAAM;GACjB;EACF;EAEA,IAAM,IAAW,EAAQ,GAAQ,GAAQ;GACvC,UAAU;GACV,MAAM;EACR,CAAC;EACD,aAAa,EAAS,KAAK;CAE7B,GAAG;EAAC;EAAU;EAAe;EAAsB;CAAM,CAAC;CAE1D,IAAM,IAAY,GAAG,EAAM,GAAG,KACxB,IAAW,GAAY,GAAW,IAAO,IAAI,CAAW;CAY9D,OACE,kBAAC,OAAD;EACE,GAZuB,IACtB;GACC,MAAM;GACN,cAAc;GACd,iBAAiB;GACjB,iBAAiB;GACjB,iBAAiB;EACnB,IACC,EAAE,eAAe,GAAK;EAKvB,WAAW,GAAO;EAClB,cAAY;EACZ,OACE;GACE,OAAO;GACP,QAAQ;GACR,gBAAgB,GAAG,EAAS,QAAQ,CAAC,EAAE;EACzC;EATJ,UAAA,CAYE,kBAAC,OAAD;GACE,WAAW,GAAO;GAClB,OAAO;GACP,QAAQ;GACR,SAAS,OAAO,EAAK,GAAG;GAJ1B,UAAA,CAME,kBAAC,UAAD;IACE,WAAW,GAAO;IAClB,IAAI,IAAO;IACX,IAAI,IAAO;IACX,GAAG;IACH,MAAK;IACL,QAAO;IACM;GACd,CAAA,GACD,kBAAC,EAAO,QAAR;IACE,IAAI,IAAO;IACX,IAAI,IAAO;IACX,GAAG;IACH,MAAK;IACL,QAAO;IACM;IACb,eAAc;IACd,iBAAiB;IACjB,OAAO,EAAE,kBAAkB,EAAO;GACnC,CAAA,CACE;EACJ,CAAA,GAAA,KAAa,kBAAC,QAAD;GAAM,WAAW,GAAO;GAAQ,UAAA;EAAgB,CAAA,CAC3D;;AAET,GCrKa,KAAmB,EAAkB;CAChD,MAAM;EAAE,IAAI;EAAW,IAAI;EAAY,IAAI;EAAY,IAAI;CAAQ;CACnE,MAAM;EAAE,IAAI;EAAS,IAAI;EAAS,IAAI;EAAY,IAAI;CAAY;CAClE,MAAM;EAAE,IAAI;EAAS,IAAI;EAAQ,IAAI;EAAS,IAAI;CAAO;CACzD,IAAI;EAAE,IAAI;EAAM,IAAI;EAAM,IAAI;EAAK,IAAI;CAAK;AAC9C,CAAC,GC0DY,MAAe,EAC1B,gBACA,eACA,UACA,aACA,WACA,WAAQ,WACR,aAAU,WACV,kBAAe,MACf,YACA,WACA,iBAAc,SACQ;CAEtB,IAAM,IAAI;EAAE,GADF,GACK;EAAG,GAAG;CAAO,GACtB,IAAc,EAAM,GACpB,IAAkB,KAAW,GAE7B,IAAQ,MAAY,YAAY,IAAe,KAC/C,IAAc,KAAK,EAAE,KAAK,GAAG,EAAY,GAAG,EAAE,GAAG,GAAG;CAE1D,OACE,kBAAA,GAAA,EAAA,UAAA,CACE,kBAAC,OAAD;EAAK,WAAW,GAAO;EAAvB,UAAA,CACE,kBAAC,OAAD;GAAK,WAAW,GAAO;GAAvB,UAAA,CACG,KACC,kBAAC,IAAD;IACE,cAAY,EAAE;IACd,SAAS;IACT,SAAQ;IACR,OAAM;IAEN,UAAA,kBAAC,GAAD,EAAW,eAAA,GAAa,CAAA;GACd,CAAA,GAEd,kBAAC,OAAD;IAAK,WAAW,GAAO;IAAvB,UAAA,CACE,kBAAC,GAAD;KACE,IAAI;KACJ,UAAU;KACV,WAAW,GAAO;KAClB,iBAAe;KAJjB,UAAA,CAMG,GACD,kBAAC,QAAD;MAAM,WAAW,GAAO;MAAS,UAAA;KAAkB,CAAA,CAC9C;IACN,CAAA,GAAA,KAAY,QACX,kBAAC,KAAD;KAAG,WAAW,GAAO;KAArB,UAAA;MACG,EAAE;MAAK;MAAG;KACV;IAEF,CAAA,CAAA;GACF,CAAA,CAAA;EACL,CAAA,GAAA,kBAAC,IAAD;GAAgB,OAAO;GAAa,KAAK;GAAmB;EAAQ,CAAA,CACjE;CACJ,CAAA,GAAA,KAAe,kBAAC,MAAD,EAAI,WAAW,GAAO,QAAU,CAAA,CAChD,EAAA,CAAA;AAEN;;;;;;;;;GE7Da,MAAqB,EAChC,gBACA,eACA,UACA,WACA,WAAQ,WACR,cAAc,IAAU,MACxB,YACA,gBAC4B;CAE5B,IAAM,IAAI;EAAE,GADF,GACK;EAAG,GAAG;CAAO,GACtB,IAAc,EAAM,GACpB,IAAkB,KAAW;CAEnC,OACE,kBAAC,OAAD;EAAK,WAAW,GAAO;EAAmB,cAAY;EAAtD,UAAA,CACE,kBAAC,GAAS,MAAV;GACE,WAAW,GAAO;GAClB,OAAO;GACP,KAAK;GACL,mBAAiB;GACjB,wBACE,GAAG,EAAE,KAAK,GAAG,EAAY,GAAG,EAAE,GAAG,GAAG;GAGtC,UAAA,kBAAC,GAAS,OAAV;IAAgB,WAAW,GAAO;IAChC,UAAA,kBAAC,GAAS,WAAV,EAAoB,WAAW,GAAO,UAAY,CAAA;GACpC,CAAA;EACH,CAAA,GACf,kBAAC,OAAD;GAAK,WAAW,GAAO;GAAvB,UAAA,CACG,KACC,kBAAC,IAAD;IACE,cAAY,EAAE;IACd,SAAS;IACT,SAAQ;IACR,OAAM;IAEN,UAAA,kBAAC,GAAD,EAAW,eAAA,GAAa,CAAA;GACd,CAAA,GAEd,kBAAC,GAAD;IAAS,IAAI;IAAiB,UAAU;IAAI,WAAW,GAAO;IAC5D,UAAA,kBAAC,QAAD;KAAwB,WAAW,GAAO;KACvC,UAAA;IACG,GAFK,CAEL;GACC,CAAA,CACN;EACF,CAAA,CAAA;;AAET,GCpFM,KAA2B,EAAmC,IAAI,GAClE,KAA4B,EAExB,IAAI,GAuBD,MAAwB,EACnC,aACA,yBAC+B;CAC/B,IAAM,CAAC,GAAU,KAAe,EAC9B,KAAmB,IACrB;CAEA,OACE,kBAAC,GAA0B,UAA3B;EAAoC,OAAO;EACzC,UAAA,kBAAC,GAAyB,UAA1B;GAAmC,OAAO;GACvC;EACgC,CAAA;CACD,CAAA;AAExC,GAOa,WAAwB,EAAW,EAAwB,GAY3D,MAAyB,MAAkC;CACtE,IAAM,IAAS,EAAW,EAAyB,GAC7C,IAAc,GAAU,aACxB,IAAa,GAAU,YACvB,IAAQ,GAAU;CAExB,QAAgB;EAEZ,CAAC,KACD,MAAgB,KAAA,KAChB,MAAe,KAAA,KACf,MAAU,KAAA,KAIZ,EAAO;GAAE;GAAa;GAAY;EAAM,CAAC;CAC3C,GAAG;EAAC;EAAQ;EAAa;EAAY;CAAK,CAAC;AAC7C,GAYa,MAAsB,MAAmC;CACpE,IAAM,IAAW,GAAgB;CAKjC,OAJK,IAIE,kBAAC,IAAD;EAAmB,GAAI;EAAO,GAAI;CAAW,CAAA,IAH3C;AAIX;;;;;;;;;;;;;AElFA,SAAgB,GAAK,EAAE,WAAQ,WAAW,cAAW,GAAG,KAAmB;CACzE,OACE,kBAAC,GAAS,MAAV;EACE,GAAI;EACJ,cAAY;EACZ,WAAW,EAAe,GAAO,MAAM,CAAS;CACjD,CAAA;AAEL;AAoBA,SAAgB,GAAK,EAAE,aAAU,cAAW,GAAG,KAAmB;CAChE,OACE,kBAAC,GAAS,MAAV;EAAe,GAAI;EAAM,WAAW,EAAe,GAAO,MAAM,CAAS;EAAzE,UAAA,CACG,GACD,kBAAC,IAAD,CAAY,CAAA,CACC;;AAEnB;AAeA,SAAgB,GAAI,EAAE,cAAW,GAAG,KAAkB;CACpD,OACE,kBAAC,GAAS,KAAV;EAAc,GAAI;EAAM,WAAW,EAAe,GAAO,KAAK,CAAS;CAAI,CAAA;AAE/E;AAQA,SAAgB,GAAU,EAAE,cAAW,GAAG,KAAwB;CAChE,OACE,kBAAC,GAAS,WAAV;EACE,GAAI;EACJ,WAAW,EAAe,GAAO,WAAW,CAAS;CACtD,CAAA;AAEL;AASA,SAAgB,GAAM,EAAE,cAAW,GAAG,KAAoB;CACxD,OACE,kBAAC,GAAS,OAAV;EACE,GAAI;EACJ,WAAW,EAAe,GAAO,OAAO,CAAS;CAClD,CAAA;AAEL;;;;;;;;;;;;;;;;;AEzEA,SAAgB,GAAK,EACnB,aAAU,WACV,kBAAe,OACf,cACA,GAAG,KACS;CACZ,OACE,kBAAC,GAAc,MAAf;EACE,GAAI;EACJ,gBAAc;EACd,sBAAoB;EACpB,WAAW,EAAe,GAAO,MAAM,CAAS;CACjD,CAAA;AAEL;AAQA,SAAgB,GAAK,EAAE,cAAW,GAAG,KAAmB;CACtD,OACE,kBAAC,GAAc,MAAf;EACE,GAAI;EACJ,WAAW,EAAe,GAAO,MAAM,CAAS;CACjD,CAAA;AAEL;AAmBA,SAAgB,GAAO,EAAE,cAAW,GAAG,KAAqB;CAC1D,OACE,kBAAC,GAAc,QAAf;EACE,GAAI;EACJ,WAAW,EAAe,GAAO,QAAQ,CAAS;CACnD,CAAA;AAEL;AASA,SAAgB,GAAQ,EAAE,aAAU,cAAW,GAAG,KAAsB;CACtE,OACE,kBAAC,GAAc,SAAf;EACE,GAAI;EACJ,WAAW,EAAe,GAAO,SAAS,CAAS;EAFrD,UAAA,CAIE,kBAAC,QAAD;GAAM,WAAW,GAAO;GAAQ;EAAe,CAAA,GAC/C,kBAAC,GAAD;GAAa,WAAW,GAAO;GAAM,MAAM;GAAI,eAAA;EAAa,CAAA,CACvC;;AAE3B;AAQA,SAAgB,GAAM,EAAE,aAAU,cAAW,GAAG,KAAoB;CAClE,OACE,kBAAC,GAAc,OAAf;EACE,GAAI;EACJ,WAAW,EAAe,GAAO,OAAO,CAAS;EAEjD,UAAA,kBAAC,OAAD;GAAK,WAAW,GAAO;GAAU;EAAc,CAAA;CAC5B,CAAA;AAEzB;;;ACvEA,SAAgB,GAAgB,EAC9B,UACA,UACA,YACA,WACA,GAAG,KACoB;CACvB,IAAM,IAAiC,KAAS,CAC9C;EAAE;EAAO;EAAS;CAAO,CAC3B;CAEA,OACE,kBAAC,IAAD;EAAgB,GAAI;EACjB,UAAA,EAAQ,KAAK,GAAM,MAAU;GAC5B,IAAM,IAAY,EAAK,SAAS,OAAO,CAAK;GAC5C,OACE,kBAAC,IAAD;IAEE,OAAO;IACP,UAAU,EAAK;IAHjB,UAAA,CAKE,kBAAC,IAAD,EAAA,UAAA,CACE,kBAAC,IAAD,EAAA,UAAoB,EAAK,MAAyB,CAAA,GACjD,EAAK,MACU,EAAA,CAAA,GAClB,kBAAC,IAAD,EAAA,UAAkB,EAAK,QAAyB,CAAA,CAClC;GATT,GAAA,CASS;EAEpB,CAAC;CACa,CAAA;AAEpB;oDE7Fa,MAAgB,EAAE,UAAO,WAElC,kBAAC,OAAD;CAAK,eAAY;CAAO,WAAW,GAAO;CAAc,aAAW;AAAO,CAAA;;;;;GEiBjE,MAAa,EACxB,kBAAe,IACf,WAAQ,IACR,aACA,SACA,mBACoB;CACpB,IAAM,IAAc,EAAS,QAAQ,CAAQ,CAAC,CAAC,SAAS;CAExD,OACE,kBAAC,UAAD;EACE,WAAW,CAAC,GAAO,WAAW,CAAS,CAAC,CAAC,OAAO,OAAO,CAAC,CAAC,KAAK,GAAG;EACjE,sBAAoB,KAAgB,KAAA;EACpC,qBAAmB,KAAe,KAAA;EAHpC,UAAA,CAKE,kBAAC,IAAD;GACE,WAAW,GAAO;GAClB,cAAY,KAAS,KAAA;GAFvB,UAAA,CAIE,kBAAC,OAAD;IAAK,WAAW,GAAO;IACpB,UAAA,KAAc,kBAAC,OAAD;KAAK,KAAI;KAAoB,KAAI;KAAO,OAAO;IAAM,CAAA;GACjE,CAAA,GACJ,KACC,kBAAC,OAAD;IAAK,WAAW,GAAO;IAAmB;GAAc,CAAA,CAEjD;EACV,CAAA,GAAA,KAAgB,kBAAC,IAAD,EAAc,MAAK,KAAM,CAAA,CACpC;;AAEZ,GChDM,KAAiB,EAA0C,IAAI;AAUrE,SAAgB,GAAgB,EAAE,YAAS,eAAkC;CAC3E,IAAM,IAAQ,QAAmC;EAC/C,IAAM,IAAS,GAAU;EAEzB,OAAO;GACL,SAAS,EAAO;GAChB,QAAQ,EAAO;GACf,UAAU,EAAO;EACnB;CACF,GAAG,CAAC,CAAO,CAAC;CAEZ,OACE,kBAAC,GAAe,UAAhB;EAAgC;EAAQ;CAAkC,CAAA;AAE9E;AAMA,SAAgB,KAAkC;CAChD,IAAM,IAAU,EAAW,EAAc;CAEzC,IAAI,CAAC,GACH,MAAU,MACR,wDACF;CAGF,OAAO;AACT;;;ACvCA,SAAgB,KAAoB;CAClC,IAAM,EAAE,WAAQ,UAAU,MAAoB,GAAW,GAEnD,IAAmB,QAErB,IAAI,KAAK,aAAa,GAAQ;EAC5B,OAAO;EACP,UAAU;CACZ,CAAC,GACH,CAAC,GAAQ,CAAe,CAC1B;CAEA,OAAO,GACJ,GAAe,MAAoC;EAClD,IAAM,EAAE,cAAW,GAAiB,GAAG,MAAkB,KAAW,CAAC;EASrE,OANE,MAAa,KACb,OAAO,KAAK,CAAa,CAAC,CAAC,WAAW,IAE/B,EAAiB,OAAO,CAAK,IAG/B,IAAI,KAAK,aAAa,GAAQ;GACnC,OAAO;GACP;GACA,GAAG;EACL,CAAC,CAAC,CAAC,OAAO,CAAK;CACjB,GACA;EAAC;EAAiB;EAAkB;CAAM,CAC5C;AACF;;;AC3CA,IAAM,KAAmD;CACvD,MAAM;CACN,OAAO;CACP,KAAK;AACP;AAEA,SAAS,GAAO,GAAqC;CACnD,OAAO,aAAiB,OAAO,IAAQ,IAAI,KAAK,CAAK;AACvD;AAKA,SAAgB,KAAgB;CAC9B,IAAM,EAAE,cAAW,GAAW,GAExB,IAAmB,QACjB,IAAI,KAAK,eAAe,GAAQ,EAAoB,GAC1D,CAAC,CAAM,CACT;CAEA,OAAO,GACJ,GAA+B,MAAyC;EACvE,IAAM,IAAO,GAAO,CAAK;EAMzB,OAJK,IAIE,IAAI,KAAK,eAAe,GAAQ,CAAO,CAAC,CAAC,OAAO,CAAI,IAHlD,EAAiB,OAAO,CAAI;CAIvC,GACA,CAAC,GAAkB,CAAM,CAC3B;AACF;;;AC7BA,SAAgB,KAAkB;CAChC,IAAM,EAAE,cAAW,GAAW,GAExB,IAAmB,QACjB,IAAI,KAAK,aAAa,CAAM,GAClC,CAAC,CAAM,CACT;CAEA,OAAO,GACJ,GAAe,MACT,IAIE,IAAI,KAAK,aAAa,GAAQ,CAAO,CAAC,CAAC,OAAO,CAAK,IAHjD,EAAiB,OAAO,CAAK,GAKxC,CAAC,GAAkB,CAAM,CAC3B;AACF;AAMA,SAAgB,KAAsB;CACpC,IAAM,EAAE,cAAW,GAAW,GAExB,IAAmB,QAErB,IAAI,KAAK,aAAa,GAAQ;EAC5B,OAAO;EACP,uBAAuB;EACvB,uBAAuB;CACzB,CAAC,GACH,CAAC,CAAM,CACT;CAEA,OAAO,GACJ,GAAe,MACT,IAIE,IAAI,KAAK,aAAa,GAAQ;EACnC,OAAO;EACP,GAAG;CACL,CAAC,CAAC,CAAC,OAAO,CAAK,IANN,EAAiB,OAAO,CAAK,GAQxC,CAAC,GAAkB,CAAM,CAC3B;AACF;;;ACxCA,SAAgB,KAAwB;CACtC,IAAM,EAAE,eAAY,GAAW,GAEzB,IAAU,GACb,MAA2B,GAAkB,GAAS,CAAK,GAC5D,CAAC,CAAO,CACV,GAEM,IAAW,GACd,MAAoC,GAAmB,GAAS,CAAK,GACtE,CAAC,CAAO,CACV;CAEA,OAAO,OAAO,OAAO,GAAS,EAAE,YAAS,CAAC;AAC5C;AAKA,SAAgB,KAAyB;CACvC,IAAM,EAAE,eAAY,GAAW,GAEzB,IAAU,GACb,MAA2B,GAAmB,GAAS,CAAK,GAC7D,CAAC,CAAO,CACV,GAEM,IAAW,GACd,MAAoC,GAAoB,GAAS,CAAK,GACvE,CAAC,CAAO,CACV;CAEA,OAAO,OAAO,OAAO,GAAS,EAAE,YAAS,CAAC;AAC5C;AAKA,SAAgB,KAAyB;CACvC,IAAM,EAAE,eAAY,GAAW,GAEzB,IAAU,GACb,MAA2B,GAAmB,GAAS,CAAK,GAC7D,CAAC,CAAO,CACV,GAEM,IAAW,GACd,MAAoC,GAAoB,GAAS,CAAK,GACvE,CAAC,CAAO,CACV;CAEA,OAAO,OAAO,OAAO,GAAS,EAAE,YAAS,CAAC;AAC5C;;;ACrDA,SAAgB,GAAY,EAC1B,cAAA,MACA,eACmB;CACnB,OACE,kBAAC,GAAgB,UAAjB;EAA0B,OAAO;EAC9B;CACuB,CAAA;AAE9B;;;AClBA,IAAa,KAAc;CACzB,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;AACN,GCDa,MAAe,EAAE,UAAO,mBAAgB,QAC5C,OACL,KAAK,MAAM,WAAW,IAAQ,MAAM,CAAa,CAAC,IAAI,OAAO,CAC/D,GCLW,MAAuB,EAClC,UACA,mBAAgB,QAET,GAAY;CAAE;CAAO;AAAc,CAAC,CAAC,CAAC,QAAQ,CAAa,GAEvD,MAAuB,EAClC,UACA,mBAAgB,QAET,GAAY;CAAE;CAAO;AAAc,CAAC,IAAI,KAAM,IACjD,GAAoB;CAAE;CAAO,eAAe;AAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,GAAG,IACjE,GAAoB;CAAE;CAAO;AAAc,CAAC,CAAC,CAAC,QAAQ,KAAK,GAAG,GCrBvD,MAAoB,GAAe,IAAwB,MAC/D,GAAoB;CAAE;CAAO;AAAc,CAAC,IAAI;;;ACHzD,SAAgB,GAAoB,GAGlC;CACA,IAAM,IAAQ,EAAe,MAAM,wBAAwB;CAE3D,OADK,IACE;EAAE,OAAO,EAAM;EAAI,MAAM,EAAM;CAAG,IADtB;EAAE,OAAO;EAAI,MAAM;CAAG;AAE3C"}
|