@leabankab/component-library 7.2.0 → 8.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (194) hide show
  1. package/CHANGELOG.md +685 -0
  2. package/README.md +2 -5
  3. package/dist/component-library.es.js +2778 -5628
  4. package/dist/component-library.es.js.map +1 -1
  5. package/dist/component-library.umd.js +2 -35
  6. package/dist/component-library.umd.js.map +1 -1
  7. package/dist/components/animations/icons/status-icon.d.ts +4 -0
  8. package/dist/components/animations/illustrations/check-animation.d.ts +8 -0
  9. package/dist/components/animations/illustrations/pulse-animation.d.ts +5 -1
  10. package/dist/components/animations/illustrations/status-animation.d.ts +8 -1
  11. package/dist/components/animations/shared.d.ts +6 -32
  12. package/dist/components/animations/spinner.d.ts +18 -0
  13. package/dist/components/animations/use-animation-labels.d.ts +0 -5
  14. package/dist/components/buttons/action-button.d.ts +8 -10
  15. package/dist/components/buttons/button-base.d.ts +31 -17
  16. package/dist/components/buttons/button.d.ts +4 -4
  17. package/dist/components/buttons/close-button.d.ts +1 -1
  18. package/dist/components/buttons/icon-button.d.ts +2 -14
  19. package/dist/components/buttons/skip-link.d.ts +21 -4
  20. package/dist/components/color-roles.d.ts +8 -0
  21. package/dist/components/data-display/card.d.ts +31 -4
  22. package/dist/components/data-display/chip.d.ts +50 -8
  23. package/dist/components/data-display/data-field.d.ts +15 -4
  24. package/dist/components/data-display/tooltip.d.ts +74 -22
  25. package/dist/components/feedback/alert-parts.d.ts +329 -0
  26. package/dist/components/feedback/alert.d.ts +14 -19
  27. package/dist/components/feedback/global-alert.d.ts +24 -0
  28. package/dist/components/feedback/index.d.ts +1 -0
  29. package/dist/components/feedback/simple-dialog.d.ts +1 -1
  30. package/dist/components/form/amount-slider.d.ts +68 -0
  31. package/dist/components/form/autocomplete.d.ts +56 -59
  32. package/dist/components/form/checkbox-box.d.ts +11 -0
  33. package/dist/components/form/checkbox.d.ts +67 -7
  34. package/dist/components/form/combo-field.d.ts +60 -0
  35. package/dist/components/form/email-input.d.ts +20 -26
  36. package/dist/components/form/field-parts.d.ts +36 -0
  37. package/dist/components/form/index.d.ts +3 -9
  38. package/dist/components/form/input.d.ts +51 -13
  39. package/dist/components/form/multi-select.d.ts +12 -14
  40. package/dist/components/form/number-input.d.ts +20 -14
  41. package/dist/components/form/phone-number-input/phone-number-input.d.ts +25 -14
  42. package/dist/components/form/radio-card.d.ts +94 -43
  43. package/dist/components/form/radio-circle.d.ts +14 -13
  44. package/dist/components/form/radio-group-root.d.ts +88 -0
  45. package/dist/components/form/radio.d.ts +68 -24
  46. package/dist/components/form/select-field.d.ts +78 -0
  47. package/dist/components/form/select.d.ts +30 -42
  48. package/dist/components/form/slider-parts.d.ts +34 -0
  49. package/dist/components/form/slider.d.ts +40 -16
  50. package/dist/components/form/use-autocomplete-labels.d.ts +3 -16
  51. package/dist/components/form/use-blur-outside.d.ts +7 -0
  52. package/dist/components/form/use-focus-target-ref.d.ts +11 -0
  53. package/dist/components/form/use-tooltip-trigger-labels.d.ts +5 -0
  54. package/dist/components/index.d.ts +0 -1
  55. package/dist/components/layout/stack.d.ts +1 -1
  56. package/dist/components/navigation/form-stepper.d.ts +1 -1
  57. package/dist/components/navigation/index.d.ts +3 -1
  58. package/dist/components/navigation/linear-form-stepper.d.ts +58 -0
  59. package/dist/components/navigation/progress-circle.d.ts +14 -8
  60. package/dist/components/navigation/step-progress.d.ts +60 -0
  61. package/dist/components/navigation/tabs.d.ts +37 -34
  62. package/dist/components/navigation/use-stepper-labels.d.ts +1 -1
  63. package/dist/components/typography/link.d.ts +25 -16
  64. package/dist/components/typography/lists.d.ts +20 -23
  65. package/dist/components/typography/text.d.ts +46 -10
  66. package/dist/components/ui/app-header.d.ts +29 -0
  67. package/dist/components/ui/brand-divider.d.ts +7 -1
  68. package/dist/components/ui/index.d.ts +1 -0
  69. package/dist/cookie-consent/react.d.ts +0 -1
  70. package/dist/cookie-consent-react.cjs +1 -1
  71. package/dist/cookie-consent-react.cjs.map +1 -1
  72. package/dist/cookie-consent-react.mjs +107 -97
  73. package/dist/cookie-consent-react.mjs.map +1 -1
  74. package/dist/cookie-consent.css +1 -1
  75. package/dist/date-picker/datepicker.d.ts +140 -0
  76. package/dist/date-picker/index.d.ts +18 -0
  77. package/dist/date-picker/theme/field-base.d.ts +23 -0
  78. package/dist/date-picker/theme/form-control.theme.d.ts +7 -0
  79. package/dist/date-picker/theme/index.d.ts +12 -0
  80. package/dist/date-picker/theme/input.theme.d.ts +6 -0
  81. package/dist/{components/form/datepicker → date-picker}/use-view-toggle-labels.d.ts +1 -1
  82. package/dist/date-picker.cjs +2 -0
  83. package/dist/date-picker.cjs.map +1 -0
  84. package/dist/date-picker.mjs +1012 -0
  85. package/dist/date-picker.mjs.map +1 -0
  86. package/dist/{components/dev-panel → dev-panel}/dev-panel-payload.d.ts +1 -1
  87. package/dist/{components/dev-panel → dev-panel}/dev-panel-status.d.ts +2 -2
  88. package/dist/{components/dev-panel → dev-panel}/dev-panel-steps.d.ts +2 -1
  89. package/dist/{components/dev-panel → dev-panel}/dev-panel.d.ts +25 -19
  90. package/dist/dev-panel/index.d.ts +10 -0
  91. package/dist/{components/dev-panel → dev-panel}/json-highlight.d.ts +2 -2
  92. package/dist/dev-panel/parts.d.ts +9 -0
  93. package/dist/{components/dev-panel → dev-panel}/segmented-control.d.ts +5 -4
  94. package/dist/{components/dev-panel → dev-panel}/use-dev-panel-labels.d.ts +1 -1
  95. package/dist/{components/dev-panel → dev-panel}/use-roving-radio.d.ts +2 -2
  96. package/dist/dev-panel.cjs +3 -0
  97. package/dist/dev-panel.cjs.map +1 -0
  98. package/dist/dev-panel.css +1 -0
  99. package/dist/dev-panel.mjs +818 -0
  100. package/dist/dev-panel.mjs.map +1 -0
  101. package/dist/fonts/ClashGrotesk-Variable.woff2 +0 -0
  102. package/dist/index.css +1 -1
  103. package/dist/index.d.ts +1 -3
  104. package/dist/provider/lea-provider.d.ts +4 -7
  105. package/dist/react-hook-form/form-field.d.ts +76 -0
  106. package/dist/react-hook-form/index.d.ts +1 -0
  107. package/dist/react-hook-form.cjs +2 -0
  108. package/dist/react-hook-form.cjs.map +1 -0
  109. package/dist/react-hook-form.mjs +33 -0
  110. package/dist/react-hook-form.mjs.map +1 -0
  111. package/dist/tailwind.css +103 -17
  112. package/dist/theme/index.d.ts +0 -4
  113. package/dist/theme/token-types.d.ts +15 -3
  114. package/dist/theme/tokens/colors.d.ts +13 -0
  115. package/dist/theme/tokens/font-family.d.ts +9 -0
  116. package/dist/theme/tokens/font-sizes.d.ts +8 -0
  117. package/dist/theme/tokens/index.d.ts +5 -1
  118. package/dist/theme/tokens/line-heights.d.ts +11 -0
  119. package/dist/theme/tokens/opacity.d.ts +5 -0
  120. package/dist/theme/tokens/spacing.d.ts +6 -0
  121. package/dist/theme/tokens/text-styles.d.ts +61 -0
  122. package/dist/theme/tokens/type-scale.d.ts +21 -0
  123. package/dist/theme/types.d.ts +19 -30
  124. package/package.json +42 -6
  125. package/dist/components/dev-panel/index.d.ts +0 -9
  126. package/dist/components/form/datepicker/datepicker.d.ts +0 -99
  127. package/dist/components/form/datepicker/index.d.ts +0 -1
  128. package/dist/components/form/fields/autocomplete-field.d.ts +0 -17
  129. package/dist/components/form/fields/boolean-radio-field.d.ts +0 -3
  130. package/dist/components/form/fields/checkbox-field.d.ts +0 -12
  131. package/dist/components/form/fields/datepicker-field.d.ts +0 -9
  132. package/dist/components/form/fields/email-field.d.ts +0 -10
  133. package/dist/components/form/fields/field-types.d.ts +0 -18
  134. package/dist/components/form/fields/index.d.ts +0 -14
  135. package/dist/components/form/fields/input-field.d.ts +0 -9
  136. package/dist/components/form/fields/multi-select-field.d.ts +0 -9
  137. package/dist/components/form/fields/number-field.d.ts +0 -10
  138. package/dist/components/form/fields/phone-number-field.d.ts +0 -11
  139. package/dist/components/form/fields/radio-card-field.d.ts +0 -22
  140. package/dist/components/form/fields/radio-field.d.ts +0 -16
  141. package/dist/components/form/fields/select-field.d.ts +0 -9
  142. package/dist/components/form/fields/use-field-control.d.ts +0 -6
  143. package/dist/components/form/fields/use-tooltip-trigger-labels.d.ts +0 -5
  144. package/dist/components/form/form-control/form-control-context.d.ts +0 -35
  145. package/dist/components/form/form-control/form-control-label.d.ts +0 -1
  146. package/dist/components/form/form-control/form-control.d.ts +0 -13
  147. package/dist/components/form/form-control/form-helper-text.d.ts +0 -9
  148. package/dist/components/form/form-control/form-label.d.ts +0 -9
  149. package/dist/components/form/form-control/index.d.ts +0 -5
  150. package/dist/components/form/input-label.d.ts +0 -9
  151. package/dist/theme/components/accordion.theme.d.ts +0 -7
  152. package/dist/theme/components/action-button.theme.d.ts +0 -45
  153. package/dist/theme/components/alert.theme.d.ts +0 -2
  154. package/dist/theme/components/autocomplete.theme.d.ts +0 -2
  155. package/dist/theme/components/baseline-css.d.ts +0 -2
  156. package/dist/theme/components/button.theme.d.ts +0 -2
  157. package/dist/theme/components/card.theme.d.ts +0 -2
  158. package/dist/theme/components/checkbox.theme.d.ts +0 -2
  159. package/dist/theme/components/chip.theme.d.ts +0 -2
  160. package/dist/theme/components/dev-panel.theme.d.ts +0 -95
  161. package/dist/theme/components/dialog.theme.d.ts +0 -2
  162. package/dist/theme/components/drawer.theme.d.ts +0 -4
  163. package/dist/theme/components/field-base.d.ts +0 -31
  164. package/dist/theme/components/form-control-label.theme.d.ts +0 -2
  165. package/dist/theme/components/form-control.theme.d.ts +0 -2
  166. package/dist/theme/components/index.d.ts +0 -2
  167. package/dist/theme/components/input.theme.d.ts +0 -3
  168. package/dist/theme/components/link.theme.d.ts +0 -2
  169. package/dist/theme/components/menu-item.theme.d.ts +0 -2
  170. package/dist/theme/components/number-input.theme.d.ts +0 -23
  171. package/dist/theme/components/phone-number-input.theme.d.ts +0 -43
  172. package/dist/theme/components/radio.theme.d.ts +0 -2
  173. package/dist/theme/components/select.theme.d.ts +0 -2
  174. package/dist/theme/components/slider.theme.d.ts +0 -2
  175. package/dist/theme/components/tabs.theme.d.ts +0 -34
  176. package/dist/theme/components/tooltip.theme.d.ts +0 -110
  177. package/dist/theme/components/typography.theme.d.ts +0 -2
  178. package/dist/theme/mui-augmentation.d.ts +0 -147
  179. package/dist/theme/sx-config.d.ts +0 -10
  180. /package/dist/{components/form/datepicker → date-picker}/calendar-header.d.ts +0 -0
  181. /package/dist/{components/form/datepicker → date-picker}/drawer-toolbar.d.ts +0 -0
  182. /package/dist/{theme/components → date-picker/theme}/date-picker.theme.d.ts +0 -0
  183. /package/dist/{theme/components → date-picker/theme}/icon-button.theme.d.ts +0 -0
  184. /package/dist/{theme/tokens → date-picker/theme}/typography.d.ts +0 -0
  185. /package/dist/{components/form/datepicker → date-picker}/use-calendar-header-labels.d.ts +0 -0
  186. /package/dist/{components/form/datepicker → date-picker}/use-datepicker-title-labels.d.ts +0 -0
  187. /package/dist/{components/form/datepicker → date-picker}/view-renderers.d.ts +0 -0
  188. /package/dist/{components/form/datepicker → date-picker}/view-toggle.d.ts +0 -0
  189. /package/dist/{components/dev-panel → dev-panel}/dev-panel-country.d.ts +0 -0
  190. /package/dist/{components/dev-panel → dev-panel}/dev-panel-flow.d.ts +0 -0
  191. /package/dist/{components/dev-panel → dev-panel}/dev-panel-footer.d.ts +0 -0
  192. /package/dist/{components/dev-panel → dev-panel}/dev-panel-step-state.d.ts +0 -0
  193. /package/dist/{components/dev-panel → dev-panel}/dev-panel-variant.d.ts +0 -0
  194. /package/dist/{components/dev-panel → dev-panel}/use-copy.d.ts +0 -0
@@ -1 +1 @@
1
- {"version":3,"file":"cookie-consent-react.mjs","names":[],"sources":["../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/dialog.module.css","../src/i18n/language-context.tsx","../src/i18n/create-translation.ts","../src/components/feedback/use-close-label.ts","../src/components/feedback/dialog.tsx","../src/components/form/switch.module.css","../src/components/form/switch.tsx","../src/components/surfaces/accordion.module.css","../src/components/surfaces/accordion.tsx","../src/cookie-consent/consent-dialog.module.css","../src/cookie-consent/strapi-blocks.tsx","../src/cookie-consent/consent-dialog.tsx","../src/cookie-consent/react.tsx"],"sourcesContent":["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 four local properties that the variants read, which keeps\n * the 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-tint: var(--lea-palette-purple-subtle);\n --button-fg: var(--lea-palette-purple-base);\n --button-border: var(--lea-palette-purple-base);\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-tint: var(--lea-palette-bg-subtle);\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-tint: var(--lea-palette-status-error-subtle);\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=\"primary\"] {\n background-color: var(--button-solid);\n color: var(--button-on-solid);\n}\n\n.Button[data-variant=\"secondary\"] {\n border-color: var(--button-border);\n}\n\n@media (hover: hover) {\n .Button[data-variant=\"primary\"]:not([data-disabled]):hover {\n background-color: var(--button-solid-hover);\n }\n\n .Button[data-variant=\"secondary\"]:not([data-disabled]):hover,\n .Button[data-variant=\"tertiary\"]: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=\"primary\"][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=\"secondary\"][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 = \"primary\" | \"secondary\" | \"tertiary\";\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 * - `\"primary\"` — solid fill, for the main action.\n * - `\"secondary\"` — outlined.\n * - `\"tertiary\"` — ghost: no border or fill until hovered.\n * @default \"primary\"\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 = \"primary\",\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` (`primary`, `secondary`, `tertiary`), a `color`\n * (`accent`, `neutral`, `danger`) and a `size` (`sm`, `md`, `lg`).\n *\n * ```tsx\n * <Button variant=\"secondary\" 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","/*\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 { 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 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 { 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 */\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 * 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-4xl);\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.Root[data-variant=\"divided\"] {\n --accordion-gap: 0;\n --accordion-item-border: transparent;\n --accordion-item-radius: 0;\n --accordion-header-radius: var(--lea-radius-xl);\n --accordion-hover-border: transparent;\n --accordion-hover-bg: var(--lea-palette-bg-subtle);\n --accordion-active-bg: var(--lea-color-neutral-100);\n}\n\n.Root[data-variant=\"ghost\"] {\n --accordion-item-border: transparent;\n --accordion-header-radius: var(--lea-radius-xl);\n --accordion-hover-border: transparent;\n --accordion-hover-bg: var(--lea-palette-bg-subtle);\n --accordion-active-bg: var(--lea-color-neutral-100);\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","/*\n * Layout of the consent dialog body. The surface, header and close button\n * come from Dialog; the categories from Accordion; the controls from Switch\n * and Button.\n */\n\n.Intro {\n color: var(--lea-palette-text-base);\n}\n\n.Intro p,\n.Intro ul,\n.Intro ol {\n margin: 0;\n}\n\n.Intro > * + * {\n margin-top: var(--lea-spacing);\n}\n\n.Intro ul,\n.Intro ol {\n padding-inline-start: calc(var(--lea-spacing) * 2.5);\n}\n\n.Intro a {\n border-radius: var(--lea-radius-sm);\n color: var(--lea-palette-text-accent);\n font-weight: var(--lea-font-weight-semibold);\n text-decoration: underline;\n text-underline-offset: 0.15em;\n}\n\n.Intro a:focus-visible {\n outline: 2px solid var(--lea-palette-text-base);\n outline-offset: 0.125rem;\n}\n\n.Categories {\n margin-top: calc(var(--lea-spacing) * 3);\n}\n\n.CategoryDescription {\n margin: 0;\n color: var(--lea-palette-text-base);\n font-size: var(--lea-font-size-md);\n}\n\n.Actions {\n display: flex;\n flex-wrap: wrap;\n margin-top: calc(var(--lea-spacing) * 3);\n gap: var(--lea-spacing);\n border-top: 1px solid var(--lea-palette-border-subtle);\n button {\n border-radius: var(--lea-radius-2xl);\n }\n}\n\n.Save {\n margin-inline-start: auto;\n}\n\n@media (max-width: 599.95px) {\n .Actions {\n flex-direction: column;\n align-items: stretch;\n }\n\n .Save {\n margin-inline-start: 0;\n }\n}\n","import type { ReactNode } from \"react\";\n\nexport interface StrapiTextNode {\n type: \"text\";\n text: string;\n bold?: boolean;\n italic?: boolean;\n underline?: boolean;\n strikethrough?: boolean;\n code?: boolean;\n}\n\nexport interface StrapiLinkNode {\n type: \"link\";\n url: string;\n children: StrapiTextNode[];\n}\n\nexport type StrapiInlineNode = StrapiTextNode | StrapiLinkNode;\n\nexport interface StrapiParagraphNode {\n type: \"paragraph\";\n children: StrapiInlineNode[];\n}\n\nexport interface StrapiHeadingNode {\n type: \"heading\";\n level: 1 | 2 | 3 | 4 | 5 | 6;\n children: StrapiInlineNode[];\n}\n\nexport interface StrapiListItemNode {\n type: \"list-item\";\n children: StrapiInlineNode[];\n}\n\nexport interface StrapiListNode {\n type: \"list\";\n format: \"ordered\" | \"unordered\";\n children: (StrapiListItemNode | StrapiListNode)[];\n}\n\nexport type StrapiBlocksNode =\n | StrapiParagraphNode\n | StrapiHeadingNode\n | StrapiListNode;\n\n/**\n * Rewrites a link's URL, e.g. to make CMS-relative paths absolute. Return\n * `null` or `undefined` to render the link's label as plain text. The result\n * must still be `https:`, `mailto:` or relative to become a link.\n */\nexport type ResolveHref = (href: string) => string | null | undefined;\n\nconst RELATIVE_BASE = \"https://relative.invalid\";\n\n// Not `URL.canParse`, which Safari only has from 17.\nfunction parseUrl(value: string, base?: string): URL | null {\n try {\n return new URL(value, base);\n } catch {\n return null;\n }\n}\n\n/**\n * Allows `https:`, `mailto:` and URLs relative to the current origin. The URL\n * parser strips the whitespace and control characters browsers ignore, so\n * `\" javascript:\"` and `\"java\\tscript:\"` are caught, and a protocol-relative\n * `//host` (or `/\\host`) resolves to a foreign origin and is rejected.\n */\nexport function isSafeHref(href: string): boolean {\n const value = href.trim();\n if (!value) return false;\n\n const absolute = parseUrl(value);\n if (absolute) {\n return absolute.protocol === \"https:\" || absolute.protocol === \"mailto:\";\n }\n\n return parseUrl(value, RELATIVE_BASE)?.origin === RELATIVE_BASE;\n}\n\nexport interface SafeLinkProps {\n href: string;\n resolveHref?: ResolveHref;\n children: ReactNode;\n}\n\n/** A new-tab link, or its label as plain text when the URL isn't allowed. */\nexport function SafeLink({\n href,\n resolveHref = (value) => value,\n children,\n}: SafeLinkProps) {\n const resolved = resolveHref(href);\n if (!resolved || !isSafeHref(resolved)) return <>{children}</>;\n\n return (\n <a href={resolved.trim()} target=\"_blank\" rel=\"noopener noreferrer\">\n {children}\n </a>\n );\n}\n\nfunction Text({ node }: { node: StrapiTextNode }) {\n let content: ReactNode = node.text;\n if (node.underline) content = <u>{content}</u>;\n if (node.italic) content = <em>{content}</em>;\n if (node.bold) content = <strong>{content}</strong>;\n return <>{content}</>;\n}\n\nfunction Inline({\n nodes,\n resolveHref,\n}: {\n nodes: StrapiInlineNode[] | undefined;\n resolveHref?: ResolveHref;\n}) {\n return (\n <>\n {(nodes ?? []).map((node, index) => {\n if (node.type === \"text\") return <Text key={index} node={node} />;\n if (node.type === \"link\") {\n return (\n <SafeLink key={index} href={node.url ?? \"\"} resolveHref={resolveHref}>\n {(node.children ?? [])\n .filter((child) => child.type === \"text\")\n .map((child, childIndex) => (\n <Text key={childIndex} node={child} />\n ))}\n </SafeLink>\n );\n }\n return null;\n })}\n </>\n );\n}\n\nfunction List({\n node,\n resolveHref,\n}: {\n node: StrapiListNode;\n resolveHref?: ResolveHref;\n}) {\n const Tag = node.format === \"ordered\" ? \"ol\" : \"ul\";\n\n return (\n <Tag>\n {(node.children ?? []).map((child, index) => {\n if (child.type === \"list\") {\n return (\n <li key={index}>\n <List node={child} resolveHref={resolveHref} />\n </li>\n );\n }\n if (child.type === \"list-item\") {\n return (\n <li key={index}>\n <Inline nodes={child.children} resolveHref={resolveHref} />\n </li>\n );\n }\n return null;\n })}\n </Tag>\n );\n}\n\nexport interface StrapiBlocksProps {\n nodes: StrapiBlocksNode[];\n resolveHref?: ResolveHref;\n}\n\n/**\n * Renders Strapi Blocks rich text with only `p`, `strong`, `em`, `u`, `ul`,\n * `ol`, `li` and `a`. Headings become a bold paragraph, so they can't break\n * the dialog's heading order; any other node type is dropped.\n */\nexport function StrapiBlocks({ nodes, resolveHref }: StrapiBlocksProps) {\n return (\n <>\n {nodes.map((node, index) => {\n switch (node.type) {\n case \"paragraph\":\n return (\n <p key={index}>\n <Inline nodes={node.children} resolveHref={resolveHref} />\n </p>\n );\n case \"heading\":\n return (\n <p key={index}>\n <strong>\n <Inline nodes={node.children} resolveHref={resolveHref} />\n </strong>\n </p>\n );\n case \"list\":\n return <List key={index} node={node} resolveHref={resolveHref} />;\n default:\n return null;\n }\n })}\n </>\n );\n}\n","\"use client\";\n\nimport { useId, useState } from \"react\";\n\nimport { Button } from \"../components/buttons/button\";\nimport * as Dialog from \"../components/feedback/dialog\";\nimport { Switch } from \"../components/form/switch\";\nimport * as Accordion from \"../components/surfaces/accordion\";\nimport styles from \"./consent-dialog.module.css\";\nimport {\n COOKIE_CONSENT_CATEGORIES,\n type ConsentState,\n type CookieConsentCategory,\n} from \"./constants\";\nimport type { CookieConsentCopy } from \"./copy\";\nimport { StrapiBlocks, type ResolveHref } from \"./strapi-blocks\";\n\nexport interface ConsentDialogProps {\n open: boolean;\n /** The stored choice. While `null`, the dialog can't be dismissed. */\n consent: ConsentState | null;\n copy: CookieConsentCopy;\n resolveHref?: ResolveHref;\n onAcceptAll: () => void;\n onAcceptNecessary: () => void;\n onSave: (categories: CookieConsentCategory[]) => void;\n onClose: () => void;\n}\n\nfunction initialSelection(consent: ConsentState | null): ConsentState {\n return {\n necessary: true,\n preferences: consent?.preferences ?? false,\n analytics: consent?.analytics ?? false,\n marketing: consent?.marketing ?? false,\n };\n}\n\nfunction CategoryRow({\n category,\n copy,\n checked,\n onCheckedChange,\n}: {\n category: CookieConsentCategory;\n copy: CookieConsentCopy;\n checked: boolean;\n onCheckedChange: (checked: boolean) => void;\n}) {\n const titleId = useId();\n const descriptionId = useId();\n const { title, description } = copy.categories[category];\n\n return (\n <Accordion.Item value={category}>\n <Accordion.Header>\n <Accordion.Trigger>\n <span id={titleId}>{title}</span>\n </Accordion.Trigger>\n <Switch\n aria-labelledby={titleId}\n aria-describedby={description ? descriptionId : undefined}\n checked={checked}\n disabled={category === \"necessary\"}\n onCheckedChange={onCheckedChange}\n />\n </Accordion.Header>\n {/* Kept mounted while collapsed so the switch's description resolves. */}\n <Accordion.Panel keepMounted>\n {description && (\n <p id={descriptionId} className={styles.CategoryDescription}>\n {description}\n </p>\n )}\n </Accordion.Panel>\n </Accordion.Item>\n );\n}\n\nexport function ConsentDialog({\n open,\n consent,\n copy,\n resolveHref,\n onAcceptAll,\n onAcceptNecessary,\n onSave,\n onClose,\n}: ConsentDialogProps) {\n const dismissible = consent !== null;\n const [selection, setSelection] = useState(() => initialSelection(consent));\n const [wasOpen, setWasOpen] = useState(open);\n\n if (open !== wasOpen) {\n setWasOpen(open);\n if (open) setSelection(initialSelection(consent));\n }\n\n return (\n <Dialog.Root\n open={open}\n onOpenChange={(next) => {\n if (!next && dismissible) onClose();\n }}\n disablePointerDismissal={!dismissible}\n >\n <Dialog.Portal>\n <Dialog.Backdrop />\n <Dialog.Viewport>\n <Dialog.Popup fullScreenOnMobile size=\"md\">\n <Dialog.Header>\n <Dialog.Title>{copy.modalTitle}</Dialog.Title>\n {dismissible && (\n <Dialog.CloseButton label={copy.closeIconLabel} />\n )}\n </Dialog.Header>\n <Dialog.Content>\n <Dialog.Description render={<div />} className={styles.Intro}>\n <StrapiBlocks nodes={copy.intro} resolveHref={resolveHref} />\n </Dialog.Description>\n\n <Accordion.Root\n variant=\"solid\"\n iconPosition=\"start\"\n multiple\n className={styles.Categories}\n >\n {COOKIE_CONSENT_CATEGORIES.map((category) => (\n <CategoryRow\n key={category}\n category={category}\n copy={copy}\n checked={selection[category]}\n onCheckedChange={(checked) =>\n setSelection((current) => ({\n ...current,\n [category]: checked,\n }))\n }\n />\n ))}\n </Accordion.Root>\n </Dialog.Content>\n <Dialog.Footer className={styles.Actions}>\n <Button onClick={onAcceptAll} color=\"neutral\" size=\"sm\">\n {copy.btnAcceptAll}\n </Button>\n <Button onClick={onAcceptNecessary} color=\"neutral\" size=\"sm\">\n {copy.btnAcceptNecessary}\n </Button>\n <Button\n variant=\"secondary\"\n color=\"neutral\"\n size=\"sm\"\n className={styles.Save}\n onClick={() =>\n onSave(\n COOKIE_CONSENT_CATEGORIES.filter(\n (category) => selection[category],\n ),\n )\n }\n >\n {copy.btnSaveSettings}\n </Button>\n </Dialog.Footer>\n </Dialog.Popup>\n </Dialog.Viewport>\n </Dialog.Portal>\n </Dialog.Root>\n );\n}\n","\"use client\";\n\nimport \"../theme/tokens.css\";\n\nimport {\n createContext,\n useContext,\n useEffect,\n useMemo,\n useSyncExternalStore,\n type ReactNode,\n} from \"react\";\n\nimport { ConsentDialog } from \"./consent-dialog\";\nimport type { ConsentState, Market } from \"./constants\";\nimport type { CookieConsentCopy } from \"./copy\";\nimport {\n closeCookieSettings,\n getServerSnapshot,\n getSnapshot,\n initCookieConsent,\n openCookieSettings,\n setConsent,\n subscribe,\n} from \"./core\";\nimport type { ResolveHref } from \"./strapi-blocks\";\n\nexport interface CookieConsentContextValue {\n /** `null` until the visitor has made a valid choice, and on the server. */\n consent: ConsentState | null;\n openSettings: () => void;\n}\n\nconst CookieConsentContext = createContext<CookieConsentContextValue | null>(\n null,\n);\n\nexport interface CookieConsentProviderProps {\n market: Market;\n copy: CookieConsentCopy;\n /** Rewrites link URLs in the copy, e.g. to make CMS-relative paths absolute. */\n resolveHref?: ResolveHref;\n children?: ReactNode;\n}\n\n/**\n * Reads the shared consent after mount and renders the settings dialog, which\n * opens by itself until the visitor has chosen. `market` is read once.\n */\nexport function CookieConsentProvider({\n market,\n copy,\n resolveHref,\n children,\n}: CookieConsentProviderProps) {\n const { consent, settingsOpen, ready } = useSyncExternalStore(\n subscribe,\n getSnapshot,\n getServerSnapshot,\n );\n\n useEffect(() => {\n initCookieConsent({ market });\n }, []);\n\n const value = useMemo(\n () => ({ consent, openSettings: openCookieSettings }),\n [consent],\n );\n\n return (\n <CookieConsentContext.Provider value={value}>\n {children}\n {ready && (\n <ConsentDialog\n open={settingsOpen}\n consent={consent}\n copy={copy}\n resolveHref={resolveHref}\n onAcceptAll={() => setConsent(\"all\")}\n onAcceptNecessary={() => setConsent([])}\n onSave={setConsent}\n onClose={closeCookieSettings}\n />\n )}\n </CookieConsentContext.Provider>\n );\n}\n\nexport function useCookieConsent(): CookieConsentContextValue {\n const value = useContext(CookieConsentContext);\n if (!value) {\n throw new Error(\n \"useCookieConsent must be used inside a CookieConsentProvider.\",\n );\n }\n return value;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"cookie-consent-react.mjs","names":[],"sources":["../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/dialog.module.css","../src/i18n/language-context.tsx","../src/i18n/create-translation.ts","../src/components/feedback/use-close-label.ts","../src/components/feedback/dialog.tsx","../src/components/form/switch.module.css","../src/components/form/switch.tsx","../src/components/surfaces/accordion.module.css","../src/components/surfaces/accordion.tsx","../src/cookie-consent/consent-dialog.module.css","../src/cookie-consent/strapi-blocks.tsx","../src/cookie-consent/consent-dialog.tsx","../src/cookie-consent/react.tsx"],"sourcesContent":["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",".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 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","/*\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 { 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 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 { 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 */\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 * 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","/*\n * Layout of the consent dialog body. The surface, header and close button\n * come from Dialog; the categories from Accordion; the controls from Switch\n * and Button.\n */\n\n.Intro {\n color: var(--lea-palette-text-base);\n}\n\n.Intro p,\n.Intro ul,\n.Intro ol {\n margin: 0;\n}\n\n.Intro > * + * {\n margin-top: var(--lea-spacing);\n}\n\n.Intro ul,\n.Intro ol {\n padding-inline-start: calc(var(--lea-spacing) * 2.5);\n}\n\n.Intro a {\n border-radius: var(--lea-radius-sm);\n color: var(--lea-palette-text-accent);\n font-weight: var(--lea-font-weight-semibold);\n text-decoration: underline;\n text-underline-offset: 0.15em;\n}\n\n.Intro a:focus-visible {\n outline: 2px solid var(--lea-palette-text-base);\n outline-offset: 0.125rem;\n}\n\n.Categories {\n margin-top: calc(var(--lea-spacing) * 3);\n}\n\n.CategoryDescription {\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.Actions {\n display: flex;\n flex-wrap: wrap;\n margin-top: calc(var(--lea-spacing) * 3);\n gap: var(--lea-spacing);\n border-top: 1px solid var(--lea-palette-border-subtle);\n button {\n border-radius: var(--lea-radius-2xl);\n }\n}\n\n.Save {\n margin-inline-start: auto;\n}\n\n@media (max-width: 599.95px) {\n .Actions {\n flex-direction: column;\n align-items: stretch;\n }\n\n .Save {\n margin-inline-start: 0;\n }\n}\n","import type { ReactNode } from \"react\";\n\nexport interface StrapiTextNode {\n type: \"text\";\n text: string;\n bold?: boolean;\n italic?: boolean;\n underline?: boolean;\n strikethrough?: boolean;\n code?: boolean;\n}\n\nexport interface StrapiLinkNode {\n type: \"link\";\n url: string;\n children: StrapiTextNode[];\n}\n\nexport type StrapiInlineNode = StrapiTextNode | StrapiLinkNode;\n\nexport interface StrapiParagraphNode {\n type: \"paragraph\";\n children: StrapiInlineNode[];\n}\n\nexport interface StrapiHeadingNode {\n type: \"heading\";\n level: 1 | 2 | 3 | 4 | 5 | 6;\n children: StrapiInlineNode[];\n}\n\nexport interface StrapiListItemNode {\n type: \"list-item\";\n children: StrapiInlineNode[];\n}\n\nexport interface StrapiListNode {\n type: \"list\";\n format: \"ordered\" | \"unordered\";\n children: (StrapiListItemNode | StrapiListNode)[];\n}\n\nexport type StrapiBlocksNode =\n | StrapiParagraphNode\n | StrapiHeadingNode\n | StrapiListNode;\n\n/**\n * Rewrites a link's URL, e.g. to make CMS-relative paths absolute. Return\n * `null` or `undefined` to render the link's label as plain text. The result\n * must still be `https:`, `mailto:` or relative to become a link.\n */\nexport type ResolveHref = (href: string) => string | null | undefined;\n\nconst RELATIVE_BASE = \"https://relative.invalid\";\n\n// Not `URL.canParse`, which Safari only has from 17.\nfunction parseUrl(value: string, base?: string): URL | null {\n try {\n return new URL(value, base);\n } catch {\n return null;\n }\n}\n\n/**\n * Allows `https:`, `mailto:` and URLs relative to the current origin. The URL\n * parser strips the whitespace and control characters browsers ignore, so\n * `\" javascript:\"` and `\"java\\tscript:\"` are caught, and a protocol-relative\n * `//host` (or `/\\host`) resolves to a foreign origin and is rejected.\n */\nexport function isSafeHref(href: string): boolean {\n const value = href.trim();\n if (!value) return false;\n\n const absolute = parseUrl(value);\n if (absolute) {\n return absolute.protocol === \"https:\" || absolute.protocol === \"mailto:\";\n }\n\n return parseUrl(value, RELATIVE_BASE)?.origin === RELATIVE_BASE;\n}\n\nexport interface SafeLinkProps {\n href: string;\n resolveHref?: ResolveHref;\n children: ReactNode;\n}\n\n/** A new-tab link, or its label as plain text when the URL isn't allowed. */\nexport function SafeLink({\n href,\n resolveHref = (value) => value,\n children,\n}: SafeLinkProps) {\n const resolved = resolveHref(href);\n if (!resolved || !isSafeHref(resolved)) return <>{children}</>;\n\n return (\n <a href={resolved.trim()} target=\"_blank\" rel=\"noopener noreferrer\">\n {children}\n </a>\n );\n}\n\nfunction Text({ node }: { node: StrapiTextNode }) {\n let content: ReactNode = node.text;\n if (node.underline) content = <u>{content}</u>;\n if (node.italic) content = <em>{content}</em>;\n if (node.bold) content = <strong>{content}</strong>;\n return <>{content}</>;\n}\n\nfunction Inline({\n nodes,\n resolveHref,\n}: {\n nodes: StrapiInlineNode[] | undefined;\n resolveHref?: ResolveHref;\n}) {\n return (\n <>\n {(nodes ?? []).map((node, index) => {\n if (node.type === \"text\") return <Text key={index} node={node} />;\n if (node.type === \"link\") {\n return (\n <SafeLink key={index} href={node.url ?? \"\"} resolveHref={resolveHref}>\n {(node.children ?? [])\n .filter((child) => child.type === \"text\")\n .map((child, childIndex) => (\n <Text key={childIndex} node={child} />\n ))}\n </SafeLink>\n );\n }\n return null;\n })}\n </>\n );\n}\n\nfunction List({\n node,\n resolveHref,\n}: {\n node: StrapiListNode;\n resolveHref?: ResolveHref;\n}) {\n const Tag = node.format === \"ordered\" ? \"ol\" : \"ul\";\n\n return (\n <Tag>\n {(node.children ?? []).map((child, index) => {\n if (child.type === \"list\") {\n return (\n <li key={index}>\n <List node={child} resolveHref={resolveHref} />\n </li>\n );\n }\n if (child.type === \"list-item\") {\n return (\n <li key={index}>\n <Inline nodes={child.children} resolveHref={resolveHref} />\n </li>\n );\n }\n return null;\n })}\n </Tag>\n );\n}\n\nexport interface StrapiBlocksProps {\n nodes: StrapiBlocksNode[];\n resolveHref?: ResolveHref;\n}\n\n/**\n * Renders Strapi Blocks rich text with only `p`, `strong`, `em`, `u`, `ul`,\n * `ol`, `li` and `a`. Headings become a bold paragraph, so they can't break\n * the dialog's heading order; any other node type is dropped.\n */\nexport function StrapiBlocks({ nodes, resolveHref }: StrapiBlocksProps) {\n return (\n <>\n {nodes.map((node, index) => {\n switch (node.type) {\n case \"paragraph\":\n return (\n <p key={index}>\n <Inline nodes={node.children} resolveHref={resolveHref} />\n </p>\n );\n case \"heading\":\n return (\n <p key={index}>\n <strong>\n <Inline nodes={node.children} resolveHref={resolveHref} />\n </strong>\n </p>\n );\n case \"list\":\n return <List key={index} node={node} resolveHref={resolveHref} />;\n default:\n return null;\n }\n })}\n </>\n );\n}\n","\"use client\";\n\nimport { useId, useState } from \"react\";\n\nimport { Button } from \"../components/buttons/button\";\nimport * as Dialog from \"../components/feedback/dialog\";\nimport { Switch } from \"../components/form/switch\";\nimport * as Accordion from \"../components/surfaces/accordion\";\nimport styles from \"./consent-dialog.module.css\";\nimport {\n COOKIE_CONSENT_CATEGORIES,\n type ConsentState,\n type CookieConsentCategory,\n} from \"./constants\";\nimport type { CookieConsentCopy } from \"./copy\";\nimport { StrapiBlocks, type ResolveHref } from \"./strapi-blocks\";\n\nexport interface ConsentDialogProps {\n open: boolean;\n /** The stored choice. While `null`, the dialog can't be dismissed. */\n consent: ConsentState | null;\n copy: CookieConsentCopy;\n resolveHref?: ResolveHref;\n onAcceptAll: () => void;\n onAcceptNecessary: () => void;\n onSave: (categories: CookieConsentCategory[]) => void;\n onClose: () => void;\n}\n\nfunction initialSelection(consent: ConsentState | null): ConsentState {\n return {\n necessary: true,\n preferences: consent?.preferences ?? false,\n analytics: consent?.analytics ?? false,\n marketing: consent?.marketing ?? false,\n };\n}\n\nfunction CategoryRow({\n category,\n copy,\n checked,\n onCheckedChange,\n}: {\n category: CookieConsentCategory;\n copy: CookieConsentCopy;\n checked: boolean;\n onCheckedChange: (checked: boolean) => void;\n}) {\n const titleId = useId();\n const descriptionId = useId();\n const { title, description } = copy.categories[category];\n\n return (\n <Accordion.Item value={category}>\n <Accordion.Header>\n <Accordion.Trigger>\n <span id={titleId}>{title}</span>\n </Accordion.Trigger>\n <Switch\n aria-labelledby={titleId}\n aria-describedby={description ? descriptionId : undefined}\n checked={checked}\n disabled={category === \"necessary\"}\n onCheckedChange={onCheckedChange}\n />\n </Accordion.Header>\n {/* Kept mounted while collapsed so the switch's description resolves. */}\n <Accordion.Panel keepMounted>\n {description && (\n <p id={descriptionId} className={styles.CategoryDescription}>\n {description}\n </p>\n )}\n </Accordion.Panel>\n </Accordion.Item>\n );\n}\n\nexport function ConsentDialog({\n open,\n consent,\n copy,\n resolveHref,\n onAcceptAll,\n onAcceptNecessary,\n onSave,\n onClose,\n}: ConsentDialogProps) {\n const dismissible = consent !== null;\n const [selection, setSelection] = useState(() => initialSelection(consent));\n const [wasOpen, setWasOpen] = useState(open);\n\n if (open !== wasOpen) {\n setWasOpen(open);\n if (open) setSelection(initialSelection(consent));\n }\n\n return (\n <Dialog.Root\n open={open}\n onOpenChange={(next) => {\n if (!next && dismissible) onClose();\n }}\n disablePointerDismissal={!dismissible}\n >\n <Dialog.Portal>\n <Dialog.Backdrop />\n <Dialog.Viewport>\n <Dialog.Popup fullScreenOnMobile size=\"md\">\n <Dialog.Header>\n <Dialog.Title>{copy.modalTitle}</Dialog.Title>\n {dismissible && (\n <Dialog.CloseButton label={copy.closeIconLabel} />\n )}\n </Dialog.Header>\n <Dialog.Content>\n <Dialog.Description render={<div />} className={styles.Intro}>\n <StrapiBlocks nodes={copy.intro} resolveHref={resolveHref} />\n </Dialog.Description>\n\n <Accordion.Root\n variant=\"solid\"\n iconPosition=\"start\"\n multiple\n className={styles.Categories}\n >\n {COOKIE_CONSENT_CATEGORIES.map((category) => (\n <CategoryRow\n key={category}\n category={category}\n copy={copy}\n checked={selection[category]}\n onCheckedChange={(checked) =>\n setSelection((current) => ({\n ...current,\n [category]: checked,\n }))\n }\n />\n ))}\n </Accordion.Root>\n </Dialog.Content>\n <Dialog.Footer className={styles.Actions}>\n <Button onClick={onAcceptAll} color=\"secondary\" size=\"sm\">\n {copy.btnAcceptAll}\n </Button>\n <Button onClick={onAcceptNecessary} color=\"secondary\" size=\"sm\">\n {copy.btnAcceptNecessary}\n </Button>\n <Button\n variant=\"outline\"\n color=\"secondary\"\n size=\"sm\"\n className={styles.Save}\n onClick={() =>\n onSave(\n COOKIE_CONSENT_CATEGORIES.filter(\n (category) => selection[category],\n ),\n )\n }\n >\n {copy.btnSaveSettings}\n </Button>\n </Dialog.Footer>\n </Dialog.Popup>\n </Dialog.Viewport>\n </Dialog.Portal>\n </Dialog.Root>\n );\n}\n","\"use client\";\n\nimport \"../theme/tokens.css\";\n\nimport {\n createContext,\n useContext,\n useEffect,\n useMemo,\n useSyncExternalStore,\n type ReactNode,\n} from \"react\";\n\nimport { ConsentDialog } from \"./consent-dialog\";\nimport type { ConsentState, Market } from \"./constants\";\nimport type { CookieConsentCopy } from \"./copy\";\nimport {\n closeCookieSettings,\n getServerSnapshot,\n getSnapshot,\n initCookieConsent,\n openCookieSettings,\n setConsent,\n subscribe,\n} from \"./core\";\nimport type { ResolveHref } from \"./strapi-blocks\";\n\nexport interface CookieConsentContextValue {\n /** `null` until the visitor has made a valid choice, and on the server. */\n consent: ConsentState | null;\n openSettings: () => void;\n}\n\nconst CookieConsentContext = createContext<CookieConsentContextValue | null>(\n null,\n);\n\nexport interface CookieConsentProviderProps {\n market: Market;\n copy: CookieConsentCopy;\n /** Rewrites link URLs in the copy, e.g. to make CMS-relative paths absolute. */\n resolveHref?: ResolveHref;\n children?: ReactNode;\n}\n\n/**\n * Reads the shared consent after mount and renders the settings dialog, which\n * opens by itself until the visitor has chosen. `market` is read once.\n */\nexport function CookieConsentProvider({\n market,\n copy,\n resolveHref,\n children,\n}: CookieConsentProviderProps) {\n const { consent, settingsOpen, ready } = useSyncExternalStore(\n subscribe,\n getSnapshot,\n getServerSnapshot,\n );\n\n useEffect(() => {\n initCookieConsent({ market });\n }, []);\n\n const value = useMemo(\n () => ({ consent, openSettings: openCookieSettings }),\n [consent],\n );\n\n return (\n <CookieConsentContext.Provider value={value}>\n {children}\n {ready && (\n <ConsentDialog\n open={settingsOpen}\n consent={consent}\n copy={copy}\n resolveHref={resolveHref}\n onAcceptAll={() => setConsent(\"all\")}\n onAcceptNecessary={() => setConsent([])}\n onSave={setConsent}\n onClose={closeCookieSettings}\n />\n )}\n </CookieConsentContext.Provider>\n );\n}\n\nexport function useCookieConsent(): CookieConsentContextValue {\n const value = useContext(CookieConsentContext);\n if (!value) {\n throw new Error(\n \"useCookieConsent must be used inside a CookieConsentProvider.\",\n );\n }\n return value;\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- :root{--lea-spacing:.5rem;--lea-palette-bg-base:#fff;--lea-palette-bg-subtle:#f7f7f6;--lea-palette-bg-muted:#f0e9e5;--lea-palette-bg-contrast:#0f1010;--lea-palette-bg-accent:#e2d8e4;--lea-palette-text-base:#0f1010;--lea-palette-text-subtle:#757575;--lea-palette-text-muted:#a2a2a2;--lea-palette-text-accent:#70427b;--lea-palette-text-contrast:#fff;--lea-palette-border-base:#dbdbdb;--lea-palette-border-subtle:#ebebeb;--lea-palette-border-strong:#0f1010;--lea-palette-border-accent:#70427b;--lea-palette-border-contrast:#fff;--lea-palette-primary-main:#70427b;--lea-palette-primary-dark:#5a3463;--lea-palette-primary-light:#e2d8e4;--lea-palette-primary-contrastText:#fff;--lea-palette-purple-base:#70427b;--lea-palette-purple-hover:#5a3463;--lea-palette-purple-subtle:#e2d8e4;--lea-palette-purple-contrast:#fff;--lea-palette-teal-base:#08c2a7;--lea-palette-teal-hover:#46d1bd;--lea-palette-teal-subtle:#daf6f1;--lea-palette-teal-contrast:#fff;--lea-palette-secondary-main:#08c2a7;--lea-palette-secondary-dark:#46d1bd;--lea-palette-secondary-light:#daf6f1;--lea-palette-secondary-contrastText:#fff;--lea-palette-status-error-base:#d32f2f;--lea-palette-status-error-subtle:#fcdcdc;--lea-palette-status-warning-base:#fe653e;--lea-palette-status-warning-subtle:#ffdfd7;--lea-palette-status-info-base:#057ef2;--lea-palette-status-info-subtle:#cbe5fd;--lea-palette-status-success-base:#46d1bd;--lea-palette-status-success-subtle:#daf6f1;--lea-color-purple-50:#faf7fb;--lea-color-purple-100:#e2d8e4;--lea-color-purple-200:#c5b1ca;--lea-color-purple-300:#c29ac2;--lea-color-purple-400:#9e6da8;--lea-color-purple-500:#855888;--lea-color-purple-600:#70427b;--lea-color-purple-700:#5a3463;--lea-color-purple-800:#422349;--lea-color-purple-900:#2e1834;--lea-color-purple-950:#1a0e1e;--lea-color-teal-50:#f0fcfa;--lea-color-teal-100:#daf6f1;--lea-color-teal-200:#cef3ed;--lea-color-teal-300:#08c2a7;--lea-color-teal-400:#46d1bd;--lea-color-teal-500:#06a892;--lea-color-teal-600:#058f7d;--lea-color-teal-700:#047568;--lea-color-teal-800:#035c53;--lea-color-teal-900:#02433e;--lea-color-teal-950:#012a28;--lea-color-blue-50:#eff6ff;--lea-color-blue-100:#cbe5fd;--lea-color-blue-200:#93cbfc;--lea-color-blue-300:#4da8f7;--lea-color-blue-400:#057ef2;--lea-color-blue-500:#0468c9;--lea-color-blue-600:#0354a3;--lea-color-blue-700:#02417d;--lea-color-blue-800:#012e57;--lea-color-blue-900:#011b31;--lea-color-blue-950:#000e19;--lea-color-orange-50:#fff5f2;--lea-color-orange-100:#ffdfd7;--lea-color-orange-200:#ffc4b5;--lea-color-orange-300:#ff9e87;--lea-color-orange-400:#fe653e;--lea-color-orange-500:#e54e28;--lea-color-orange-600:#c43e1c;--lea-color-orange-700:#a33218;--lea-color-orange-800:#822814;--lea-color-orange-900:#611e0f;--lea-color-orange-950:#401408;--lea-color-red-50:#fef2f2;--lea-color-red-100:#fcdcdc;--lea-color-red-200:#f9bbbb;--lea-color-red-300:#f28888;--lea-color-red-400:#e85555;--lea-color-red-500:#d32f2f;--lea-color-red-600:#ad2121;--lea-color-red-700:#8a1919;--lea-color-red-800:#6f1313;--lea-color-red-900:#4d0e0e;--lea-color-red-950:#2e0808;--lea-color-beige-50:#faf7f5;--lea-color-beige-100:#f0e9e5;--lea-color-beige-200:#e0d4cd;--lea-color-beige-300:#c9b8ad;--lea-color-beige-400:#b09a8c;--lea-color-beige-500:#977c6b;--lea-color-beige-600:#7e6556;--lea-color-beige-700:#654f42;--lea-color-beige-800:#4c3a32;--lea-color-beige-900:#332722;--lea-color-beige-950:#1a1411;--lea-color-neutral-50:#f7f7f6;--lea-color-neutral-100:#ebebeb;--lea-color-neutral-200:#dbdbdb;--lea-color-neutral-300:#c4c4c4;--lea-color-neutral-400:#a2a2a2;--lea-color-neutral-500:#757575;--lea-color-neutral-600:#5e5e5e;--lea-color-neutral-700:#454545;--lea-color-neutral-800:#2e2e2e;--lea-color-neutral-900:#1a1a1a;--lea-color-neutral-950:#0f1010;--lea-color-white:#fff;--lea-color-black:#0f1010;--lea-radius-sm:4px;--lea-radius-md:5px;--lea-radius-lg:6px;--lea-radius-xl:8px;--lea-radius-2xl:10px;--lea-radius-3xl:12px;--lea-radius-4xl:16px;--lea-radius-5xl:32px;--lea-radius-huge:64px;--lea-radius-full:100px;--lea-shadow-xs:0 1px 2px 0 #0000000d;--lea-shadow-sm:0px 1px 3px 0px #0000001a, 0px 1px 2px -1px #0000001a;--lea-shadow-md:0px 4px 6px -1px #0000001a, 0px 2px 4px -2px #0000001a;--lea-shadow-lg:0px 10px 15px -3px #0000001a, 0px 4px 6px -4px #0000001a;--lea-shadow-xl:0px 20px 25px -5px #0000001a, 0px 8px 10px -6px #0000001a;--lea-shadow-2xl:0px 25px 50px -12px #00000040;--lea-shadow-inner:0px 2px 4px 0px #0000000d inset;--lea-font-size-xs:.75rem;--lea-font-size-sm:.875rem;--lea-font-size-md:1rem;--lea-font-size-lg:1.25rem;--lea-font-size-xl:1.5rem;--lea-font-size-2xl:2rem;--lea-font-size-3xl:2.5rem;--lea-font-size-4xl:3rem;--lea-font-size-5xl:3.5rem;--lea-font-size-6xl:4rem;--lea-font-weight-thin:200;--lea-font-weight-light:300;--lea-font-weight-regular:400;--lea-font-weight-medium:500;--lea-font-weight-semibold:600;--lea-font-weight-bold:700;--lea-font-weight-black:800;--lea-duration-fast:.15s;--lea-duration-normal:.2s;--lea-duration-emphasis:.3s;--lea-easing-standard:ease-in-out;--lea-easing-spring:cubic-bezier(.34, 1.56, .64, 1);--lea-breakpoint-xs:0px;--lea-breakpoint-sm:600px;--lea-breakpoint-md:900px;--lea-breakpoint-lg:1200px;--lea-breakpoint-xl:1536px}._Button_10ggi_9{--button-solid:var(--lea-palette-purple-base);--button-solid-hover:var(--lea-palette-purple-hover);--button-on-solid:var(--lea-palette-purple-contrast);--button-tint:var(--lea-palette-purple-subtle);--button-fg:var(--lea-palette-purple-base);--button-border:var(--lea-palette-purple-base);--button-height:2.75rem;--button-icon-size:1.25rem;--button-padding-inline:calc(var(--lea-spacing) * 2.5);box-sizing:border-box;min-height:var(--button-height);justify-content:center;align-items:center;gap:var(--lea-spacing);padding-block:calc(var(--lea-spacing) * .5);padding-inline:var(--button-padding-inline);border-radius:var(--lea-radius-full);color:var(--button-fg);font-family:inherit;font-size:var(--lea-font-size-md);font-weight:var(--lea-font-weight-medium);text-align:center;cursor:pointer;-webkit-user-select:none;user-select:none;-webkit-tap-highlight-color:transparent;transition:background-color var(--lea-duration-normal) var(--lea-easing-standard), border-color var(--lea-duration-normal) var(--lea-easing-standard), color var(--lea-duration-normal) var(--lea-easing-standard), opacity var(--lea-duration-normal) var(--lea-easing-standard);background-color:#0000;border:1px solid #0000;flex-shrink:0;margin:0;line-height:1.25;text-decoration:none;display:inline-flex}._Button_10ggi_9 svg{width:var(--button-icon-size);height:var(--button-icon-size);flex-shrink:0}._Button_10ggi_9:focus-visible{outline:2px solid var(--lea-palette-text-base);outline-offset:.125rem}._Button_10ggi_9[data-color=neutral]{--button-solid:var(--lea-palette-bg-contrast);--button-solid-hover:var(--lea-color-neutral-800);--button-on-solid:var(--lea-palette-text-contrast);--button-tint:var(--lea-palette-bg-subtle);--button-fg:var(--lea-palette-text-base);--button-border:var(--lea-palette-border-strong)}._Button_10ggi_9[data-color=danger]{--button-solid:var(--lea-color-red-600);--button-solid-hover:var(--lea-color-red-500);--button-on-solid:var(--lea-palette-text-contrast);--button-tint:var(--lea-palette-status-error-subtle);--button-fg:var(--lea-color-red-600);--button-border:var(--lea-color-red-600)}._Button_10ggi_9[data-variant=primary]{background-color:var(--button-solid);color:var(--button-on-solid)}._Button_10ggi_9[data-variant=secondary]{border-color:var(--button-border)}@media (hover:hover){._Button_10ggi_9[data-variant=primary]:not([data-disabled]):hover{background-color:var(--button-solid-hover)}._Button_10ggi_9[data-variant=secondary]:not([data-disabled]):hover,._Button_10ggi_9[data-variant=tertiary]:not([data-disabled]):hover{background-color:var(--button-tint)}}._Button_10ggi_9[data-size=sm]{--button-height:2.25rem;--button-icon-size:1rem;--button-padding-inline:calc(var(--lea-spacing) * 2)}._Button_10ggi_9[data-size=lg]{--button-height:3.25rem;--button-icon-size:1.5rem;--button-padding-inline:calc(var(--lea-spacing) * 2.5)}._Button_10ggi_9[data-start-icon]{padding-inline-start:calc(var(--button-padding-inline) - var(--lea-spacing))}._Button_10ggi_9[data-end-icon]{padding-inline-end:calc(var(--button-padding-inline) - var(--lea-spacing))}._Button_10ggi_9._IconButton_10ggi_132{width:var(--button-height);height:var(--button-height);padding:0}._Button_10ggi_9[data-disabled]:not([data-loading]){color:var(--lea-color-neutral-400);cursor:not-allowed}._Button_10ggi_9[data-variant=primary][data-disabled]:not([data-loading]){background-color:var(--lea-color-neutral-200);color:var(--lea-color-neutral-600)}._Button_10ggi_9[data-variant=secondary][data-disabled]:not([data-loading]){border-color:var(--lea-palette-border-base)}._Button_10ggi_9[data-loading]{cursor:progress;opacity:.7}._Spinner_10ggi_159{box-sizing:border-box;width:var(--button-icon-size);height:var(--button-icon-size);border:2px solid;border-radius:var(--lea-radius-full);border-inline-end-color:#0000;flex-shrink:0;animation:.8s linear infinite _button-spin_10ggi_1;display:inline-block}@keyframes _button-spin_10ggi_1{to{rotate:360deg}}._SrOnly_10ggi_177{clip-path:inset(50%);white-space:nowrap;border:0;width:1px;height:1px;margin:-1px;padding:0;position:absolute;overflow:hidden}@media (prefers-reduced-motion:reduce){._Button_10ggi_9{transition-duration:.01ms}._Spinner_10ggi_159{animation:none}}._Backdrop_1tudt_8{z-index:1300;opacity:1;transition:opacity var(--lea-duration-normal) var(--lea-easing-standard);background-color:#0f101080;position:fixed;inset:0}._Backdrop_1tudt_8[data-starting-style],._Backdrop_1tudt_8[data-ending-style]{opacity:0}._Viewport_1tudt_22{z-index:1300;padding:calc(var(--lea-spacing) * 2);pointer-events:none;justify-content:center;align-items:center;display:flex;position:fixed;inset:0}._Popup_1tudt_38{border-radius:var(--lea-radius-4xl);background-color:var(--lea-palette-bg-base);width:100%;max-height:100%;box-shadow:var(--lea-shadow-xl);color:var(--lea-palette-text-base);opacity:1;pointer-events:auto;transition:opacity var(--lea-duration-normal) var(--lea-easing-standard), transform var(--lea-duration-normal) var(--lea-easing-standard);flex-direction:column;display:flex;overflow:hidden;transform:scale(1)}._Popup_1tudt_38[data-starting-style],._Popup_1tudt_38[data-ending-style]{opacity:0;transform:scale(.95)}._Popup_1tudt_38[data-size=xs]{max-width:27.75rem}._Popup_1tudt_38[data-size=sm]{max-width:37.5rem}._Popup_1tudt_38[data-size=md]{max-width:56.25rem}._Popup_1tudt_38[data-size=lg]{max-width:75rem}._Header_1tudt_78{justify-content:space-between;align-items:flex-start;gap:var(--lea-spacing);padding:calc(var(--lea-spacing) * 3) calc(var(--lea-spacing) * 3) calc(var(--lea-spacing) * 2);flex-shrink:0;display:flex}._Title_1tudt_88{color:var(--lea-palette-text-base);font-size:var(--lea-font-size-lg);font-weight:var(--lea-font-weight-semibold);margin:0;line-height:1.4}._Description_1tudt_96{margin:0 0 calc(var(--lea-spacing) * 2);color:var(--lea-palette-text-subtle)}._Description_1tudt_96[data-last]{margin-bottom:0}._Content_1tudt_110{padding:0 calc(var(--lea-spacing) * 3) calc(var(--lea-spacing) * 3);color:var(--lea-palette-text-base);flex:1;overflow-y:auto}._Content_1tudt_110:has(+._Footer_1tudt_118){padding-bottom:0}._Footer_1tudt_118{justify-content:flex-end;align-items:center;gap:var(--lea-spacing);padding:calc(var(--lea-spacing) * 2) calc(var(--lea-spacing) * 3) calc(var(--lea-spacing) * 2);background-color:var(--lea-palette-bg-base);flex-wrap:wrap;flex-shrink:0;display:flex}._CloseButton_1tudt_134{border:2px solid var(--lea-palette-border-base);border-radius:var(--lea-radius-full);width:2.5rem;height:2.5rem;color:var(--lea-palette-text-base);cursor:pointer;transition:border-color var(--lea-duration-emphasis) var(--lea-easing-spring), background-color var(--lea-duration-emphasis) var(--lea-easing-spring), color var(--lea-duration-emphasis) var(--lea-easing-spring);background-color:#0000;flex-shrink:0;justify-content:center;align-items:center;margin-inline-end:calc(var(--lea-spacing) * -.5);padding:0;display:inline-flex}@media (hover:hover){._CloseButton_1tudt_134:hover{border-color:var(--lea-palette-purple-base);background-color:var(--lea-palette-purple-base);color:var(--lea-palette-purple-contrast)}}._CloseButton_1tudt_134:focus-visible{outline:2px solid var(--lea-palette-text-base);outline-offset:.125rem}@media (width<=599.95px){._Viewport_1tudt_22:has(._Popup_1tudt_38[data-full-screen-on-mobile]){padding:0}._Popup_1tudt_38[data-full-screen-on-mobile]{border-radius:0;width:100vw;max-width:none;height:100dvh;max-height:none}._Popup_1tudt_38[data-full-screen-on-mobile] ._Content_1tudt_110{padding-bottom:calc(var(--lea-spacing) * 3 + env(safe-area-inset-bottom))}._Popup_1tudt_38[data-full-screen-on-mobile] ._Content_1tudt_110:has(+._Footer_1tudt_118){padding-bottom:0}._Popup_1tudt_38[data-full-screen-on-mobile] ._Footer_1tudt_118{padding-bottom:calc(var(--lea-spacing) * 3 + env(safe-area-inset-bottom))}}@media (prefers-reduced-motion:reduce){._Backdrop_1tudt_8,._Popup_1tudt_38,._CloseButton_1tudt_134{transition-duration:.01ms}}._Switch_d3xdl_7{border-radius:var(--lea-radius-full);background-color:var(--lea-color-neutral-200);cursor:pointer;width:2.5rem;height:1.5rem;transition:background-color var(--lea-duration-normal) var(--lea-easing-standard);border:none;flex-shrink:0;align-items:center;padding:.125rem;display:inline-flex}._Switch_d3xdl_7[data-checked]{background-color:var(--lea-palette-purple-base)}._Switch_d3xdl_7:focus-visible{outline:2px solid var(--lea-palette-text-base);outline-offset:.125rem}._Switch_d3xdl_7[data-disabled]{cursor:not-allowed;opacity:.5}._Thumb_d3xdl_36{border-radius:var(--lea-radius-full);background-color:var(--lea-palette-bg-base);width:1.25rem;height:1.25rem;transition:translate var(--lea-duration-normal) var(--lea-easing-standard);display:block}._Thumb_d3xdl_36[data-checked]{translate:1rem}@media (prefers-reduced-motion:reduce){._Switch_d3xdl_7,._Thumb_d3xdl_36{transition-duration:.01ms}}._Root_1ps0p_13{--accordion-gap:var(--lea-spacing);--accordion-item-bg:transparent;--accordion-item-border:var(--lea-palette-border-subtle);--accordion-item-radius:var(--lea-radius-2xl);--accordion-header-radius:var(--lea-radius-4xl);--accordion-hover-border:var(--lea-palette-border-strong);--accordion-hover-bg:transparent;--accordion-active-bg:var(--lea-color-purple-50);gap:var(--accordion-gap);flex-direction:column;width:100%;display:flex}._Root_1ps0p_13[data-variant=solid]{--accordion-item-bg:var(--lea-palette-bg-subtle);--accordion-item-border:transparent;--accordion-hover-border:transparent;--accordion-hover-bg:var(--lea-color-neutral-100);--accordion-active-bg:var(--lea-color-neutral-200)}._Root_1ps0p_13[data-variant=divided]{--accordion-gap:0;--accordion-item-border:transparent;--accordion-item-radius:0;--accordion-header-radius:var(--lea-radius-xl);--accordion-hover-border:transparent;--accordion-hover-bg:var(--lea-palette-bg-subtle);--accordion-active-bg:var(--lea-color-neutral-100)}._Root_1ps0p_13[data-variant=ghost]{--accordion-item-border:transparent;--accordion-header-radius:var(--lea-radius-xl);--accordion-hover-border:transparent;--accordion-hover-bg:var(--lea-palette-bg-subtle);--accordion-active-bg:var(--lea-color-neutral-100)}._Item_1ps0p_10{border:1px solid var(--accordion-item-border);border-radius:var(--accordion-item-radius);background-color:var(--accordion-item-bg)}._Root_1ps0p_13[data-variant=divided]>._Item_1ps0p_10:not(:last-child){border-block-end-color:var(--lea-palette-border-subtle)}._Header_1ps0p_10{align-items:center;gap:calc(var(--lea-spacing) * 2);padding:calc(var(--lea-spacing) * 1.7) calc(var(--lea-spacing) * 2);border-radius:var(--accordion-header-radius);transition:border-color var(--lea-duration-emphasis) var(--lea-easing-standard), background-color var(--lea-duration-emphasis) var(--lea-easing-standard);border:1px solid #0000;margin:0;display:flex}@media (hover:hover){._Header_1ps0p_10:has(._Trigger_1ps0p_83:hover:not([data-disabled])){border-color:var(--accordion-hover-border);background-color:var(--accordion-hover-bg)}}._Header_1ps0p_10:has(._Trigger_1ps0p_83:active:not([data-disabled])){background-color:var(--accordion-active-bg)}._Trigger_1ps0p_83{justify-content:space-between;align-items:center;gap:var(--lea-spacing);min-width:0;color:var(--lea-palette-text-base);cursor:pointer;font-family:inherit;font-size:var(--lea-font-size-md);font-weight:var(--lea-font-weight-medium);text-align:left;background-color:#0000;border:none;flex:1;margin:0;padding:0;line-height:1.5;display:flex}._Trigger_1ps0p_83:focus-visible{outline:2px solid var(--lea-palette-text-base);outline-offset:.125rem}._Trigger_1ps0p_83[data-disabled]{color:var(--lea-palette-text-muted);cursor:not-allowed}._Label_1ps0p_123{min-width:0}._Icon_1ps0p_127{transition:transform var(--lea-duration-emphasis) var(--lea-easing-standard);flex-shrink:0}._Trigger_1ps0p_83[data-panel-open] ._Icon_1ps0p_127{transform:rotate(180deg)}._Root_1ps0p_13[data-icon-position=start] ._Trigger_1ps0p_83{justify-content:flex-start}._Root_1ps0p_13[data-icon-position=start] ._Icon_1ps0p_127{order:-1}._Panel_1ps0p_145{height:var(--accordion-panel-height);transition:height var(--lea-duration-emphasis) var(--lea-easing-standard);overflow:hidden}._Panel_1ps0p_145[data-starting-style],._Panel_1ps0p_145[data-ending-style]{height:0}._Content_1ps0p_156{padding-inline:calc(var(--lea-spacing) * 2);padding-block:var(--lea-spacing);color:var(--lea-palette-text-base);font-size:var(--lea-font-size-md);line-height:1.5}@media (prefers-reduced-motion:reduce){._Header_1ps0p_10,._Icon_1ps0p_127,._Panel_1ps0p_145{transition-duration:.01ms}}._Intro_1lxh4_7{color:var(--lea-palette-text-base)}._Intro_1lxh4_7 p,._Intro_1lxh4_7 ul,._Intro_1lxh4_7 ol{margin:0}._Intro_1lxh4_7>*+*{margin-top:var(--lea-spacing)}._Intro_1lxh4_7 ul,._Intro_1lxh4_7 ol{padding-inline-start:calc(var(--lea-spacing) * 2.5)}._Intro_1lxh4_7 a{border-radius:var(--lea-radius-sm);color:var(--lea-palette-text-accent);font-weight:var(--lea-font-weight-semibold);text-underline-offset:.15em;text-decoration:underline}._Intro_1lxh4_7 a:focus-visible{outline:2px solid var(--lea-palette-text-base);outline-offset:.125rem}._Categories_1lxh4_39{margin-top:calc(var(--lea-spacing) * 3)}._CategoryDescription_1lxh4_43{color:var(--lea-palette-text-base);font-size:var(--lea-font-size-md);margin:0}._Actions_1lxh4_49{margin-top:calc(var(--lea-spacing) * 3);gap:var(--lea-spacing);border-top:1px solid var(--lea-palette-border-subtle);flex-wrap:wrap;display:flex}._Actions_1lxh4_49 button{border-radius:var(--lea-radius-2xl)}._Save_1lxh4_60{margin-inline-start:auto}@media (width<=599.95px){._Actions_1lxh4_49{flex-direction:column;align-items:stretch}._Save_1lxh4_60{margin-inline-start:0}}
1
+ :root{--lea-spacing:.5rem;--lea-spacing-0-5:.25rem;--lea-spacing-1:.5rem;--lea-spacing-1-5:.75rem;--lea-spacing-2:1rem;--lea-spacing-2-5:1.25rem;--lea-spacing-3:1.5rem;--lea-spacing-4:2rem;--lea-spacing-5:2.5rem;--lea-spacing-6:3rem;--lea-spacing-8:4rem;--lea-palette-bg-base:#fff;--lea-palette-bg-subtle:#f7f7f6;--lea-palette-bg-muted:#f0e9e5;--lea-palette-bg-contrast:#0f1010;--lea-palette-bg-accent:#e2d8e4;--lea-palette-bg-overlay:#0f101080;--lea-palette-text-base:#0f1010;--lea-palette-text-subtle:#757575;--lea-palette-text-muted:#a2a2a2;--lea-palette-text-accent:#70427b;--lea-palette-text-contrast:#fff;--lea-palette-border-base:#dbdbdb;--lea-palette-border-subtle:#ebebeb;--lea-palette-border-strong:#0f1010;--lea-palette-border-accent:#70427b;--lea-palette-border-contrast:#fff;--lea-palette-primary-base:#70427b;--lea-palette-primary-hover:#5a3463;--lea-palette-primary-subtle:#e2d8e4;--lea-palette-primary-contrast:#fff;--lea-palette-secondary-base:#0f1010;--lea-palette-secondary-hover:#2e2e2e;--lea-palette-secondary-subtle:#ebebeb;--lea-palette-secondary-contrast:#fff;--lea-palette-tertiary-base:#08c2a7;--lea-palette-tertiary-hover:#46d1bd;--lea-palette-tertiary-subtle:#daf6f1;--lea-palette-tertiary-contrast:#fff;--lea-palette-status-error-base:#d32f2f;--lea-palette-status-error-subtle:#fcdcdc;--lea-palette-status-warning-base:#f7a800;--lea-palette-status-warning-subtle:#ffefc7;--lea-palette-status-info-base:#057ef2;--lea-palette-status-info-subtle:#cbe5fd;--lea-palette-status-success-base:#46d1bd;--lea-palette-status-success-subtle:#daf6f1;--lea-color-purple-50:#faf7fb;--lea-color-purple-100:#e2d8e4;--lea-color-purple-200:#c5b1ca;--lea-color-purple-300:#c29ac2;--lea-color-purple-400:#9e6da8;--lea-color-purple-500:#855888;--lea-color-purple-600:#70427b;--lea-color-purple-700:#5a3463;--lea-color-purple-800:#422349;--lea-color-purple-900:#2e1834;--lea-color-purple-950:#1a0e1e;--lea-color-teal-50:#f0fcfa;--lea-color-teal-100:#daf6f1;--lea-color-teal-200:#cef3ed;--lea-color-teal-300:#08c2a7;--lea-color-teal-400:#46d1bd;--lea-color-teal-500:#06a892;--lea-color-teal-600:#058f7d;--lea-color-teal-700:#047568;--lea-color-teal-800:#035c53;--lea-color-teal-900:#02433e;--lea-color-teal-950:#012a28;--lea-color-blue-50:#eff6ff;--lea-color-blue-100:#cbe5fd;--lea-color-blue-200:#93cbfc;--lea-color-blue-300:#4da8f7;--lea-color-blue-400:#057ef2;--lea-color-blue-500:#0468c9;--lea-color-blue-600:#0354a3;--lea-color-blue-700:#02417d;--lea-color-blue-800:#012e57;--lea-color-blue-900:#011b31;--lea-color-blue-950:#000e19;--lea-color-orange-50:#fff5f2;--lea-color-orange-100:#ffdfd7;--lea-color-orange-200:#ffc4b5;--lea-color-orange-300:#ff9e87;--lea-color-orange-400:#fe653e;--lea-color-orange-500:#e54e28;--lea-color-orange-600:#c43e1c;--lea-color-orange-700:#a33218;--lea-color-orange-800:#822814;--lea-color-orange-900:#611e0f;--lea-color-orange-950:#401408;--lea-color-amber-50:#fff9eb;--lea-color-amber-100:#ffefc7;--lea-color-amber-200:#ffe299;--lea-color-amber-300:#ffcf5c;--lea-color-amber-400:#f7a800;--lea-color-amber-500:#d98f00;--lea-color-amber-600:#b37400;--lea-color-amber-700:#8c5a00;--lea-color-amber-800:#6b4500;--lea-color-amber-900:#4a3000;--lea-color-amber-950:#2e1d00;--lea-color-red-50:#fef2f2;--lea-color-red-100:#fcdcdc;--lea-color-red-200:#f9bbbb;--lea-color-red-300:#f28888;--lea-color-red-400:#e85555;--lea-color-red-500:#d32f2f;--lea-color-red-600:#ad2121;--lea-color-red-700:#8a1919;--lea-color-red-800:#6f1313;--lea-color-red-900:#4d0e0e;--lea-color-red-950:#2e0808;--lea-color-beige-50:#faf7f5;--lea-color-beige-100:#f0e9e5;--lea-color-beige-200:#e0d4cd;--lea-color-beige-300:#c9b8ad;--lea-color-beige-400:#b09a8c;--lea-color-beige-500:#977c6b;--lea-color-beige-600:#7e6556;--lea-color-beige-700:#654f42;--lea-color-beige-800:#4c3a32;--lea-color-beige-900:#332722;--lea-color-beige-950:#1a1411;--lea-color-neutral-50:#f7f7f6;--lea-color-neutral-100:#ebebeb;--lea-color-neutral-200:#dbdbdb;--lea-color-neutral-300:#c4c4c4;--lea-color-neutral-400:#a2a2a2;--lea-color-neutral-500:#757575;--lea-color-neutral-600:#5e5e5e;--lea-color-neutral-700:#454545;--lea-color-neutral-800:#2e2e2e;--lea-color-neutral-900:#1a1a1a;--lea-color-neutral-950:#0f1010;--lea-color-white:#fff;--lea-color-black:#0f1010;--lea-radius-sm:4px;--lea-radius-md:5px;--lea-radius-lg:6px;--lea-radius-xl:8px;--lea-radius-2xl:10px;--lea-radius-3xl:12px;--lea-radius-4xl:16px;--lea-radius-5xl:32px;--lea-radius-huge:64px;--lea-radius-full:100px;--lea-shadow-xs:0 1px 2px 0 #0000000d;--lea-shadow-sm:0px 1px 3px 0px #0000001a, 0px 1px 2px -1px #0000001a;--lea-shadow-md:0px 4px 6px -1px #0000001a, 0px 2px 4px -2px #0000001a;--lea-shadow-lg:0px 10px 15px -3px #0000001a, 0px 4px 6px -4px #0000001a;--lea-shadow-xl:0px 20px 25px -5px #0000001a, 0px 8px 10px -6px #0000001a;--lea-shadow-2xl:0px 25px 50px -12px #00000040;--lea-shadow-inner:0px 2px 4px 0px #0000000d inset;--lea-font-family:"ClashGrotesk", "ClashGrotesk Fallback", sans-serif;--lea-font-size-xs:.75rem;--lea-font-size-sm:.875rem;--lea-font-size-md:1rem;--lea-font-size-lg:1.25rem;--lea-font-size-xl:1.5rem;--lea-font-size-2xl:2rem;--lea-font-size-3xl:2.5rem;--lea-font-size-4xl:3rem;--lea-font-size-5xl:3.5rem;--lea-font-size-6xl:4rem;--lea-font-weight-thin:200;--lea-font-weight-light:300;--lea-font-weight-regular:400;--lea-font-weight-medium:500;--lea-font-weight-semibold:600;--lea-font-weight-bold:700;--lea-font-weight-black:800;--lea-font-step-minus-2:.8125rem;--lea-font-step-minus-1:.875rem;--lea-font-step-0:1rem;--lea-font-step-1:1.125rem;--lea-font-step-2:1.25rem;--lea-font-step-3:1.4375rem;--lea-font-step-4:1.625rem;--lea-font-step-5:1.8125rem;--lea-font-step-6:2rem;--lea-font-step-7:2.25rem;--lea-font-step-8:2.5625rem;--lea-font-step-9:2.875rem;--lea-font-step-10:3.25rem;--lea-font-step-11:3.625rem;--lea-font-step-12:4.125rem;--lea-line-height-none:1;--lea-line-height-tight:1.25;--lea-line-height-snug:1.4;--lea-line-height-normal:1.5;--lea-text-display-sm-font-size:var(--lea-font-step-10);--lea-text-display-sm-font-weight:var(--lea-font-weight-semibold);--lea-text-display-sm-line-height:var(--lea-line-height-none);--lea-text-display-sm-letter-spacing:0;--lea-text-display-md-font-size:var(--lea-font-step-12);--lea-text-display-md-font-weight:var(--lea-font-weight-semibold);--lea-text-display-md-line-height:var(--lea-line-height-none);--lea-text-display-md-letter-spacing:0;--lea-text-heading-xs-font-size:var(--lea-font-step-0);--lea-text-heading-xs-font-weight:var(--lea-font-weight-semibold);--lea-text-heading-xs-line-height:var(--lea-line-height-snug);--lea-text-heading-xs-letter-spacing:0;--lea-text-heading-sm-font-size:var(--lea-font-step-2);--lea-text-heading-sm-font-weight:var(--lea-font-weight-semibold);--lea-text-heading-sm-line-height:var(--lea-line-height-snug);--lea-text-heading-sm-letter-spacing:0;--lea-text-heading-md-font-size:var(--lea-font-step-4);--lea-text-heading-md-font-weight:var(--lea-font-weight-semibold);--lea-text-heading-md-line-height:var(--lea-line-height-snug);--lea-text-heading-md-letter-spacing:0;--lea-text-heading-lg-font-size:var(--lea-font-step-6);--lea-text-heading-lg-font-weight:var(--lea-font-weight-semibold);--lea-text-heading-lg-line-height:var(--lea-line-height-tight);--lea-text-heading-lg-letter-spacing:0;--lea-text-heading-xl-font-size:var(--lea-font-step-8);--lea-text-heading-xl-font-weight:var(--lea-font-weight-semibold);--lea-text-heading-xl-line-height:var(--lea-line-height-tight);--lea-text-heading-xl-letter-spacing:0;--lea-text-body-xs-font-size:var(--lea-font-step-minus-2);--lea-text-body-xs-font-weight:var(--lea-font-weight-regular);--lea-text-body-xs-line-height:var(--lea-line-height-normal);--lea-text-body-xs-letter-spacing:0;--lea-text-body-sm-font-size:var(--lea-font-step-minus-1);--lea-text-body-sm-font-weight:var(--lea-font-weight-regular);--lea-text-body-sm-line-height:var(--lea-line-height-normal);--lea-text-body-sm-letter-spacing:0;--lea-text-body-md-font-size:var(--lea-font-step-0);--lea-text-body-md-font-weight:var(--lea-font-weight-regular);--lea-text-body-md-line-height:var(--lea-line-height-normal);--lea-text-body-md-letter-spacing:0;--lea-text-body-lg-font-size:var(--lea-font-step-1);--lea-text-body-lg-font-weight:var(--lea-font-weight-regular);--lea-text-body-lg-line-height:var(--lea-line-height-normal);--lea-text-body-lg-letter-spacing:0;--lea-text-label-sm-font-size:var(--lea-font-step-minus-2);--lea-text-label-sm-font-weight:var(--lea-font-weight-medium);--lea-text-label-sm-line-height:var(--lea-line-height-tight);--lea-text-label-sm-letter-spacing:0;--lea-text-label-md-font-size:var(--lea-font-step-minus-1);--lea-text-label-md-font-weight:var(--lea-font-weight-medium);--lea-text-label-md-line-height:var(--lea-line-height-tight);--lea-text-label-md-letter-spacing:0;--lea-text-label-lg-font-size:var(--lea-font-step-0);--lea-text-label-lg-font-weight:var(--lea-font-weight-medium);--lea-text-label-lg-line-height:var(--lea-line-height-tight);--lea-text-label-lg-letter-spacing:0;--lea-opacity-hover:.08;--lea-opacity-pressed:.12;--lea-opacity-highlight:.6;--lea-duration-fast:.15s;--lea-duration-normal:.2s;--lea-duration-emphasis:.3s;--lea-easing-standard:ease-in-out;--lea-easing-spring:cubic-bezier(.34, 1.56, .64, 1);--lea-breakpoint-xs:0px;--lea-breakpoint-sm:600px;--lea-breakpoint-md:900px;--lea-breakpoint-lg:1200px;--lea-breakpoint-xl:1536px}._Button_1d72q_1{--button-solid:var(--lea-palette-primary-base);--button-solid-hover:var(--lea-palette-primary-hover);--button-on-solid:var(--lea-palette-primary-contrast);--button-fg:var(--lea-palette-primary-base);--button-border:var(--lea-palette-primary-base);--button-tint:color-mix(in srgb, var(--button-fg) calc(var(--lea-opacity-hover) * 100%), color-mix(in srgb, var(--lea-color-white) calc(var(--lea-opacity-highlight) * 100%), transparent));--button-height:2.75rem;--button-icon-size:1.25rem;--button-padding-inline:calc(var(--lea-spacing) * 2.5);box-sizing:border-box;min-height:var(--button-height);justify-content:center;align-items:center;gap:var(--lea-spacing);padding-block:calc(var(--lea-spacing) * .5);padding-inline:var(--button-padding-inline);border-radius:var(--lea-radius-full);color:var(--button-fg);font-family:inherit;font-size:var(--lea-text-label-lg-font-size);font-weight:var(--lea-text-label-lg-font-weight);line-height:var(--lea-text-label-lg-line-height);letter-spacing:var(--lea-text-label-lg-letter-spacing);text-align:center;cursor:pointer;-webkit-user-select:none;user-select:none;-webkit-tap-highlight-color:transparent;transition:background-color var(--lea-duration-normal) var(--lea-easing-standard), border-color var(--lea-duration-normal) var(--lea-easing-standard), color var(--lea-duration-normal) var(--lea-easing-standard), opacity var(--lea-duration-normal) var(--lea-easing-standard);background-color:#0000;border:1px solid #0000;flex-shrink:0;margin:0;text-decoration:none;display:inline-flex}._Button_1d72q_1 svg{width:var(--button-icon-size);height:var(--button-icon-size);flex-shrink:0}._Button_1d72q_1:focus-visible{outline:2px solid var(--lea-palette-text-base);outline-offset:.125rem}._Button_1d72q_1[data-color=secondary]{--button-solid:var(--lea-palette-secondary-base);--button-solid-hover:var(--lea-palette-secondary-hover);--button-on-solid:var(--lea-palette-secondary-contrast);--button-fg:var(--lea-palette-secondary-base);--button-border:var(--lea-palette-secondary-base)}._Button_1d72q_1[data-color=error]{--button-solid:var(--lea-color-red-600);--button-solid-hover:var(--lea-color-red-500);--button-on-solid:var(--lea-palette-text-contrast);--button-fg:var(--lea-color-red-600);--button-border:var(--lea-color-red-600)}._Button_1d72q_1[data-variant=solid]{background-color:var(--button-solid);color:var(--button-on-solid)}._Button_1d72q_1[data-variant=outline]{border-color:var(--button-border)}@media (hover:hover){._Button_1d72q_1[data-variant=solid]:not([data-disabled]):hover{background-color:var(--button-solid-hover)}._Button_1d72q_1[data-variant=outline]:not([data-disabled]):hover,._Button_1d72q_1[data-variant=ghost]:not([data-disabled]):hover{background-color:var(--button-tint)}}._Button_1d72q_1[data-size=sm]{--button-height:2.25rem;--button-icon-size:1rem;--button-padding-inline:calc(var(--lea-spacing) * 2)}._Button_1d72q_1[data-size=lg]{--button-height:3.25rem;--button-icon-size:1.5rem;--button-padding-inline:calc(var(--lea-spacing) * 2.5)}._Button_1d72q_1[data-start-icon]{padding-inline-start:calc(var(--button-padding-inline) - var(--lea-spacing))}._Button_1d72q_1[data-end-icon]{padding-inline-end:calc(var(--button-padding-inline) - var(--lea-spacing))}._Button_1d72q_1._IconButton_1d72q_125{width:var(--button-height);height:var(--button-height);padding:0}._Button_1d72q_1[data-disabled]:not([data-loading]){color:var(--lea-color-neutral-400);cursor:not-allowed}._Button_1d72q_1[data-variant=solid][data-disabled]:not([data-loading]){background-color:var(--lea-color-neutral-200);color:var(--lea-color-neutral-600)}._Button_1d72q_1[data-variant=outline][data-disabled]:not([data-loading]){border-color:var(--lea-palette-border-base)}._Button_1d72q_1[data-loading]{cursor:progress;opacity:.7}._Spinner_1d72q_150{box-sizing:border-box;width:var(--button-icon-size);height:var(--button-icon-size);border:2px solid;border-radius:var(--lea-radius-full);border-inline-end-color:#0000;flex-shrink:0;animation:.8s linear infinite _button-spin_1d72q_1;display:inline-block}@keyframes _button-spin_1d72q_1{to{rotate:360deg}}._SrOnly_1d72q_168{clip-path:inset(50%);white-space:nowrap;border:0;width:1px;height:1px;margin:-1px;padding:0;position:absolute;overflow:hidden}@media (prefers-reduced-motion:reduce){._Button_1d72q_1{transition-duration:.01ms}._Spinner_1d72q_150{animation:none}}._Backdrop_1mady_8{z-index:1300;background-color:var(--lea-palette-bg-overlay);opacity:1;transition:opacity var(--lea-duration-normal) var(--lea-easing-standard);position:fixed;inset:0}._Backdrop_1mady_8[data-starting-style],._Backdrop_1mady_8[data-ending-style]{opacity:0}._Viewport_1mady_22{z-index:1300;padding:calc(var(--lea-spacing) * 2);pointer-events:none;justify-content:center;align-items:center;display:flex;position:fixed;inset:0}._Popup_1mady_38{border-radius:var(--lea-radius-4xl);background-color:var(--lea-palette-bg-base);width:100%;max-height:100%;box-shadow:var(--lea-shadow-xl);color:var(--lea-palette-text-base);opacity:1;pointer-events:auto;transition:opacity var(--lea-duration-normal) var(--lea-easing-standard), transform var(--lea-duration-normal) var(--lea-easing-standard);flex-direction:column;display:flex;overflow:hidden;transform:scale(1)}._Popup_1mady_38[data-starting-style],._Popup_1mady_38[data-ending-style]{opacity:0;transform:scale(.95)}._Popup_1mady_38[data-size=xs]{max-width:27.75rem}._Popup_1mady_38[data-size=sm]{max-width:37.5rem}._Popup_1mady_38[data-size=md]{max-width:56.25rem}._Popup_1mady_38[data-size=lg]{max-width:75rem}._Header_1mady_78{justify-content:space-between;align-items:flex-start;gap:var(--lea-spacing);padding:calc(var(--lea-spacing) * 3) calc(var(--lea-spacing) * 3) calc(var(--lea-spacing) * 2);flex-shrink:0;display:flex}._Title_1mady_88{color:var(--lea-palette-text-base);font-size:var(--lea-text-heading-sm-font-size);font-weight:var(--lea-text-heading-sm-font-weight);line-height:var(--lea-text-heading-sm-line-height);letter-spacing:var(--lea-text-heading-sm-letter-spacing);margin:0}._Description_1mady_97{margin:0 0 calc(var(--lea-spacing) * 2);color:var(--lea-palette-text-subtle)}._Description_1mady_97[data-last]{margin-bottom:0}._Content_1mady_111{padding:0 calc(var(--lea-spacing) * 3) calc(var(--lea-spacing) * 3);color:var(--lea-palette-text-base);flex:1;overflow-y:auto}._Content_1mady_111:has(+._Footer_1mady_119){padding-bottom:0}._Footer_1mady_119{justify-content:flex-end;align-items:center;gap:var(--lea-spacing);padding:calc(var(--lea-spacing) * 2) calc(var(--lea-spacing) * 3) calc(var(--lea-spacing) * 2);background-color:var(--lea-palette-bg-base);flex-wrap:wrap;flex-shrink:0;display:flex}._CloseButton_1mady_135{border:2px solid var(--lea-palette-border-base);border-radius:var(--lea-radius-full);width:2.5rem;height:2.5rem;color:var(--lea-palette-text-base);cursor:pointer;transition:border-color var(--lea-duration-emphasis) var(--lea-easing-spring), background-color var(--lea-duration-emphasis) var(--lea-easing-spring), color var(--lea-duration-emphasis) var(--lea-easing-spring);background-color:#0000;flex-shrink:0;justify-content:center;align-items:center;margin-inline-end:calc(var(--lea-spacing) * -.5);padding:0;display:inline-flex}@media (hover:hover){._CloseButton_1mady_135:hover{border-color:var(--lea-palette-primary-base);background-color:var(--lea-palette-primary-base);color:var(--lea-palette-primary-contrast)}}._CloseButton_1mady_135:focus-visible{outline:2px solid var(--lea-palette-text-base);outline-offset:.125rem}@media (width<=599.95px){._Viewport_1mady_22:has(._Popup_1mady_38[data-full-screen-on-mobile]){padding:0}._Popup_1mady_38[data-full-screen-on-mobile]{border-radius:0;width:100vw;max-width:none;height:100dvh;max-height:none}._Popup_1mady_38[data-full-screen-on-mobile] ._Content_1mady_111{padding-bottom:calc(var(--lea-spacing) * 3 + env(safe-area-inset-bottom))}._Popup_1mady_38[data-full-screen-on-mobile] ._Content_1mady_111:has(+._Footer_1mady_119){padding-bottom:0}._Popup_1mady_38[data-full-screen-on-mobile] ._Footer_1mady_119{padding-bottom:calc(var(--lea-spacing) * 3 + env(safe-area-inset-bottom))}}@media (prefers-reduced-motion:reduce){._Backdrop_1mady_8,._Popup_1mady_38,._CloseButton_1mady_135{transition-duration:.01ms}}._Switch_9c9ji_7{border-radius:var(--lea-radius-full);background-color:var(--lea-color-neutral-200);cursor:pointer;width:2.5rem;height:1.5rem;transition:background-color var(--lea-duration-normal) var(--lea-easing-standard);border:none;flex-shrink:0;align-items:center;padding:.125rem;display:inline-flex}._Switch_9c9ji_7[data-checked]{background-color:var(--lea-palette-primary-base)}._Switch_9c9ji_7:focus-visible{outline:2px solid var(--lea-palette-text-base);outline-offset:.125rem}._Switch_9c9ji_7[data-disabled]{cursor:not-allowed;opacity:.5}._Thumb_9c9ji_36{border-radius:var(--lea-radius-full);background-color:var(--lea-palette-bg-base);width:1.25rem;height:1.25rem;transition:translate var(--lea-duration-normal) var(--lea-easing-standard);display:block}._Thumb_9c9ji_36[data-checked]{translate:1rem}@media (prefers-reduced-motion:reduce){._Switch_9c9ji_7,._Thumb_9c9ji_36{transition-duration:.01ms}}._Root_18gqk_13{--accordion-gap:var(--lea-spacing);--accordion-item-bg:transparent;--accordion-item-border:var(--lea-palette-border-subtle);--accordion-item-radius:var(--lea-radius-2xl);--accordion-header-radius:var(--lea-radius-2xl);--accordion-hover-border:var(--lea-palette-border-strong);--accordion-hover-bg:transparent;--accordion-active-bg:var(--lea-color-purple-50);gap:var(--accordion-gap);flex-direction:column;width:100%;display:flex}._Root_18gqk_13[data-variant=solid]{--accordion-item-bg:var(--lea-palette-bg-subtle);--accordion-item-border:transparent;--accordion-hover-border:transparent;--accordion-hover-bg:var(--lea-color-neutral-100);--accordion-active-bg:var(--lea-color-neutral-200)}._Root_18gqk_13[data-variant=divided],._Root_18gqk_13[data-variant=ghost]{--accordion-highlight:color-mix(in srgb, var(--lea-color-white) calc(var(--lea-opacity-highlight) * 100%), transparent);--accordion-item-border:transparent;--accordion-header-radius:var(--lea-radius-sm);--accordion-hover-border:transparent;--accordion-hover-bg:color-mix(in srgb, var(--lea-palette-text-base) calc(var(--lea-opacity-hover) * 100%), var(--accordion-highlight));--accordion-active-bg:color-mix(in srgb, var(--lea-palette-text-base) calc(var(--lea-opacity-pressed) * 100%), var(--accordion-highlight))}._Root_18gqk_13[data-variant=divided]{--accordion-gap:0;--accordion-item-radius:0}._Item_18gqk_10{border:1px solid var(--accordion-item-border);border-radius:var(--accordion-item-radius);background-color:var(--accordion-item-bg)}._Root_18gqk_13[data-variant=divided]>._Item_18gqk_10:not(:last-child){border-block-end-color:var(--lea-palette-border-subtle)}._Header_18gqk_10{align-items:center;gap:calc(var(--lea-spacing) * 2);padding:calc(var(--lea-spacing) * 1.7) calc(var(--lea-spacing) * 2);border-radius:var(--accordion-header-radius);transition:border-color var(--lea-duration-emphasis) var(--lea-easing-standard), background-color var(--lea-duration-emphasis) var(--lea-easing-standard);border:1px solid #0000;margin:0;display:flex}@media (hover:hover){._Header_18gqk_10:has(._Trigger_18gqk_95:hover:not([data-disabled])){border-color:var(--accordion-hover-border);background-color:var(--accordion-hover-bg)}}._Header_18gqk_10:has(._Trigger_18gqk_95:active:not([data-disabled])){background-color:var(--accordion-active-bg)}._Trigger_18gqk_95{justify-content:space-between;align-items:center;gap:var(--lea-spacing);min-width:0;color:var(--lea-palette-text-base);cursor:pointer;font-family:inherit;font-size:var(--lea-font-step-0);font-weight:var(--lea-font-weight-medium);line-height:var(--lea-line-height-normal);text-align:left;background-color:#0000;border:none;flex:1;margin:0;padding:0;display:flex}._Trigger_18gqk_95:focus-visible{outline:2px solid var(--lea-palette-text-base);outline-offset:.125rem}._Trigger_18gqk_95[data-disabled]{color:var(--lea-palette-text-muted);cursor:not-allowed}._Label_18gqk_136{min-width:0}._Icon_18gqk_140{transition:transform var(--lea-duration-emphasis) var(--lea-easing-standard);flex-shrink:0}._Trigger_18gqk_95[data-panel-open] ._Icon_18gqk_140{transform:rotate(180deg)}._Root_18gqk_13[data-icon-position=start] ._Trigger_18gqk_95{justify-content:flex-start}._Root_18gqk_13[data-icon-position=start] ._Icon_18gqk_140{order:-1}._Panel_18gqk_158{height:var(--accordion-panel-height);transition:height var(--lea-duration-emphasis) var(--lea-easing-standard);overflow:hidden}._Panel_18gqk_158[data-starting-style],._Panel_18gqk_158[data-ending-style]{height:0}._Content_18gqk_169{padding-inline:calc(var(--lea-spacing) * 2);padding-block:var(--lea-spacing);color:var(--lea-palette-text-base);font-size:var(--lea-text-body-md-font-size);font-weight:var(--lea-text-body-md-font-weight);line-height:var(--lea-text-body-md-line-height);letter-spacing:var(--lea-text-body-md-letter-spacing)}@media (prefers-reduced-motion:reduce){._Header_18gqk_10,._Icon_18gqk_140,._Panel_18gqk_158{transition-duration:.01ms}}._Intro_nxwj4_7{color:var(--lea-palette-text-base)}._Intro_nxwj4_7 p,._Intro_nxwj4_7 ul,._Intro_nxwj4_7 ol{margin:0}._Intro_nxwj4_7>*+*{margin-top:var(--lea-spacing)}._Intro_nxwj4_7 ul,._Intro_nxwj4_7 ol{padding-inline-start:calc(var(--lea-spacing) * 2.5)}._Intro_nxwj4_7 a{border-radius:var(--lea-radius-sm);color:var(--lea-palette-text-accent);font-weight:var(--lea-font-weight-semibold);text-underline-offset:.15em;text-decoration:underline}._Intro_nxwj4_7 a:focus-visible{outline:2px solid var(--lea-palette-text-base);outline-offset:.125rem}._Categories_nxwj4_39{margin-top:calc(var(--lea-spacing) * 3)}._CategoryDescription_nxwj4_43{color:var(--lea-palette-text-base);font-size:var(--lea-text-body-md-font-size);font-weight:var(--lea-text-body-md-font-weight);line-height:var(--lea-text-body-md-line-height);letter-spacing:var(--lea-text-body-md-letter-spacing);margin:0}._Actions_nxwj4_52{margin-top:calc(var(--lea-spacing) * 3);gap:var(--lea-spacing);border-top:1px solid var(--lea-palette-border-subtle);flex-wrap:wrap;display:flex}._Actions_nxwj4_52 button{border-radius:var(--lea-radius-2xl)}._Save_nxwj4_63{margin-inline-start:auto}@media (width<=599.95px){._Actions_nxwj4_52{flex-direction:column;align-items:stretch}._Save_nxwj4_63{margin-inline-start:0}}
@@ -0,0 +1,140 @@
1
+ import { CSSProperties, ReactNode, Ref } from 'react';
2
+ import { CalendarHeaderLabels } from './use-calendar-header-labels';
3
+ import { ViewToggleLabels } from './use-view-toggle-labels';
4
+ import { MonthYearOrder } from './view-toggle';
5
+ export { type CalendarHeaderLabels, type MonthYearOrder, type ViewToggleLabels, };
6
+ export type DatePickerView = "year" | "month" | "day";
7
+ /** Why the date in the field is not a valid choice. */
8
+ export type DatePickerValidationError = "invalidDate" | "minDate" | "maxDate" | "disablePast" | "disableFuture";
9
+ export type DatePickerChangeDetails = {
10
+ /**
11
+ * Set when the date in the field is not one that can be chosen:
12
+ * `"invalidDate"` for a date that does not exist (31.02., where the value
13
+ * is an invalid `Date`), the others when it falls outside what `minDate`,
14
+ * `maxDate`, `disablePast` or `disableFuture` allow. `null` when the date
15
+ * is fine, and when the field is empty or only partly filled (the value is
16
+ * then `null`).
17
+ *
18
+ * A year is reported while it is typed: "2", "20" and "202" each arrive as
19
+ * a date in that year, with `"minDate"`, since nothing before 1900 can be
20
+ * chosen.
21
+ */
22
+ validationError: DatePickerValidationError | null;
23
+ };
24
+ export type DatePickerProps = {
25
+ /** The chosen date (controlled). `null` means the field is empty. */
26
+ value?: Date | null;
27
+ /** The chosen date when first rendered, for uncontrolled use. */
28
+ defaultValue?: Date | null;
29
+ /**
30
+ * Called with the new date when one is picked or typed, and with `null`
31
+ * when the field is cleared.
32
+ */
33
+ onValueChange?: (value: Date | null, details: DatePickerChangeDetails) => void;
34
+ /**
35
+ * Called when focus leaves the field, and when the calendar closes.
36
+ * Opening the calendar does not count as leaving.
37
+ */
38
+ onBlur?: () => void;
39
+ /** The first part of the date in the field, which is where focus goes. */
40
+ ref?: Ref<HTMLElement>;
41
+ /** Submitted with a native form, as the date in the field's format. */
42
+ name?: string;
43
+ /** The floating label, linked to the field. */
44
+ label?: ReactNode;
45
+ /** Helper / error text shown below the control and linked via `aria-describedby`. */
46
+ helperText?: ReactNode;
47
+ /** Puts the control in an error state and styles the helper text accordingly. */
48
+ error?: boolean;
49
+ disabled?: boolean;
50
+ /** Marks the control as required. */
51
+ required?: boolean;
52
+ /** The date can be read and copied, not changed. */
53
+ readOnly?: boolean;
54
+ /** The earliest date that can be chosen. */
55
+ minDate?: Date;
56
+ /** The latest date that can be chosen. */
57
+ maxDate?: Date;
58
+ /** Only today and later can be chosen. */
59
+ disablePast?: boolean;
60
+ /** Only today and earlier can be chosen. */
61
+ disableFuture?: boolean;
62
+ /**
63
+ * What can be picked. The default is a full date; `["year", "month"]` gives
64
+ * the month/year picker.
65
+ * @default ["year", "month", "day"]
66
+ */
67
+ views?: readonly DatePickerView[];
68
+ /** Order of month and year in the month/year picker. Default: "month-year" */
69
+ monthYearOrder?: MonthYearOrder;
70
+ /**
71
+ * How the date is written in the field, as a `date-fns` format string.
72
+ * Defaults to the language's own format ("dd.MM.yyyy" in Norwegian).
73
+ */
74
+ format?: string;
75
+ /**
76
+ * The date the calendar shows while the field is empty. Defaults to today.
77
+ */
78
+ referenceDate?: Date;
79
+ /** Whether the calendar is open (controlled). */
80
+ open?: boolean;
81
+ /** Called when the calendar opens or closes. */
82
+ onOpenChange?: (open: boolean) => void;
83
+ /**
84
+ * The media query above which the calendar is a popover; below it, it is a
85
+ * drawer from the bottom of the screen. Defaults to the `sm` breakpoint.
86
+ */
87
+ desktopModeMediaQuery?: string;
88
+ /** Small uppercase context label shown above the drawer title on mobile. */
89
+ eyebrow?: ReactNode;
90
+ /** Drawer heading on mobile. Defaults from `views` ("Velg dato" or "Velg måned og år"). */
91
+ title?: ReactNode;
92
+ /**
93
+ * Override the month/year toggle's translated labels (`month`, `year`,
94
+ * `selectView`) per-instance. Only used by the month/year picker
95
+ * (`views={["year", "month"]}`).
96
+ */
97
+ viewToggleLabels?: ViewToggleLabels;
98
+ /**
99
+ * Override the day calendar header's translated labels (`previousMonth`,
100
+ * `nextMonth`, `switchToYearView`, `switchToDayView`) per-instance. Only
101
+ * used by the day picker (default `views`).
102
+ */
103
+ calendarHeaderLabels?: CalendarHeaderLabels;
104
+ /** On the field. */
105
+ className?: string;
106
+ /** On the field. */
107
+ style?: CSSProperties;
108
+ };
109
+ /**
110
+ * Date picker. It is the one component of the library that still wraps MUI
111
+ * (`@mui/x-date-pickers`), which is why it has an import path of its own:
112
+ *
113
+ * ```tsx
114
+ * import { DatePicker } from "@leabankab/component-library/date-picker";
115
+ *
116
+ * <DatePicker label="Ansatt siden" value={value} onValueChange={setValue} />
117
+ * ```
118
+ *
119
+ * An app that uses it installs `@mui/material`, `@mui/system`, `@mui/x-date-pickers`,
120
+ * `@emotion/react`, `@emotion/styled` and `date-fns`. It needs no provider:
121
+ * the picker brings its own MUI theme and localisation, and follows the
122
+ * language of `LeaProvider`.
123
+ *
124
+ * Two calendar designs, chosen by `views`:
125
+ * - **Day picker** (default): a day grid with a centered header (prev/next
126
+ * month chevrons either side of a clickable month-year label that switches
127
+ * to the year list) and lowercase Monday-first weekdays.
128
+ * - **Month/year picker** (`views={["year", "month"]}`): a Måned / År segmented
129
+ * toggle above the month / year grids. Control the order via `monthYearOrder`:
130
+ * "month-year" (default) or "year-month" (for Sweden and other locales).
131
+ * Opens on the first view and drills through to the second.
132
+ *
133
+ * - **Desktop:** a compact popover ("dropdown").
134
+ * - **Mobile:** a bottom `Drawer` with an `eyebrow` + `title` header. The switch
135
+ * happens at the `sm` breakpoint by default; override with
136
+ * `desktopModeMediaQuery`.
137
+ *
138
+ * Selecting a value commits immediately in both modes.
139
+ */
140
+ export declare function DatePicker(props: DatePickerProps): import("react").JSX.Element;
@@ -0,0 +1,18 @@
1
+ /**
2
+ * The `@leabankab/component-library/date-picker` entry. `DatePicker` is the
3
+ * one component that still wraps MUI, and it lives here so that the main entry
4
+ * imports neither MUI, Emotion nor `date-fns`: an app that has no date picker
5
+ * does not install them.
6
+ *
7
+ * Two rules for the files in this folder, both checked by
8
+ * tests/entries.test.tsx:
9
+ *
10
+ * - What they share with the main entry at run time (the language context,
11
+ * components with a stylesheet) they import from "../index". The build
12
+ * leaves that module out and points the import at the main bundle, so the
13
+ * picker reads the language the app's `LeaProvider` sets rather than a
14
+ * context of its own.
15
+ * - Anything else they import from `src/` is bundled in, so it has to be
16
+ * plain data or a helper without state: the tokens, `useFocusTargetRef`.
17
+ */
18
+ export { DatePicker, type CalendarHeaderLabels, type DatePickerChangeDetails, type DatePickerProps, type DatePickerValidationError, type DatePickerView, type MonthYearOrder, type ViewToggleLabels, } from './datepicker';
@@ -0,0 +1,23 @@
1
+ import { CSSObject } from '@mui/material';
2
+ /**
3
+ * The outlined field of the date picker, the one field that still wraps MUI:
4
+ * its height, padding, collapsed notch and border-state colours. The other
5
+ * fields get the same look from `input.module.css`.
6
+ */
7
+ export declare const FIELD_HEIGHT = "54px";
8
+ export declare const fieldPadding: {
9
+ readonly paddingInlineStart: "0.9rem";
10
+ readonly paddingBlockStart: "1.5rem";
11
+ readonly paddingBlockEnd: "0.5rem";
12
+ };
13
+ /**
14
+ * We draw the field border ourselves, so MUI's notch and its legend are
15
+ * collapsed. Takes the class of the notched outline, which the picker's
16
+ * `PickersOutlinedInput` names differently from MUI's `OutlinedInput`.
17
+ */
18
+ export declare const collapsedNotch: (outlineClass: string) => CSSObject;
19
+ /**
20
+ * Hover / focus / error border treatment of the field. Takes the class of the
21
+ * notched outline, for the same reason as `collapsedNotch`.
22
+ */
23
+ export declare const fieldBorderStates: (outlineClass: string) => CSSObject;
@@ -0,0 +1,7 @@
1
+ import { Components, Theme } from '@mui/material';
2
+ export declare const formControlTheme: Components<Theme>["MuiFormControl"];
3
+ /**
4
+ * Helper text under the date picker, the one field that still wraps MUI, in
5
+ * the same text style as under the other fields (`field-parts.module.css`).
6
+ */
7
+ export declare const formHelperTextTheme: Components<Theme>["MuiFormHelperText"];