@bmsuisse/ui 0.15.0 → 0.16.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/primitives/button.tsx","../src/lib/utils.ts","../src/primitives/input.tsx","../src/primitives/label.tsx","../src/primitives/textarea.tsx","../src/primitives/card.tsx","../src/primitives/badge.tsx","../src/primitives/dialog.tsx","../src/primitives/popover.tsx","../src/primitives/select.tsx","../src/primitives/skeleton.tsx","../src/primitives/checkbox.tsx","../src/primitives/switch.tsx","../src/primitives/tabs.tsx","../src/primitives/separator.tsx","../src/primitives/scroll-area.tsx","../src/primitives/table.tsx","../src/primitives/dropdown-menu.tsx","../src/primitives/sheet.tsx","../src/primitives/tooltip.tsx","../src/patterns/modal/Modal.tsx","../src/patterns/modal/ConfirmDialog.tsx","../src/patterns/modal/DialogActions.tsx","../src/lib/platform.ts","../src/patterns/modal/FormModal.tsx","../src/patterns/modal/ResponsivePanel.tsx","../src/lib/useMediaQuery.ts","../src/patterns/modal/QuestionDialog.tsx","../src/patterns/form-field/FormField.tsx","../src/patterns/combobox/Combobox.tsx","../src/lib/optionGrouping.ts","../src/lib/optionGrid.tsx","../src/patterns/tag-combobox/TagCombobox.tsx","../src/patterns/alert-box/AlertBox.tsx","../src/patterns/status-badge/StatusBadge.tsx","../src/patterns/button-group/ButtonGroup.tsx","../src/patterns/loading-spinner/LoadingSpinner.tsx","../src/patterns/search-bar/SearchBar.tsx","../src/patterns/kpi-card/KpiCard.tsx","../src/patterns/search-panel/SearchPanel.tsx","../src/patterns/search-panel/SearchTrigger.tsx","../src/patterns/sidebar/context.ts","../src/patterns/sidebar/NavItem.tsx","../src/patterns/sidebar/NavGroup.tsx","../src/patterns/sidebar/Sidebar.tsx","../src/patterns/stepper/Stepper.tsx"],"sourcesContent":["import { Slot } from \"@radix-ui/react-slot\";\nimport { type VariantProps, cva } from \"class-variance-authority\";\nimport type { ButtonHTMLAttributes } from \"react\";\nimport { forwardRef } from \"react\";\nimport { cn } from \"../lib/utils\";\n\nexport const buttonVariants = cva(\n \"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0\",\n {\n variants: {\n variant: {\n default: \"bg-primary text-primary-foreground hover:bg-primary/90\",\n outline: \"border border-input bg-background hover:bg-accent hover:text-accent-foreground\",\n ghost: \"hover:bg-accent hover:text-accent-foreground\",\n destructive: \"bg-destructive text-destructive-foreground hover:bg-destructive/90\",\n secondary: \"bg-muted text-muted-foreground hover:bg-muted/80\",\n link: \"text-primary underline-offset-4 hover:underline\",\n // \"Swiss design\" red CTA, ported from akeneo_editor's old .btn-primary-swiss\n // naive-ui override. Relies on --color-swiss-primary/-hover and\n // --color-swiss-primary-foreground tokens defined by the consuming app's own\n // Tailwind theme (this package doesn't define them) — same pattern as AlertBox's\n // warning/info/success colors, which assume tokens the shared theme doesn't have.\n \"swiss-primary\":\n \"bg-swiss-primary text-swiss-primary-foreground font-semibold shadow-sm hover:bg-swiss-primary-hover hover:-translate-y-px active:translate-y-px\",\n \"swiss-secondary\":\n \"border border-input bg-background font-semibold text-foreground shadow-sm hover:bg-accent hover:-translate-y-px active:translate-y-px\",\n },\n size: {\n default: \"h-9 px-3\",\n xs: \"h-7 px-2 text-xs\",\n sm: \"h-8 px-2 text-xs\",\n lg: \"h-10 px-4\",\n icon: \"h-9 w-9\",\n \"icon-xs\": \"h-7 w-7\",\n \"icon-sm\": \"h-8 w-8\",\n \"icon-lg\": \"h-10 w-10\",\n },\n },\n defaultVariants: {\n variant: \"default\",\n size: \"default\",\n },\n },\n);\n\nexport interface ButtonProps\n extends ButtonHTMLAttributes<HTMLButtonElement>,\n VariantProps<typeof buttonVariants> {\n asChild?: boolean;\n}\n\nexport const Button = forwardRef<HTMLButtonElement, ButtonProps>(\n ({ className, variant, size, asChild = false, ...props }, ref) => {\n const Comp = asChild ? Slot : \"button\";\n return (\n <Comp className={cn(buttonVariants({ variant, size, className }))} ref={ref} {...props} />\n );\n },\n);\nButton.displayName = \"Button\";\n","import { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\n/** Merges conditional class names, then dedupes conflicting Tailwind utility classes. */\nexport function cn(...inputs: ClassValue[]): string {\n return twMerge(clsx(inputs));\n}\n","import type { InputHTMLAttributes } from \"react\";\nimport { forwardRef } from \"react\";\nimport { cn } from \"../lib/utils\";\n\nexport type InputProps = InputHTMLAttributes<HTMLInputElement>;\n\nexport const Input = forwardRef<HTMLInputElement, InputProps>(({ className, type, ...props }, ref) => {\n return (\n <input\n type={type}\n className={cn(\n \"flex h-9 w-full min-w-0 rounded-md border border-input bg-transparent px-3 py-1 text-sm shadow-sm transition-colors selection:bg-primary selection:text-primary-foreground file:inline-flex file:h-7 file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50\",\n className,\n )}\n ref={ref}\n {...props}\n />\n );\n});\nInput.displayName = \"Input\";\n","import type { LabelHTMLAttributes } from \"react\";\nimport { forwardRef } from \"react\";\nimport { cn } from \"../lib/utils\";\n\nexport const Label = forwardRef<HTMLLabelElement, LabelHTMLAttributes<HTMLLabelElement>>(\n ({ className, ...props }, ref) => (\n <label\n ref={ref}\n className={cn(\n \"text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70\",\n className,\n )}\n {...props}\n />\n ),\n);\nLabel.displayName = \"Label\";\n","import type { TextareaHTMLAttributes } from \"react\";\nimport { forwardRef } from \"react\";\nimport { cn } from \"../lib/utils\";\n\nexport type TextareaProps = TextareaHTMLAttributes<HTMLTextAreaElement>;\n\nexport const Textarea = forwardRef<HTMLTextAreaElement, TextareaProps>(\n ({ className, ...props }, ref) => (\n <textarea\n className={cn(\n \"flex min-h-16 w-full rounded-md border border-input bg-transparent px-3 py-2 text-sm shadow-sm transition-colors placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50\",\n className,\n )}\n ref={ref}\n {...props}\n />\n ),\n);\nTextarea.displayName = \"Textarea\";\n","import type { HTMLAttributes, ReactElement } from \"react\";\nimport { cn } from \"../lib/utils\";\n\n// Deliberately uses bg-background/text-foreground rather than shadcn's usual\n// bg-card/text-card-foreground tokens: the reference consumer app's actual\n// token set (which this package's demo/theme mirrors) has no --card token,\n// and adding one just for this component would be a second, redundant\n// \"surface\" token to keep in sync.\nexport const Card = ({ className, ...props }: HTMLAttributes<HTMLDivElement>): ReactElement => (\n <div className={cn(\"rounded-lg border bg-background text-foreground shadow-sm\", className)} {...props} />\n);\n\nexport const CardHeader = ({\n className,\n ...props\n}: HTMLAttributes<HTMLDivElement>): ReactElement => (\n <div className={cn(\"flex flex-col gap-1.5 p-6\", className)} {...props} />\n);\n\nexport const CardTitle = ({ className, ...props }: HTMLAttributes<HTMLDivElement>): ReactElement => (\n <div className={cn(\"text-lg font-semibold leading-none tracking-tight\", className)} {...props} />\n);\n\nexport const CardDescription = ({\n className,\n ...props\n}: HTMLAttributes<HTMLDivElement>): ReactElement => (\n <div className={cn(\"text-sm text-muted-foreground\", className)} {...props} />\n);\n\nexport const CardContent = ({\n className,\n ...props\n}: HTMLAttributes<HTMLDivElement>): ReactElement => <div className={cn(\"p-6 pt-0\", className)} {...props} />;\n\nexport const CardFooter = ({\n className,\n ...props\n}: HTMLAttributes<HTMLDivElement>): ReactElement => (\n <div className={cn(\"flex items-center gap-2 p-6 pt-0\", className)} {...props} />\n);\n","import { type VariantProps, cva } from \"class-variance-authority\";\nimport type { HTMLAttributes, ReactElement } from \"react\";\nimport { cn } from \"../lib/utils\";\n\nexport const badgeVariants = cva(\n \"inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-medium transition-colors focus:outline-none focus:ring-2 focus:ring-ring\",\n {\n variants: {\n variant: {\n default: \"border-transparent bg-primary text-primary-foreground\",\n secondary: \"border-transparent bg-muted text-muted-foreground\",\n destructive: \"border-transparent bg-destructive text-destructive-foreground\",\n outline: \"border-input text-foreground\",\n // Amber warning tone — same fixed-palette choice as AlertBox/StatusBadge's\n // warning tone, since the shared theme has no warning token yet.\n warning: \"border-transparent bg-amber-100 text-amber-900 dark:bg-amber-900/40 dark:text-amber-200\",\n },\n },\n defaultVariants: {\n variant: \"default\",\n },\n },\n);\n\nexport interface BadgeProps extends HTMLAttributes<HTMLDivElement>, VariantProps<typeof badgeVariants> {}\n\nexport const Badge = ({ className, variant, ...props }: BadgeProps): ReactElement => (\n <div className={cn(badgeVariants({ variant }), className)} {...props} />\n);\n","import * as DialogPrimitive from \"@radix-ui/react-dialog\";\nimport { X } from \"lucide-react\";\nimport type { ComponentPropsWithoutRef, ElementRef, HTMLAttributes, ReactElement } from \"react\";\nimport { forwardRef } from \"react\";\nimport { cn } from \"../lib/utils\";\n\nexport const Dialog = DialogPrimitive.Root;\nexport const DialogTrigger = DialogPrimitive.Trigger;\n\nexport const DialogOverlay = forwardRef<\n ElementRef<typeof DialogPrimitive.Overlay>,\n ComponentPropsWithoutRef<typeof DialogPrimitive.Overlay>\n>(({ className, ...props }, ref) => (\n <DialogPrimitive.Overlay\n ref={ref}\n className={cn(\"fixed inset-0 z-50 bg-black/50\", className)}\n {...props}\n />\n));\nDialogOverlay.displayName = \"DialogOverlay\";\n\nexport const DialogContent = forwardRef<\n ElementRef<typeof DialogPrimitive.Content>,\n ComponentPropsWithoutRef<typeof DialogPrimitive.Content> & {\n showCloseButton?: boolean;\n /** data-testid for the built-in header close button, since it renders no DOM a caller controls directly. */\n closeButtonTestId?: string;\n }\n>(({ className, children, showCloseButton = true, closeButtonTestId, ...props }, ref) => (\n <DialogPrimitive.Portal>\n <DialogOverlay />\n <DialogPrimitive.Content\n ref={ref}\n className={cn(\n \"fixed left-1/2 top-1/2 z-50 max-h-[85vh] w-full max-w-md -translate-x-1/2 -translate-y-1/2 overflow-y-auto rounded-lg border bg-background p-6 shadow-lg\",\n className,\n )}\n {...props}\n >\n {children}\n {showCloseButton ? (\n <DialogPrimitive.Close\n data-testid={closeButtonTestId}\n className=\"absolute right-4 top-4 rounded-sm opacity-70 hover:opacity-100\"\n >\n <X className=\"h-4 w-4\" />\n <span className=\"sr-only\">Close</span>\n </DialogPrimitive.Close>\n ) : null}\n </DialogPrimitive.Content>\n </DialogPrimitive.Portal>\n));\nDialogContent.displayName = \"DialogContent\";\n\nexport const DialogHeader = ({\n className,\n ...props\n}: HTMLAttributes<HTMLDivElement>): ReactElement => (\n <div className={cn(\"flex flex-col gap-1.5\", className)} {...props} />\n);\n\nexport const DialogTitle = forwardRef<\n ElementRef<typeof DialogPrimitive.Title>,\n ComponentPropsWithoutRef<typeof DialogPrimitive.Title>\n>(({ className, ...props }, ref) => (\n <DialogPrimitive.Title ref={ref} className={cn(\"text-lg font-semibold\", className)} {...props} />\n));\nDialogTitle.displayName = \"DialogTitle\";\n\nexport const DialogDescription = forwardRef<\n ElementRef<typeof DialogPrimitive.Description>,\n ComponentPropsWithoutRef<typeof DialogPrimitive.Description>\n>(({ className, ...props }, ref) => (\n <DialogPrimitive.Description\n ref={ref}\n className={cn(\"text-sm text-muted-foreground\", className)}\n {...props}\n />\n));\nDialogDescription.displayName = \"DialogDescription\";\n\nexport const DialogFooter = ({\n className,\n ...props\n}: HTMLAttributes<HTMLDivElement>): ReactElement => (\n <div className={cn(\"mt-4 flex justify-end gap-2\", className)} {...props} />\n);\n","import * as PopoverPrimitive from \"@radix-ui/react-popover\";\nimport type { ComponentPropsWithoutRef, ElementRef } from \"react\";\nimport { forwardRef } from \"react\";\nimport { cn } from \"../lib/utils\";\n\nexport const Popover = PopoverPrimitive.Root;\nexport const PopoverTrigger = PopoverPrimitive.Trigger;\nexport const PopoverAnchor = PopoverPrimitive.Anchor;\n\nexport const PopoverContent = forwardRef<\n ElementRef<typeof PopoverPrimitive.Content>,\n ComponentPropsWithoutRef<typeof PopoverPrimitive.Content> & {\n /** Portal target for the popover content. Defaults to `document.body` (Radix's\n * own default) when omitted. Needed when the popover is opened from inside a\n * modal Dialog/Sheet: Radix's Dialog `FocusScope` traps focus within its own\n * content subtree, and a popover portaled to `document.body` sits outside that\n * subtree — so pass the Dialog/Sheet content element here to portal into it\n * instead. */\n container?: ComponentPropsWithoutRef<typeof PopoverPrimitive.Portal>[\"container\"];\n }\n>(({ className, align = \"start\", sideOffset = 4, container, ...props }, ref) => (\n <PopoverPrimitive.Portal container={container}>\n <PopoverPrimitive.Content\n ref={ref}\n align={align}\n sideOffset={sideOffset}\n className={cn(\n \"z-50 w-72 rounded-md border bg-popover p-4 text-popover-foreground shadow-md outline-none\",\n className,\n )}\n {...props}\n />\n </PopoverPrimitive.Portal>\n));\nPopoverContent.displayName = \"PopoverContent\";\n","import * as SelectPrimitive from \"@radix-ui/react-select\";\nimport { Check, ChevronDown } from \"lucide-react\";\nimport type { ComponentPropsWithoutRef, ElementRef } from \"react\";\nimport { forwardRef } from \"react\";\nimport { cn } from \"../lib/utils\";\n\nexport const Select = SelectPrimitive.Root;\nexport const SelectGroup = SelectPrimitive.Group;\nexport const SelectValue = SelectPrimitive.Value;\n\nexport interface SelectTriggerProps extends ComponentPropsWithoutRef<typeof SelectPrimitive.Trigger> {\n size?: \"sm\" | \"default\";\n}\n\nexport const SelectTrigger = forwardRef<ElementRef<typeof SelectPrimitive.Trigger>, SelectTriggerProps>(\n ({ className, children, size = \"default\", ...props }, ref) => (\n <SelectPrimitive.Trigger\n ref={ref}\n className={cn(\n \"flex w-full items-center justify-between whitespace-nowrap rounded-md border border-input bg-transparent px-3 py-1 text-sm shadow-sm focus:outline-none focus:ring-1 focus:ring-ring disabled:cursor-not-allowed disabled:opacity-50\",\n size === \"sm\" ? \"h-8\" : \"h-9\",\n className,\n )}\n {...props}\n >\n {children}\n <SelectPrimitive.Icon asChild>\n <ChevronDown className=\"h-4 w-4 opacity-50\" />\n </SelectPrimitive.Icon>\n </SelectPrimitive.Trigger>\n ),\n);\nSelectTrigger.displayName = \"SelectTrigger\";\n\nexport const SelectContent = forwardRef<\n ElementRef<typeof SelectPrimitive.Content>,\n ComponentPropsWithoutRef<typeof SelectPrimitive.Content>\n>(({ className, children, position = \"popper\", ...props }, ref) => (\n <SelectPrimitive.Portal>\n <SelectPrimitive.Content\n ref={ref}\n position={position}\n className={cn(\n \"relative z-50 max-h-96 min-w-[8rem] overflow-hidden rounded-md border bg-popover text-popover-foreground shadow-md\",\n position === \"popper\" && \"translate-y-1\",\n className,\n )}\n {...props}\n >\n <SelectPrimitive.Viewport className=\"p-1\">{children}</SelectPrimitive.Viewport>\n </SelectPrimitive.Content>\n </SelectPrimitive.Portal>\n));\nSelectContent.displayName = \"SelectContent\";\n\nexport const SelectItem = forwardRef<\n ElementRef<typeof SelectPrimitive.Item>,\n ComponentPropsWithoutRef<typeof SelectPrimitive.Item>\n>(({ className, children, ...props }, ref) => (\n <SelectPrimitive.Item\n ref={ref}\n className={cn(\n \"relative flex w-full cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50\",\n className,\n )}\n {...props}\n >\n <span className=\"absolute left-2 flex h-3.5 w-3.5 items-center justify-center\">\n <SelectPrimitive.ItemIndicator>\n <Check className=\"h-4 w-4\" />\n </SelectPrimitive.ItemIndicator>\n </span>\n <SelectPrimitive.ItemText>{children}</SelectPrimitive.ItemText>\n </SelectPrimitive.Item>\n));\nSelectItem.displayName = \"SelectItem\";\n","import type { HTMLAttributes, ReactElement } from \"react\";\nimport { cn } from \"../lib/utils\";\n\nexport const Skeleton = ({ className, ...props }: HTMLAttributes<HTMLDivElement>): ReactElement => (\n <div className={cn(\"animate-pulse rounded-md bg-muted\", className)} {...props} />\n);\n","import * as CheckboxPrimitive from \"@radix-ui/react-checkbox\";\nimport { Check } from \"lucide-react\";\nimport type { ComponentPropsWithoutRef, ElementRef } from \"react\";\nimport { forwardRef } from \"react\";\nimport { cn } from \"../lib/utils\";\n\nexport const Checkbox = forwardRef<\n ElementRef<typeof CheckboxPrimitive.Root>,\n ComponentPropsWithoutRef<typeof CheckboxPrimitive.Root>\n>(({ className, ...props }, ref) => (\n <CheckboxPrimitive.Root\n ref={ref}\n className={cn(\n \"peer h-4 w-4 shrink-0 rounded-sm border border-input shadow focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground data-[state=checked]:border-primary\",\n className,\n )}\n {...props}\n >\n <CheckboxPrimitive.Indicator className=\"flex items-center justify-center text-current\">\n <Check className=\"h-3.5 w-3.5\" />\n </CheckboxPrimitive.Indicator>\n </CheckboxPrimitive.Root>\n));\nCheckbox.displayName = \"Checkbox\";\n","import * as SwitchPrimitive from \"@radix-ui/react-switch\";\nimport type { ComponentPropsWithoutRef, ElementRef } from \"react\";\nimport { forwardRef } from \"react\";\nimport { cn } from \"../lib/utils\";\n\nexport interface SwitchProps extends ComponentPropsWithoutRef<typeof SwitchPrimitive.Root> {\n size?: \"sm\" | \"default\";\n}\n\nexport const Switch = forwardRef<ElementRef<typeof SwitchPrimitive.Root>, SwitchProps>(\n ({ className, size = \"default\", ...props }, ref) => (\n <SwitchPrimitive.Root\n ref={ref}\n className={cn(\n \"peer inline-flex shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=unchecked]:bg-input\",\n size === \"sm\" ? \"h-3.5 w-6\" : \"h-5 w-9\",\n className,\n )}\n {...props}\n >\n <SwitchPrimitive.Thumb\n className={cn(\n \"pointer-events-none block rounded-full bg-background shadow-lg ring-0 transition-transform data-[state=unchecked]:translate-x-0\",\n size === \"sm\"\n ? \"h-3 w-3 data-[state=checked]:translate-x-2.5\"\n : \"h-4 w-4 data-[state=checked]:translate-x-4\",\n )}\n />\n </SwitchPrimitive.Root>\n ),\n);\nSwitch.displayName = \"Switch\";\n","import * as TabsPrimitive from \"@radix-ui/react-tabs\";\nimport type { ComponentPropsWithoutRef, ElementRef } from \"react\";\nimport { forwardRef } from \"react\";\nimport { cn } from \"../lib/utils\";\n\nexport const Tabs = TabsPrimitive.Root;\n\nexport const TabsList = forwardRef<\n ElementRef<typeof TabsPrimitive.List>,\n ComponentPropsWithoutRef<typeof TabsPrimitive.List>\n>(({ className, ...props }, ref) => (\n <TabsPrimitive.List\n ref={ref}\n className={cn(\n \"inline-flex h-9 w-fit items-center justify-center rounded-lg bg-muted p-[3px] text-muted-foreground\",\n className,\n )}\n {...props}\n />\n));\nTabsList.displayName = \"TabsList\";\n\nexport const TabsTrigger = forwardRef<\n ElementRef<typeof TabsPrimitive.Trigger>,\n ComponentPropsWithoutRef<typeof TabsPrimitive.Trigger>\n>(({ className, ...props }, ref) => (\n <TabsPrimitive.Trigger\n ref={ref}\n className={cn(\n \"inline-flex h-[calc(100%-1px)] flex-1 items-center justify-center gap-1.5 whitespace-nowrap rounded-md border border-transparent px-2 py-1 text-sm font-medium text-foreground/60 transition-all hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 data-[state=active]:bg-background data-[state=active]:text-foreground data-[state=active]:shadow-sm\",\n className,\n )}\n {...props}\n />\n));\nTabsTrigger.displayName = \"TabsTrigger\";\n\nexport const TabsContent = forwardRef<\n ElementRef<typeof TabsPrimitive.Content>,\n ComponentPropsWithoutRef<typeof TabsPrimitive.Content>\n>(({ className, ...props }, ref) => (\n <TabsPrimitive.Content ref={ref} className={cn(\"flex-1 outline-none\", className)} {...props} />\n));\nTabsContent.displayName = \"TabsContent\";\n","import * as SeparatorPrimitive from \"@radix-ui/react-separator\";\nimport type { ComponentPropsWithoutRef, ElementRef } from \"react\";\nimport { forwardRef } from \"react\";\nimport { cn } from \"../lib/utils\";\n\nexport const Separator = forwardRef<\n ElementRef<typeof SeparatorPrimitive.Root>,\n ComponentPropsWithoutRef<typeof SeparatorPrimitive.Root>\n>(({ className, orientation = \"horizontal\", decorative = true, ...props }, ref) => (\n <SeparatorPrimitive.Root\n ref={ref}\n decorative={decorative}\n orientation={orientation}\n className={cn(\n \"shrink-0 bg-border\",\n orientation === \"horizontal\" ? \"h-px w-full\" : \"h-full w-px\",\n className,\n )}\n {...props}\n />\n));\nSeparator.displayName = \"Separator\";\n","import * as ScrollAreaPrimitive from \"@radix-ui/react-scroll-area\";\nimport type { ComponentPropsWithoutRef, ElementRef } from \"react\";\nimport { forwardRef } from \"react\";\nimport { cn } from \"../lib/utils\";\n\nexport const ScrollBar = forwardRef<\n ElementRef<typeof ScrollAreaPrimitive.ScrollAreaScrollbar>,\n ComponentPropsWithoutRef<typeof ScrollAreaPrimitive.ScrollAreaScrollbar>\n>(({ className, orientation = \"vertical\", ...props }, ref) => (\n <ScrollAreaPrimitive.ScrollAreaScrollbar\n ref={ref}\n orientation={orientation}\n className={cn(\n \"flex touch-none select-none transition-colors\",\n orientation === \"vertical\" && \"h-full w-2.5 border-l border-l-transparent p-[1px]\",\n orientation === \"horizontal\" && \"h-2.5 flex-col border-t border-t-transparent p-[1px]\",\n className,\n )}\n {...props}\n >\n <ScrollAreaPrimitive.ScrollAreaThumb className=\"relative flex-1 rounded-full bg-border\" />\n </ScrollAreaPrimitive.ScrollAreaScrollbar>\n));\nScrollBar.displayName = \"ScrollBar\";\n\nexport const ScrollArea = forwardRef<\n ElementRef<typeof ScrollAreaPrimitive.Root>,\n ComponentPropsWithoutRef<typeof ScrollAreaPrimitive.Root>\n>(({ className, children, ...props }, ref) => (\n <ScrollAreaPrimitive.Root ref={ref} className={cn(\"relative overflow-hidden\", className)} {...props}>\n <ScrollAreaPrimitive.Viewport className=\"h-full w-full rounded-[inherit]\">\n {children}\n </ScrollAreaPrimitive.Viewport>\n <ScrollBar />\n <ScrollAreaPrimitive.Corner />\n </ScrollAreaPrimitive.Root>\n));\nScrollArea.displayName = \"ScrollArea\";\n","import type { HTMLAttributes, TdHTMLAttributes, ThHTMLAttributes } from \"react\";\nimport { forwardRef } from \"react\";\nimport { cn } from \"../lib/utils\";\n\nexport const Table = forwardRef<HTMLTableElement, HTMLAttributes<HTMLTableElement>>(\n ({ className, ...props }, ref) => (\n <div className=\"relative w-full overflow-x-auto\">\n <table ref={ref} className={cn(\"w-full caption-bottom text-sm\", className)} {...props} />\n </div>\n ),\n);\nTable.displayName = \"Table\";\n\nexport const TableHeader = forwardRef<HTMLTableSectionElement, HTMLAttributes<HTMLTableSectionElement>>(\n ({ className, ...props }, ref) => (\n <thead ref={ref} className={cn(\"[&_tr]:border-b\", className)} {...props} />\n ),\n);\nTableHeader.displayName = \"TableHeader\";\n\nexport const TableBody = forwardRef<HTMLTableSectionElement, HTMLAttributes<HTMLTableSectionElement>>(\n ({ className, ...props }, ref) => (\n <tbody ref={ref} className={cn(\"[&_tr:last-child]:border-0\", className)} {...props} />\n ),\n);\nTableBody.displayName = \"TableBody\";\n\nexport const TableFooter = forwardRef<HTMLTableSectionElement, HTMLAttributes<HTMLTableSectionElement>>(\n ({ className, ...props }, ref) => (\n <tfoot\n ref={ref}\n className={cn(\"border-t bg-muted/50 font-medium [&>tr]:last:border-b-0\", className)}\n {...props}\n />\n ),\n);\nTableFooter.displayName = \"TableFooter\";\n\nexport const TableRow = forwardRef<HTMLTableRowElement, HTMLAttributes<HTMLTableRowElement>>(\n ({ className, ...props }, ref) => (\n <tr\n ref={ref}\n className={cn(\"border-b transition-colors hover:bg-muted/50 data-[state=selected]:bg-muted\", className)}\n {...props}\n />\n ),\n);\nTableRow.displayName = \"TableRow\";\n\nexport const TableHead = forwardRef<HTMLTableCellElement, ThHTMLAttributes<HTMLTableCellElement>>(\n ({ className, ...props }, ref) => (\n <th\n ref={ref}\n className={cn(\n \"h-10 whitespace-nowrap px-2 text-left align-middle font-medium text-foreground [&:has([role=checkbox])]:pr-0\",\n className,\n )}\n {...props}\n />\n ),\n);\nTableHead.displayName = \"TableHead\";\n\nexport const TableCell = forwardRef<HTMLTableCellElement, TdHTMLAttributes<HTMLTableCellElement>>(\n ({ className, ...props }, ref) => (\n <td\n ref={ref}\n className={cn(\"whitespace-nowrap p-2 align-middle [&:has([role=checkbox])]:pr-0\", className)}\n {...props}\n />\n ),\n);\nTableCell.displayName = \"TableCell\";\n\nexport const TableCaption = forwardRef<HTMLTableCaptionElement, HTMLAttributes<HTMLTableCaptionElement>>(\n ({ className, ...props }, ref) => (\n <caption ref={ref} className={cn(\"mt-4 text-sm text-muted-foreground\", className)} {...props} />\n ),\n);\nTableCaption.displayName = \"TableCaption\";\n","import * as DropdownMenuPrimitive from \"@radix-ui/react-dropdown-menu\";\nimport { Check, ChevronRight, Circle } from \"lucide-react\";\nimport type { ComponentPropsWithoutRef, ElementRef, HTMLAttributes } from \"react\";\nimport { forwardRef } from \"react\";\nimport { cn } from \"../lib/utils\";\n\nexport const DropdownMenu = DropdownMenuPrimitive.Root;\nexport const DropdownMenuTrigger = DropdownMenuPrimitive.Trigger;\nexport const DropdownMenuGroup = DropdownMenuPrimitive.Group;\nexport const DropdownMenuPortal = DropdownMenuPrimitive.Portal;\nexport const DropdownMenuSub = DropdownMenuPrimitive.Sub;\nexport const DropdownMenuRadioGroup = DropdownMenuPrimitive.RadioGroup;\n\nexport const DropdownMenuContent = forwardRef<\n ElementRef<typeof DropdownMenuPrimitive.Content>,\n ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Content>\n>(({ className, sideOffset = 4, ...props }, ref) => (\n <DropdownMenuPrimitive.Portal>\n <DropdownMenuPrimitive.Content\n ref={ref}\n sideOffset={sideOffset}\n className={cn(\n \"z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-md\",\n className,\n )}\n {...props}\n />\n </DropdownMenuPrimitive.Portal>\n));\nDropdownMenuContent.displayName = \"DropdownMenuContent\";\n\nexport const DropdownMenuItem = forwardRef<\n ElementRef<typeof DropdownMenuPrimitive.Item>,\n ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Item> & { danger?: boolean }\n>(({ className, danger, ...props }, ref) => (\n <DropdownMenuPrimitive.Item\n ref={ref}\n className={cn(\n \"relative flex cursor-default select-none items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50\",\n danger && \"text-destructive focus:bg-destructive/10 focus:text-destructive\",\n className,\n )}\n {...props}\n />\n));\nDropdownMenuItem.displayName = \"DropdownMenuItem\";\n\nexport const DropdownMenuCheckboxItem = forwardRef<\n ElementRef<typeof DropdownMenuPrimitive.CheckboxItem>,\n ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.CheckboxItem>\n>(({ className, children, checked, ...props }, ref) => (\n <DropdownMenuPrimitive.CheckboxItem\n ref={ref}\n checked={checked}\n className={cn(\n \"relative flex cursor-default select-none items-center gap-2 rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50\",\n className,\n )}\n {...props}\n >\n <span className=\"absolute left-2 flex h-3.5 w-3.5 items-center justify-center\">\n <DropdownMenuPrimitive.ItemIndicator>\n <Check className=\"h-4 w-4\" />\n </DropdownMenuPrimitive.ItemIndicator>\n </span>\n {children}\n </DropdownMenuPrimitive.CheckboxItem>\n));\nDropdownMenuCheckboxItem.displayName = \"DropdownMenuCheckboxItem\";\n\nexport const DropdownMenuRadioItem = forwardRef<\n ElementRef<typeof DropdownMenuPrimitive.RadioItem>,\n ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.RadioItem>\n>(({ className, children, ...props }, ref) => (\n <DropdownMenuPrimitive.RadioItem\n ref={ref}\n className={cn(\n \"relative flex cursor-default select-none items-center gap-2 rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50\",\n className,\n )}\n {...props}\n >\n <span className=\"absolute left-2 flex h-3.5 w-3.5 items-center justify-center\">\n <DropdownMenuPrimitive.ItemIndicator>\n <Circle className=\"h-2 w-2 fill-current\" />\n </DropdownMenuPrimitive.ItemIndicator>\n </span>\n {children}\n </DropdownMenuPrimitive.RadioItem>\n));\nDropdownMenuRadioItem.displayName = \"DropdownMenuRadioItem\";\n\nexport const DropdownMenuSeparator = forwardRef<\n ElementRef<typeof DropdownMenuPrimitive.Separator>,\n ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Separator>\n>(({ className, ...props }, ref) => (\n <DropdownMenuPrimitive.Separator\n ref={ref}\n className={cn(\"-mx-1 my-1 h-px bg-muted\", className)}\n {...props}\n />\n));\nDropdownMenuSeparator.displayName = \"DropdownMenuSeparator\";\n\nexport const DropdownMenuLabel = forwardRef<\n ElementRef<typeof DropdownMenuPrimitive.Label>,\n ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Label>\n>(({ className, ...props }, ref) => (\n <DropdownMenuPrimitive.Label\n ref={ref}\n className={cn(\"px-2 py-1.5 text-xs font-medium text-muted-foreground\", className)}\n {...props}\n />\n));\nDropdownMenuLabel.displayName = \"DropdownMenuLabel\";\n\nexport const DropdownMenuShortcut = ({\n className,\n ...props\n}: HTMLAttributes<HTMLSpanElement>) => (\n <span className={cn(\"ml-auto text-xs tracking-widest text-muted-foreground\", className)} {...props} />\n);\n\nexport const DropdownMenuSubTrigger = forwardRef<\n ElementRef<typeof DropdownMenuPrimitive.SubTrigger>,\n ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.SubTrigger>\n>(({ className, children, ...props }, ref) => (\n <DropdownMenuPrimitive.SubTrigger\n ref={ref}\n className={cn(\n \"flex cursor-default select-none items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[state=open]:bg-accent data-[state=open]:text-accent-foreground\",\n className,\n )}\n {...props}\n >\n {children}\n <ChevronRight className=\"ml-auto h-4 w-4\" />\n </DropdownMenuPrimitive.SubTrigger>\n));\nDropdownMenuSubTrigger.displayName = \"DropdownMenuSubTrigger\";\n\nexport const DropdownMenuSubContent = forwardRef<\n ElementRef<typeof DropdownMenuPrimitive.SubContent>,\n ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.SubContent>\n>(({ className, ...props }, ref) => (\n <DropdownMenuPrimitive.SubContent\n ref={ref}\n className={cn(\n \"z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-md\",\n className,\n )}\n {...props}\n />\n));\nDropdownMenuSubContent.displayName = \"DropdownMenuSubContent\";\n","import { type VariantProps, cva } from \"class-variance-authority\";\nimport * as DialogPrimitive from \"@radix-ui/react-dialog\";\nimport { X } from \"lucide-react\";\nimport type {\n ComponentPropsWithoutRef,\n CSSProperties,\n ElementRef,\n HTMLAttributes,\n PointerEvent as ReactPointerEvent,\n ReactElement,\n} from \"react\";\nimport { forwardRef, useEffect, useRef, useState } from \"react\";\nimport { cn } from \"../lib/utils\";\n\nexport const Sheet = DialogPrimitive.Root;\nexport const SheetTrigger = DialogPrimitive.Trigger;\nexport const SheetClose = DialogPrimitive.Close;\nexport const SheetPortal = DialogPrimitive.Portal;\n\nexport const SheetOverlay = forwardRef<\n ElementRef<typeof DialogPrimitive.Overlay>,\n ComponentPropsWithoutRef<typeof DialogPrimitive.Overlay>\n>(({ className, ...props }, ref) => (\n <DialogPrimitive.Overlay\n ref={ref}\n className={cn(\"fixed inset-0 z-50 bg-black/50\", className)}\n {...props}\n />\n));\nSheetOverlay.displayName = \"SheetOverlay\";\n\n// Neither this package nor any other package in the monorepo depends on the\n// `tailwindcss-animate` plugin (grepped for \"animate-in\"/\"tailwindcss-animate\"\n// across the repo — the only pre-existing `data-[state=...]` usages are plain\n// color/background toggles, not that plugin's enter/exit keyframe utilities).\n// Rather than have @bmsuisse/ui silently assume a consumer has that plugin\n// installed, the slide transition here is done with Tailwind's built-in\n// `transition-transform` plus a `translate-x`/`translate-y` toggle driven off\n// Radix's own `data-[state=open]`/`data-[state=closed]` attributes.\nexport const sheetVariants = cva(\n \"fixed z-50 gap-4 bg-background p-6 shadow-lg transition-[transform,box-shadow] duration-300 ease-in-out\",\n {\n variants: {\n side: {\n // Every edge border below is paired with `border-border` explicitly —\n // Tailwind v4's bare `border-*` utilities default to `currentColor`,\n // not the theme's border token, which otherwise renders this seam in\n // the foreground text color (a harsh, high-contrast line in both\n // themes) instead of the intended subtle divider.\n top: \"inset-x-0 top-0 border-b border-border data-[state=closed]:-translate-y-full data-[state=open]:translate-y-0\",\n bottom:\n \"inset-x-0 bottom-0 border-t border-border data-[state=closed]:translate-y-full data-[state=open]:translate-y-0\",\n left: \"inset-y-0 left-0 h-full w-3/4 border-r border-border data-[state=closed]:-translate-x-full data-[state=open]:translate-x-0 sm:max-w-sm\",\n right:\n \"inset-y-0 right-0 h-full w-3/4 border-l border-border data-[state=closed]:translate-x-full data-[state=open]:translate-x-0 sm:max-w-sm\",\n },\n },\n defaultVariants: {\n side: \"right\",\n },\n },\n);\n\nexport interface SheetContentProps\n extends ComponentPropsWithoutRef<typeof DialogPrimitive.Content>,\n VariantProps<typeof sheetVariants> {\n /**\n * Bottom sheets only: adds a drag handle so the user can pull the sheet\n * taller (up to 95% of the viewport) or shorter (down to 30%) with the\n * mouse/touch instead of being stuck with the height set by className.\n * Ignored for other sides.\n */\n resizable?: boolean;\n}\n\n// Off-screen starting transform for the entrance animation below — same\n// direction as each side's own `data-[state=closed]` translate class.\nconst enterFromTransform: Record<\"top\" | \"bottom\" | \"left\" | \"right\", string> = {\n top: \"translateY(-100%)\",\n bottom: \"translateY(100%)\",\n left: \"translateX(-100%)\",\n right: \"translateX(100%)\",\n};\n\nexport const SheetContent = forwardRef<ElementRef<typeof DialogPrimitive.Content>, SheetContentProps>(\n ({ side = \"right\", className, children, resizable = false, style: styleProp, ...props }, ref) => {\n // Radix mounts Content with `data-state=\"open\"` already on first paint,\n // so the `data-[state=...]` translate classes above never see a \"before\"\n // position to transition from — it just appears instead of sliding in.\n // Render one frame off-screen via an inline transform (which overrides\n // the class-based one), then clear it so the transition plays. Exit\n // already animates correctly: Radix flips to `data-state=\"closed\"` while\n // still mounted and defers unmounting until the transition ends.\n const [entered, setEntered] = useState(false);\n useEffect(() => {\n const id = requestAnimationFrame(() => setEntered(true));\n return () => cancelAnimationFrame(id);\n }, []);\n\n // Drag-to-resize: track the sheet's height in local state once the user\n // starts dragging the handle, clamped between 30% and 95% of the\n // viewport height (same bounds as the sheet consumers ported this from).\n const [dragHeight, setDragHeight] = useState<number | null>(null);\n const [isDragging, setIsDragging] = useState(false);\n const dragStart = useRef<{ y: number; height: number } | null>(null);\n const canResize = resizable && side === \"bottom\";\n\n const onHandlePointerDown = (e: ReactPointerEvent<HTMLDivElement>): void => {\n const popup = e.currentTarget.closest('[data-slot=\"sheet-content\"]');\n if (!(popup instanceof HTMLElement)) return;\n e.currentTarget.setPointerCapture(e.pointerId);\n dragStart.current = { y: e.clientY, height: popup.getBoundingClientRect().height };\n setIsDragging(true);\n };\n const onHandlePointerMove = (e: ReactPointerEvent<HTMLDivElement>): void => {\n if (!dragStart.current) return;\n const delta = dragStart.current.y - e.clientY;\n const next = dragStart.current.height + delta;\n const min = window.innerHeight * 0.3;\n const max = window.innerHeight * 0.95;\n setDragHeight(Math.min(max, Math.max(min, next)));\n };\n const onHandlePointerUp = (): void => {\n dragStart.current = null;\n setIsDragging(false);\n };\n\n const style: CSSProperties | undefined = entered\n ? { ...styleProp, ...(canResize && dragHeight != null ? { height: dragHeight, maxHeight: dragHeight } : null) }\n : { ...styleProp, transform: enterFromTransform[side ?? \"right\"] };\n\n return (\n <SheetPortal>\n <SheetOverlay />\n <DialogPrimitive.Content\n ref={ref}\n data-slot=\"sheet-content\"\n style={style}\n className={cn(sheetVariants({ side }), isDragging && \"shadow-2xl\", className)}\n {...props}\n >\n {canResize && (\n <div\n data-testid=\"sheet-drag-handle\"\n className=\"group -mb-2 flex shrink-0 cursor-grab touch-none justify-center py-2 active:cursor-grabbing\"\n onPointerDown={onHandlePointerDown}\n onPointerMove={onHandlePointerMove}\n onPointerUp={onHandlePointerUp}\n onPointerCancel={onHandlePointerUp}\n >\n <div\n className={cn(\n \"h-1 w-10 rounded-full bg-muted-foreground/30 transition-all duration-150 group-hover:w-14 group-hover:bg-muted-foreground/50\",\n isDragging && \"w-14 bg-primary/60\",\n )}\n />\n </div>\n )}\n {children}\n <DialogPrimitive.Close className=\"absolute right-4 top-4 rounded-sm opacity-70 hover:opacity-100\">\n <X className=\"h-4 w-4\" />\n <span className=\"sr-only\">Close</span>\n </DialogPrimitive.Close>\n </DialogPrimitive.Content>\n </SheetPortal>\n );\n },\n);\nSheetContent.displayName = \"SheetContent\";\n\nexport const SheetHeader = ({\n className,\n ...props\n}: HTMLAttributes<HTMLDivElement>): ReactElement => (\n <div className={cn(\"flex flex-col gap-1.5\", className)} {...props} />\n);\n\nexport const SheetFooter = ({\n className,\n ...props\n}: HTMLAttributes<HTMLDivElement>): ReactElement => (\n <div className={cn(\"flex justify-end gap-2\", className)} {...props} />\n);\n\nexport const SheetTitle = forwardRef<\n ElementRef<typeof DialogPrimitive.Title>,\n ComponentPropsWithoutRef<typeof DialogPrimitive.Title>\n>(({ className, ...props }, ref) => (\n <DialogPrimitive.Title ref={ref} className={cn(\"text-lg font-semibold\", className)} {...props} />\n));\nSheetTitle.displayName = \"SheetTitle\";\n\nexport const SheetDescription = forwardRef<\n ElementRef<typeof DialogPrimitive.Description>,\n ComponentPropsWithoutRef<typeof DialogPrimitive.Description>\n>(({ className, ...props }, ref) => (\n <DialogPrimitive.Description\n ref={ref}\n className={cn(\"text-sm text-muted-foreground\", className)}\n {...props}\n />\n));\nSheetDescription.displayName = \"SheetDescription\";\n","import * as TooltipPrimitive from \"@radix-ui/react-tooltip\";\nimport type { ComponentPropsWithoutRef, ElementRef } from \"react\";\nimport { forwardRef } from \"react\";\nimport { cn } from \"../lib/utils\";\n\nexport const TooltipProvider = TooltipPrimitive.Provider;\nexport const Tooltip = TooltipPrimitive.Root;\nexport const TooltipTrigger = TooltipPrimitive.Trigger;\n\nexport const TooltipContent = forwardRef<\n ElementRef<typeof TooltipPrimitive.Content>,\n ComponentPropsWithoutRef<typeof TooltipPrimitive.Content>\n>(({ className, sideOffset = 4, ...props }, ref) => (\n <TooltipPrimitive.Portal>\n <TooltipPrimitive.Content\n ref={ref}\n sideOffset={sideOffset}\n className={cn(\n \"z-50 overflow-hidden rounded-md border bg-popover px-3 py-1.5 text-xs text-popover-foreground shadow-md\",\n className,\n )}\n {...props}\n />\n </TooltipPrimitive.Portal>\n));\nTooltipContent.displayName = \"TooltipContent\";\n","import type { ReactElement, ReactNode } from \"react\";\nimport {\n Dialog,\n DialogContent,\n DialogDescription,\n DialogFooter,\n DialogHeader,\n DialogTitle,\n} from \"../../primitives/dialog\";\n\nexport interface ModalProps {\n /** Whether the modal is open. Modal is fully controlled — no internal open state. */\n open: boolean;\n /** Called when Radix wants to change the open state (backdrop click, Esc, close button). */\n onOpenChange: (open: boolean) => void;\n /** Dialog title, rendered in `DialogTitle`. */\n title: string;\n /** Optional supporting copy, rendered in `DialogDescription` under the title. */\n description?: string;\n /** Body content of the modal. */\n children: ReactNode;\n /** Optional footer content (typically action buttons), rendered in `DialogFooter`. */\n footer?: ReactNode;\n /** Extra classes applied to `DialogContent`, e.g. to override the default width. */\n className?: string;\n}\n\n/**\n * Base structural wrapper around the `@bmsuisse/ui` Dialog primitives: title,\n * optional description, body, and an optional footer. Use this directly for\n * modals that don't fit `ConfirmDialog` or `FormModal`; those two are built\n * on top of the same shape.\n */\nexport const Modal = ({\n open,\n onOpenChange,\n title,\n description,\n children,\n footer,\n className,\n}: ModalProps): ReactElement => (\n <Dialog open={open} onOpenChange={onOpenChange}>\n <DialogContent className={className}>\n <DialogHeader>\n <DialogTitle>{title}</DialogTitle>\n {description ? <DialogDescription>{description}</DialogDescription> : null}\n </DialogHeader>\n {children}\n {footer ? <DialogFooter>{footer}</DialogFooter> : null}\n </DialogContent>\n </Dialog>\n);\n","import type { ReactElement } from \"react\";\nimport { useState } from \"react\";\nimport { Button } from \"../../primitives/button\";\nimport { DialogActions } from \"./DialogActions\";\nimport { Modal } from \"./Modal\";\n\nexport interface ConfirmDialogProps {\n /** Whether the dialog is open. Fully controlled — no internal open state. */\n open: boolean;\n /** Called when Radix wants to change the open state (backdrop click, Esc, close button). */\n onOpenChange: (open: boolean) => void;\n /** Dialog title. */\n title: string;\n /** Optional supporting copy shown under the title. */\n description?: string;\n /** Label for the confirm button. Defaults to `\"Confirm\"`. */\n confirmLabel?: string;\n /** Label for the cancel button. Defaults to `\"Cancel\"`. */\n cancelLabel?: string;\n /** Called when the user clicks confirm. May return a promise; the dialog waits for it. */\n onConfirm: () => void | Promise<void>;\n /** Visual style of the confirm button. Defaults to `\"default\"`. */\n variant?: \"default\" | \"destructive\";\n /** Forwarded to the confirm button, for test targeting (e.g. Playwright/Testing Library). */\n confirmTestId?: string;\n /** Forwarded to the cancel button, for test targeting. */\n cancelTestId?: string;\n}\n\n/**\n * \"Are you sure?\" confirmation dialog. Unlike `FormModal`, this DOES close\n * itself automatically after a successful `onConfirm` — confirmations are a\n * single yes/no action with no follow-up state to inspect, so there's nothing\n * for the caller to decide. If `onConfirm` throws/rejects, the dialog stays\n * open and the error is not swallowed, so a caller can surface its own error\n * UI without the dialog disappearing out from under it.\n */\nexport const ConfirmDialog = ({\n open,\n onOpenChange,\n title,\n description,\n confirmLabel = \"Confirm\",\n cancelLabel = \"Cancel\",\n onConfirm,\n variant = \"default\",\n confirmTestId,\n cancelTestId,\n}: ConfirmDialogProps): ReactElement => {\n const [pending, setPending] = useState(false);\n\n const handleCancel = (): void => {\n onOpenChange(false);\n };\n\n const handleConfirm = async (): Promise<void> => {\n setPending(true);\n try {\n await onConfirm();\n onOpenChange(false);\n } catch (error) {\n // Do not swallow the failure into a silent no-op: surface it (the\n // caller's own error UI is the right place to react to it in detail)\n // and, critically, leave the dialog open instead of closing it as if\n // nothing happened.\n console.error(error);\n } finally {\n setPending(false);\n }\n };\n\n const cancelButton = (\n <Button variant=\"outline\" onClick={handleCancel} disabled={pending} data-testid={cancelTestId}>\n {cancelLabel}\n </Button>\n );\n const confirmButton = (\n <Button\n variant={variant === \"destructive\" ? \"destructive\" : \"default\"}\n onClick={handleConfirm}\n disabled={pending}\n data-testid={confirmTestId}\n >\n {pending ? `${confirmLabel}…` : confirmLabel}\n </Button>\n );\n\n return (\n <Modal\n open={open}\n onOpenChange={onOpenChange}\n title={title}\n description={description}\n footer={<DialogActions actions={[confirmButton]} cancel={cancelButton} />}\n >\n {null}\n </Modal>\n );\n};\n","import type { Key, ReactElement, ReactNode } from \"react\";\nimport { Fragment, useState } from \"react\";\nimport { getConfirmButtonPlacement } from \"../../lib/platform\";\n\nexport interface DialogActionsProps {\n /**\n * The dialog's non-cancel actions, ordered from *nearest to Cancel* to\n * *most primary* — e.g. `[secondaryAction, primaryAction]`. For a plain\n * two-button confirm dialog, pass a single primary action here.\n */\n actions: ReactNode[];\n /** The dismissive/cancel action. */\n cancel: ReactNode;\n}\n\n/**\n * Renders `actions` and `cancel` in the order the current platform's own\n * dialogs use — Windows puts Cancel on the right (trailing), every other\n * platform we target (iOS/iPadOS, macOS, Android, Linux) puts it on the\n * left (leading) — instead of a fixed order every caller has to get right\n * itself. `ConfirmDialog` and `QuestionDialog` use this internally; use it\n * directly for any other dialog/panel footer with the same\n * actions-plus-cancel shape.\n *\n * Matches native multi-button \"Save changes?\"-style dialogs: the most\n * primary action sits at the edge *opposite* Cancel (Windows:\n * `Save · Don't Save · Cancel`; iOS/macOS: `Cancel · Don't Save · Save`),\n * not next to it. `actions` is reversed when Cancel sits on the right\n * (Windows), so the last element of `actions` — the primary action — is\n * always the one furthest from Cancel, and the first element is always the\n * one nearest Cancel, regardless of platform — a caller picks the order\n * once, by meaning, and doesn't have to reason about which edge Cancel\n * lands on.\n *\n * Renders no wrapping element of its own — nest it inside the caller's own\n * footer container (e.g. `DialogFooter`, or `Modal`'s `footer` prop) for\n * layout/spacing.\n */\nexport function DialogActions({ actions, cancel }: DialogActionsProps): ReactElement {\n // Platform doesn't change mid-session, so this is computed once rather\n // than re-read from `navigator` on every render.\n const [placement] = useState(getConfirmButtonPlacement);\n const cancelLeading = placement === \"trailing\";\n const ordered = cancelLeading ? actions : [...actions].reverse();\n\n const renderedActions = ordered.map((action, index) => (\n <Fragment key={actionKey(action, index)}>{action}</Fragment>\n ));\n\n return cancelLeading ? (\n <>\n {cancel}\n {renderedActions}\n </>\n ) : (\n <>\n {renderedActions}\n {cancel}\n </>\n );\n}\n\nfunction actionKey(action: ReactNode, index: number): Key {\n if (action && typeof action === \"object\" && \"key\" in action && action.key !== null) return action.key as Key;\n return index;\n}\n","/**\n * Whether the current runtime is Windows, based on the UA string. Returns\n * `false` outside a browser (SSR, tests) so platform-dependent UI falls back\n * to the non-Windows default rather than guessing.\n */\nexport function isWindowsPlatform(): boolean {\n if (typeof navigator === \"undefined\") return false;\n return /Windows/i.test(navigator.userAgent);\n}\n\nexport type ConfirmButtonPlacement = \"leading\" | \"trailing\";\n\n/**\n * Where a dialog's affirmative/confirm button should sit, matching each\n * platform's own system convention: Windows dialogs place OK/Save on the\n * left (Cancel on the right); every other platform we target — iOS/iPadOS,\n * macOS, Android, Linux — places the affirmative action on the right (the\n * iOS/macOS Human Interface Guidelines require this, and it's the de facto\n * default everywhere else too). Windows is the one exception, so this is\n * driven entirely by `isWindowsPlatform`.\n */\nexport function getConfirmButtonPlacement(): ConfirmButtonPlacement {\n return isWindowsPlatform() ? \"leading\" : \"trailing\";\n}\n","import type { FormEvent, ReactElement, ReactNode } from \"react\";\nimport { useState } from \"react\";\nimport { Button } from \"../../primitives/button\";\nimport {\n Dialog,\n DialogContent,\n DialogDescription,\n DialogFooter,\n DialogHeader,\n DialogTitle,\n} from \"../../primitives/dialog\";\n\nexport interface FormModalProps {\n /** Whether the modal is open. Fully controlled — no internal open state. */\n open: boolean;\n /** Called when Radix wants to change the open state (backdrop click, Esc, close button). */\n onOpenChange: (open: boolean) => void;\n /** Dialog title. */\n title: string;\n /** Optional supporting copy shown under the title. */\n description?: string;\n /** Form field content, rendered inside the `<form>`. */\n children: ReactNode;\n /** Called on submit (button click or Enter in a field). May return a promise. */\n onSubmit: () => void | Promise<void>;\n /** Label for the submit button. Defaults to `\"Save\"`. */\n submitLabel?: string;\n /** Label for the cancel button. Defaults to `\"Cancel\"`. */\n cancelLabel?: string;\n /**\n * Disables the submit button (e.g. required fields still empty), on top of\n * the automatic disable while `onSubmit`'s promise is pending. Cancel\n * stays enabled either way. Defaults to `false`.\n */\n submitDisabled?: boolean;\n /** Extra classes applied to `DialogContent`, e.g. to override the default width. */\n className?: string;\n /** Forwarded to the submit button, for test targeting (e.g. Playwright/Testing Library). */\n submitTestId?: string;\n /** Forwarded to the cancel button, for test targeting. */\n cancelTestId?: string;\n}\n\n/**\n * Modal wrapping a form. Unlike `ConfirmDialog`, this does NOT close itself\n * after a successful `onSubmit` — forms commonly have server-side validation\n * and shouldn't vanish on failure, so closing after success is left entirely\n * to the caller (typically by calling `onOpenChange(false)` once its own\n * submit handler resolves without error).\n */\nexport const FormModal = ({\n open,\n onOpenChange,\n title,\n description,\n children,\n onSubmit,\n submitLabel = \"Save\",\n cancelLabel = \"Cancel\",\n submitDisabled = false,\n className,\n submitTestId,\n cancelTestId,\n}: FormModalProps): ReactElement => {\n const [pending, setPending] = useState(false);\n\n const handleSubmit = async (event: FormEvent<HTMLFormElement>): Promise<void> => {\n event.preventDefault();\n setPending(true);\n try {\n await onSubmit();\n } finally {\n setPending(false);\n }\n };\n\n const handleCancel = (): void => {\n onOpenChange(false);\n };\n\n return (\n <Dialog open={open} onOpenChange={onOpenChange}>\n <DialogContent className={className}>\n <form onSubmit={handleSubmit}>\n <DialogHeader>\n <DialogTitle>{title}</DialogTitle>\n {description ? <DialogDescription>{description}</DialogDescription> : null}\n </DialogHeader>\n {children}\n <DialogFooter>\n <Button\n type=\"button\"\n variant=\"outline\"\n onClick={handleCancel}\n disabled={pending}\n data-testid={cancelTestId}\n >\n {cancelLabel}\n </Button>\n <Button type=\"submit\" disabled={pending || submitDisabled} data-testid={submitTestId}>\n {pending ? `${submitLabel}…` : submitLabel}\n </Button>\n </DialogFooter>\n </form>\n </DialogContent>\n </Dialog>\n );\n};\n","import type { CSSProperties, PointerEvent as ReactPointerEvent, ReactElement, ReactNode } from \"react\";\nimport { useRef, useState } from \"react\";\nimport { useMediaQuery } from \"../../lib/useMediaQuery\";\nimport { cn } from \"../../lib/utils\";\nimport {\n Dialog,\n DialogContent,\n DialogDescription,\n DialogFooter,\n DialogHeader,\n DialogTitle,\n} from \"../../primitives/dialog\";\nimport {\n Sheet,\n SheetContent,\n SheetDescription,\n SheetFooter,\n SheetHeader,\n SheetTitle,\n} from \"../../primitives/sheet\";\n\nconst desktopSizeClasses = {\n sm: \"max-w-md\",\n md: \"max-w-xl\",\n lg: \"max-w-2xl\",\n xl: \"max-w-7xl\",\n} as const;\n\nconst drawerSizeClasses = {\n sm: \"max-h-[50vh]\",\n md: \"max-h-[70vh]\",\n lg: \"max-h-[90vh]\",\n xl: \"max-h-[96vh]\",\n} as const;\n\nexport type ResponsivePanelSize = keyof typeof desktopSizeClasses;\n\nconst MIN_PANEL_WIDTH = 320;\nconst MIN_PANEL_HEIGHT = 240;\nconst VIEWPORT_MARGIN = 16;\n\ntype Corner = \"top-left\" | \"top-right\" | \"bottom-left\" | \"bottom-right\";\n\nconst cornerCursor: Record<Corner, string> = {\n \"top-left\": \"cursor-nwse-resize\",\n \"bottom-right\": \"cursor-nwse-resize\",\n \"top-right\": \"cursor-nesw-resize\",\n \"bottom-left\": \"cursor-nesw-resize\",\n};\n\nconst cornerPosition: Record<Corner, string> = {\n \"top-left\": \"left-0 top-0\",\n \"top-right\": \"right-0 top-0\",\n \"bottom-left\": \"left-0 bottom-0\",\n \"bottom-right\": \"right-0 bottom-0\",\n};\n\nconst cornerGripPosition: Record<Corner, string> = {\n \"top-left\": \"left-1 top-1 border-l-2 border-t-2\",\n \"top-right\": \"right-1 top-1 border-r-2 border-t-2\",\n \"bottom-left\": \"left-1 bottom-1 border-l-2 border-b-2\",\n \"bottom-right\": \"right-1 bottom-1 border-r-2 border-b-2\",\n};\n\ninterface Rect {\n left: number;\n top: number;\n width: number;\n height: number;\n}\n\ninterface DragState {\n mode: \"move\" | \"resize\";\n corner?: Corner;\n x: number;\n y: number;\n rect: Rect;\n}\n\n// Drag the dialog's header to move it, or a corner handle to resize it from\n// that corner (the opposite corner stays anchored). Radix centers the dialog\n// with a translate-based className, so once the user starts dragging we\n// switch to explicit fixed left/top/width/height (inline styles beat the\n// class-based transform/size utilities) and never go back to the centered\n// layout for that open panel. Both left/top and width/height are always\n// clamped to a viewport margin so the panel can never end up positioned\n// (partly) off-screen with no way to drag it back.\n//\n// The anchor rect for a new drag comes from `lastRect` (the geometry we set\n// ourselves on the previous drag) rather than a fresh `getBoundingClientRect()`\n// call whenever one is available — re-measuring the DOM right as a new\n// pointerdown fires occasionally raced with layout and returned a stale box,\n// which made a resize immediately after a move jump the panel off-screen.\nfunction useDesktopPanelGeometry(): {\n style: CSSProperties | undefined;\n isDragging: boolean;\n startMove: (e: ReactPointerEvent<HTMLDivElement>) => void;\n startResize: (corner: Corner) => (e: ReactPointerEvent<HTMLDivElement>) => void;\n onPointerMove: (e: ReactPointerEvent<HTMLDivElement>) => void;\n onPointerUp: () => void;\n} {\n const [style, setStyle] = useState<CSSProperties | undefined>(undefined);\n const [isDragging, setIsDragging] = useState(false);\n const drag = useRef<DragState | null>(null);\n const lastRect = useRef<Rect | null>(null);\n\n const beginDrag =\n (mode: \"move\" | \"resize\", corner?: Corner) =>\n (e: ReactPointerEvent<HTMLDivElement>): void => {\n const content = e.currentTarget.closest('[data-slot=\"dialog-content\"]');\n if (!(content instanceof HTMLElement)) return;\n e.currentTarget.setPointerCapture(e.pointerId);\n const domRect = content.getBoundingClientRect();\n const rect = lastRect.current ?? {\n left: domRect.left,\n top: domRect.top,\n width: domRect.width,\n height: domRect.height,\n };\n drag.current = { mode, corner, x: e.clientX, y: e.clientY, rect };\n setIsDragging(true);\n };\n\n const onPointerMove = (e: ReactPointerEvent<HTMLDivElement>): void => {\n const state = drag.current;\n if (!state) return;\n const deltaX = e.clientX - state.x;\n const deltaY = e.clientY - state.y;\n\n if (state.mode === \"move\") {\n const maxLeft = window.innerWidth - VIEWPORT_MARGIN - state.rect.width;\n const maxTop = window.innerHeight - VIEWPORT_MARGIN - state.rect.height;\n const next: Rect = {\n left: Math.min(maxLeft, Math.max(VIEWPORT_MARGIN, state.rect.left + deltaX)),\n top: Math.min(maxTop, Math.max(VIEWPORT_MARGIN, state.rect.top + deltaY)),\n width: state.rect.width,\n height: state.rect.height,\n };\n lastRect.current = next;\n setStyle({ position: \"fixed\", transform: \"none\", translate: \"none\", maxWidth: \"none\", maxHeight: \"none\", ...next });\n return;\n }\n\n const corner = state.corner ?? \"top-left\";\n const growsLeft = corner === \"top-left\" || corner === \"bottom-left\";\n const growsUp = corner === \"top-left\" || corner === \"top-right\";\n const right = state.rect.left + state.rect.width;\n const bottom = state.rect.top + state.rect.height;\n const maxWidth = window.innerWidth - VIEWPORT_MARGIN * 2;\n const maxHeight = window.innerHeight - VIEWPORT_MARGIN * 2;\n\n let width = Math.max(\n MIN_PANEL_WIDTH,\n Math.min(maxWidth, growsLeft ? state.rect.width - deltaX : state.rect.width + deltaX),\n );\n let height = Math.max(\n MIN_PANEL_HEIGHT,\n Math.min(maxHeight, growsUp ? state.rect.height - deltaY : state.rect.height + deltaY),\n );\n\n // Clamp the moving edge to the viewport margin too, so growing toward\n // an edge never pushes the opposite (anchored) edge off-screen.\n const left = growsLeft ? right - Math.min(width, right - VIEWPORT_MARGIN) : state.rect.left;\n width = growsLeft ? right - left : Math.min(width, window.innerWidth - VIEWPORT_MARGIN - state.rect.left);\n\n const top = growsUp ? bottom - Math.min(height, bottom - VIEWPORT_MARGIN) : state.rect.top;\n height = growsUp ? bottom - top : Math.min(height, window.innerHeight - VIEWPORT_MARGIN - state.rect.top);\n\n const next: Rect = { left, top, width, height };\n lastRect.current = next;\n setStyle({ position: \"fixed\", transform: \"none\", translate: \"none\", maxWidth: \"none\", maxHeight: \"none\", ...next });\n };\n\n const onPointerUp = (): void => {\n drag.current = null;\n setIsDragging(false);\n };\n\n return {\n style,\n isDragging,\n startMove: beginDrag(\"move\"),\n startResize: (corner) => beginDrag(\"resize\", corner),\n onPointerMove,\n onPointerUp,\n };\n}\n\nexport interface ResponsivePanelProps {\n /** Whether the panel is open. Fully controlled — no internal open state. */\n open: boolean;\n /** Called when Radix wants to change the open state (backdrop click, Esc, close button). */\n onOpenChange: (open: boolean) => void;\n /** Panel title. */\n title: string;\n /** Optional supporting copy shown under the title. */\n description?: string;\n /** Body content of the panel. */\n children: ReactNode;\n /** Optional footer content (typically action buttons). */\n footer?: ReactNode;\n /** Extra classes applied to the panel content, e.g. to override the default width/height. */\n className?: string;\n /**\n * `matchMedia` query that decides desktop vs. mobile layout. Defaults to\n * Tailwind's `lg` breakpoint, matching the rest of `@bmsuisse/ui`'s responsive patterns.\n */\n breakpoint?: string;\n /**\n * Panel size, `sm`/`md`/`lg` (default)/`xl`. On desktop this is the dialog\n * width (`max-w-md`/`max-w-xl`/`max-w-2xl`/`max-w-4xl`); on mobile — where\n * width is always full-bleed — it's the drawer's max height instead\n * (`50vh`/`70vh`/`90vh`/`96vh`).\n */\n size?: ResponsivePanelSize;\n /**\n * Adds drag handles so the user can resize the panel with the mouse:\n * on desktop, a grip on all four corners (each anchors the opposite\n * corner, so `size` just becomes the starting size); on the mobile\n * drawer, a handle at the top (drags height between 30vh and 95vh).\n * Default `false`.\n */\n resizable?: boolean;\n /**\n * Desktop only: lets the user drag the panel by its header to reposition\n * it anywhere in the viewport. Default `false`. No effect on the mobile\n * drawer, which is always docked to the bottom.\n */\n draggable?: boolean;\n /**\n * Whether clicking/tapping outside the panel closes it. Default `true`.\n * When `false`, only the header's close button (and Esc) can close it —\n * use this for panels guarding unsaved work the user shouldn't lose to a\n * stray click.\n */\n closeOnOutsideClick?: boolean;\n}\n\n/**\n * Like `Modal`, but uses the extra desktop space instead of a fixed small\n * dialog, and becomes a native bottom-sheet drawer below `breakpoint` — a\n * centered floating box with its own scroll region reads as a leftover\n * desktop shape on a phone. Use this over `Modal` for content that benefits\n * from more room (multi-section forms, longer lists) on both form factors.\n */\nexport const ResponsivePanel = ({\n open,\n onOpenChange,\n title,\n description,\n children,\n footer,\n className,\n breakpoint = \"(min-width: 1024px)\",\n size = \"lg\",\n resizable = false,\n draggable = false,\n closeOnOutsideClick = true,\n}: ResponsivePanelProps): ReactElement => {\n const isDesktop = useMediaQuery(breakpoint);\n const geometry = useDesktopPanelGeometry();\n const onInteractOutside = closeOnOutsideClick ? undefined : (e: Event): void => e.preventDefault();\n\n if (isDesktop) {\n const corners: Corner[] = [\"top-left\", \"top-right\", \"bottom-left\", \"bottom-right\"];\n return (\n <Dialog open={open} onOpenChange={onOpenChange}>\n <DialogContent\n data-slot=\"dialog-content\"\n onInteractOutside={onInteractOutside}\n style={resizable || draggable ? geometry.style : undefined}\n className={cn(\n \"max-h-[85vh] overflow-y-auto transition-shadow duration-150 ease-out\",\n geometry.isDragging && \"shadow-2xl ring-2 ring-primary/30\",\n desktopSizeClasses[size],\n className,\n )}\n >\n {resizable &&\n corners.map((corner) => (\n <div\n key={corner}\n data-testid={`panel-resize-handle-${corner}`}\n className={cn(\n \"group absolute h-4 w-4 touch-none\",\n cornerPosition[corner],\n cornerCursor[corner],\n )}\n onPointerDown={geometry.startResize(corner)}\n onPointerMove={geometry.onPointerMove}\n onPointerUp={geometry.onPointerUp}\n onPointerCancel={geometry.onPointerUp}\n >\n <div\n className={cn(\n \"absolute h-2 w-2 scale-100 border-muted-foreground/40 transition-transform duration-150 group-hover:scale-125 group-hover:border-primary/60\",\n cornerGripPosition[corner],\n )}\n />\n </div>\n ))}\n <DialogHeader\n className={cn(draggable && \"touch-none cursor-move select-none\")}\n onPointerDown={draggable ? geometry.startMove : undefined}\n onPointerMove={draggable ? geometry.onPointerMove : undefined}\n onPointerUp={draggable ? geometry.onPointerUp : undefined}\n onPointerCancel={draggable ? geometry.onPointerUp : undefined}\n >\n <DialogTitle>{title}</DialogTitle>\n {description ? <DialogDescription>{description}</DialogDescription> : null}\n </DialogHeader>\n {children}\n {footer ? <DialogFooter>{footer}</DialogFooter> : null}\n </DialogContent>\n </Dialog>\n );\n }\n\n return (\n <Sheet open={open} onOpenChange={onOpenChange}>\n <SheetContent\n side=\"bottom\"\n resizable={resizable}\n onInteractOutside={onInteractOutside}\n className={cn(\n \"flex flex-col overflow-y-auto rounded-t-2xl\",\n drawerSizeClasses[size],\n className,\n )}\n >\n <SheetHeader>\n <SheetTitle>{title}</SheetTitle>\n {description ? <SheetDescription>{description}</SheetDescription> : null}\n </SheetHeader>\n {children}\n {footer ? <SheetFooter>{footer}</SheetFooter> : null}\n </SheetContent>\n </Sheet>\n );\n};\n","import { useEffect, useState } from \"react\";\n\n/**\n * Tracks whether a `matchMedia` query currently matches, updating on change.\n * Used to switch between desktop/mobile layouts (see `ResponsivePanel`).\n */\nexport function useMediaQuery(query: string): boolean {\n const [matches, setMatches] = useState(() =>\n typeof window !== \"undefined\" ? window.matchMedia(query).matches : false,\n );\n\n useEffect(() => {\n const mq = window.matchMedia(query);\n setMatches(mq.matches);\n const handler = (e: MediaQueryListEvent): void => setMatches(e.matches);\n mq.addEventListener(\"change\", handler);\n return () => mq.removeEventListener(\"change\", handler);\n }, [query]);\n\n return matches;\n}\n","import type { ReactElement } from \"react\";\nimport { useState } from \"react\";\nimport { Button, type ButtonProps } from \"../../primitives/button\";\nimport { DialogActions } from \"./DialogActions\";\nimport { Modal } from \"./Modal\";\n\nexport interface QuestionDialogAction {\n /** Button label. */\n label: string;\n /** Called when this action is clicked. May return a promise; the dialog waits for it before closing. */\n onClick: () => void | Promise<void>;\n /** Visual style of this action's button. Defaults to `\"default\"`. */\n variant?: ButtonProps[\"variant\"];\n /** Forwarded to this action's `Button`, for test targeting. */\n testId?: string;\n}\n\nexport interface QuestionDialogProps {\n /** Whether the dialog is open. Fully controlled — no internal open state. */\n open: boolean;\n /** Called when Radix wants to change the open state (backdrop click, Esc, close button, Cancel). */\n onOpenChange: (open: boolean) => void;\n /** Dialog title. */\n title: string;\n /** Optional supporting copy shown under the title. */\n description?: string;\n /**\n * The dialog's non-cancel actions, ordered from *nearest Cancel* to *most\n * primary* (see `DialogActions`) — e.g.\n * `[{ label: \"Don't Save\", ... }, { label: \"Save\", ... }]` puts \"Save\",\n * the primary action, at the edge opposite Cancel on every platform,\n * matching native \"Save changes?\"-style dialogs.\n */\n actions: QuestionDialogAction[];\n /** Label for the cancel button. Defaults to `\"Cancel\"`. */\n cancelLabel?: string;\n /** Forwarded to the cancel button, for test targeting. */\n cancelTestId?: string;\n}\n\n/**\n * A dialog asking a question with any number of actions plus a Cancel —\n * `ConfirmDialog` generalized past the fixed confirm/cancel pair, for\n * prompts like \"Save changes before closing?\" (Don't Save / Cancel / Save).\n * Like `ConfirmDialog`, it closes itself automatically after a successful\n * action click — if the clicked action's `onClick` throws/rejects, the\n * dialog stays open (and the error isn't swallowed) so a caller can surface\n * its own error UI. Cancel always closes immediately.\n *\n * Button order follows the current platform's own convention via\n * `DialogActions` — pick `actions`' order by *meaning* (least to most\n * primary), not by which edge Cancel happens to land on.\n */\nexport const QuestionDialog = ({\n open,\n onOpenChange,\n title,\n description,\n actions,\n cancelLabel = \"Cancel\",\n cancelTestId,\n}: QuestionDialogProps): ReactElement => {\n const [pendingIndex, setPendingIndex] = useState<number | null>(null);\n const pending = pendingIndex !== null;\n\n const handleCancel = (): void => {\n onOpenChange(false);\n };\n\n const handleActionClick = async (action: QuestionDialogAction, index: number): Promise<void> => {\n setPendingIndex(index);\n try {\n await action.onClick();\n onOpenChange(false);\n } catch (error) {\n // Do not swallow the failure into a silent no-op: surface it (the\n // caller's own error UI is the right place to react to it in detail)\n // and, critically, leave the dialog open instead of closing it as if\n // nothing happened.\n console.error(error);\n } finally {\n setPendingIndex(null);\n }\n };\n\n return (\n <Modal\n open={open}\n onOpenChange={onOpenChange}\n title={title}\n description={description}\n footer={\n <DialogActions\n actions={actions.map((action, index) => (\n <Button\n key={action.label}\n variant={action.variant ?? \"default\"}\n onClick={() => handleActionClick(action, index)}\n disabled={pending}\n data-testid={action.testId}\n >\n {pendingIndex === index ? `${action.label}…` : action.label}\n </Button>\n ))}\n cancel={\n <Button variant=\"outline\" onClick={handleCancel} disabled={pending} data-testid={cancelTestId}>\n {cancelLabel}\n </Button>\n }\n />\n }\n >\n {null}\n </Modal>\n );\n};\n","import type { ReactElement } from \"react\";\nimport { cloneElement, isValidElement, useId } from \"react\";\nimport { cn } from \"../../lib/utils\";\nimport { Label } from \"../../primitives/label\";\n\nexport interface FormFieldProps {\n /** Visible label text for the field. */\n label: string;\n /** Explicit id to associate the label with the child control. Auto-generated when omitted. */\n htmlFor?: string;\n /** Validation error text. When set, takes precedence over `description` and marks the child as invalid. */\n error?: string;\n /** Helper text shown below the child control when there's no `error`. */\n description?: string;\n /** Renders a visual \"required\" indicator next to the label. */\n required?: boolean;\n /** The single form control (e.g. `Input`, `Textarea`, `Select`) this field wraps. */\n children: ReactElement;\n /** Additional class names for the outer wrapper. */\n className?: string;\n}\n\n/**\n * Wraps a single form control with a `Label`, optional required indicator, and\n * either an `error` or `description` message — the \"label + input + error\"\n * pattern used throughout the consuming apps' forms.\n *\n * Handles id plumbing automatically: generates a stable id (via `useId`) for\n * the label/control pair unless `htmlFor` or the child's own `id` is set, and\n * wires up `aria-invalid` / `aria-describedby` so the error or description\n * text is announced by assistive tech.\n */\nexport function FormField({\n label,\n htmlFor,\n error,\n description,\n required,\n children,\n className,\n}: FormFieldProps): ReactElement {\n const generatedId = useId();\n const resolvedId = htmlFor ?? generatedId;\n const isSingleElement = isValidElement(children);\n const existingChildId = isSingleElement\n ? (children.props as { id?: string }).id\n : undefined;\n const effectiveId = existingChildId ?? resolvedId;\n\n const message = error ?? description;\n const messageId = message ? `${effectiveId}-message` : undefined;\n\n const child = isSingleElement\n ? cloneElement(\n children as ReactElement<{\n id?: string;\n \"aria-invalid\"?: boolean;\n \"aria-describedby\"?: string;\n }>,\n {\n id: effectiveId,\n ...(error ? { \"aria-invalid\": true } : {}),\n ...(messageId ? { \"aria-describedby\": messageId } : {}),\n },\n )\n : children;\n\n return (\n <div className={cn(\"flex flex-col gap-1.5\", className)}>\n <Label htmlFor={effectiveId}>\n {label}\n {required ? (\n <span className=\"text-destructive\" aria-hidden=\"true\">\n {\" \"}\n *\n </span>\n ) : null}\n </Label>\n {child}\n {error ? (\n <p id={messageId} className=\"text-sm text-destructive\">\n {error}\n </p>\n ) : description ? (\n <p id={messageId} className=\"text-sm text-muted-foreground\">\n {description}\n </p>\n ) : null}\n </div>\n );\n}\n","import { Check, ChevronsUpDown, X } from \"lucide-react\";\nimport type { ComponentProps, KeyboardEvent, ReactElement, ReactNode } from \"react\";\nimport { useEffect, useMemo, useRef, useState } from \"react\";\nimport { cn } from \"../../lib/utils\";\nimport {\n buildRenderChunks,\n groupCheckState,\n groupMembers,\n type OptionRow as ImportedOptionRow,\n} from \"../../lib/optionGrouping\";\nimport { renderGridOptions, type GridColumn } from \"../../lib/optionGrid\";\nimport { Button } from \"../../primitives/button\";\nimport { Input } from \"../../primitives/input\";\nimport { Popover, PopoverContent, PopoverTrigger } from \"../../primitives/popover\";\n\nexport interface ComboboxOption {\n value: string;\n label: string;\n disabled?: boolean;\n /** Groups this option under a header with the given key, rendered as a bold label\n * (plus a tri-state \"select all\" checkbox in multi-select mode — see `groupLabels`\n * on the base props). Options sharing a `group` must be contiguous in `options` —\n * the component renders a header the first time a group key is seen and does not\n * re-sort the list, so interleaved groups would render more than one header for the\n * same key. Ungrouped options (no `group`) render individually, with no header.\n * Ignored when `columns` is set (see that prop's own doc). */\n group?: string;\n /** Extra fields for this option, surfaced as additional columns when the\n * base props' `columns` is set — e.g. `{ email: \"a@b.com\", role: \"Admin\" }`.\n * Ignored otherwise. */\n data?: Record<string, ReactNode>;\n}\n\ninterface ComboboxBaseProps {\n /** The full option list. Filtering happens client-side against `label`. */\n options: ComboboxOption[];\n /** Trigger text shown when nothing is selected. Defaults to `\"Select…\"`. */\n placeholder?: string;\n /** Placeholder for the search input inside the popover. Defaults to `\"Search…\"`. */\n searchPlaceholder?: string;\n /** Shown when the search term matches nothing. Defaults to `\"No matches.\"`. */\n emptyMessage?: string;\n disabled?: boolean;\n /** Shows `loadingMessage` on the trigger instead of the placeholder/selection, and\n * disables the trigger and clear affordance alongside `disabled`. For a combobox whose\n * `options` are still being fetched. Defaults to `false`. */\n loading?: boolean;\n /** Trigger text shown while `loading` is true. Defaults to `\"Loading…\"`. */\n loadingMessage?: string;\n /** Shows a clear (\"x\") affordance on the trigger when a value is selected. Defaults to `true`. */\n clearable?: boolean;\n className?: string;\n id?: string;\n /** Forwarded to the trigger button, for test targeting (e.g. Playwright/Testing Library). */\n \"data-testid\"?: string;\n /** Display label for a group key (`ComboboxOption.group`). Falls back to the raw key\n * when an entry is missing. Only relevant when at least one option sets `group`. */\n groupLabels?: Record<string, string>;\n /** Portal target for the popover, forwarded to the underlying `PopoverContent`.\n * Needed when the combobox is opened from inside a modal Dialog/Sheet — pass the\n * Dialog/Sheet content element so the popover portals inside it instead of\n * `document.body`, which would otherwise fight with the Dialog's focus trap. */\n container?: ComponentProps<typeof PopoverContent>[\"container\"];\n /** Switches the search input to server-driven mode: called with the raw search\n * text on every keystroke (and with `\"\"` when the popover opens), and `options`\n * is rendered as-is instead of being filtered locally against `label`. Omit for\n * the default client-side filtering behavior. */\n onSearchChange?: (search: string) => void;\n /** Fallback trigger label used when the current selection's `value`(s) aren't\n * present in `options` — the case in server-driven search mode where the\n * selected option was found by an earlier query and isn't part of the current\n * result page. Ignored once a matching option is found in `options`. */\n selectedLabel?: string;\n /** Renders the popup's option list as a multi-column grid instead of a flat\n * label list — one column per entry here, each reading either the option's\n * own `label` (`key: \"label\"`) or `option.data[key]`. Useful when users need\n * more context than a label to tell options apart (e.g. an id/email/role\n * table instead of a bare name). Mutually exclusive with `group` — a grid\n * row has no natural place for a group header spanning several unrelated\n * columns, so `group` is ignored on every option while this is set. The\n * popup grows to fit the columns (at least as wide as the trigger). */\n columns?: GridColumn[];\n}\n\nexport interface ComboboxSingleProps extends ComboboxBaseProps {\n /** Omitted or `false` for the (default) single-select shape below. */\n multiple?: false;\n /** Selected option's `value`, or `null`/`undefined` for no selection. */\n value?: string | null;\n /** Called with the newly selected option's `value`, or `null` when cleared. */\n onChange: (value: string | null) => void;\n}\n\nexport interface ComboboxMultiProps extends ComboboxBaseProps {\n /** `true` selects the multi-select shape below. */\n multiple: true;\n /** Selected options' `value`s. */\n value: string[];\n /** Called with the full updated selection after a toggle, or `[]` when cleared. */\n onChange: (value: string[]) => void;\n}\n\n/**\n * Discriminated on `multiple`: the default (omitted/`false`) shape is the\n * original single-select API, unchanged (`value: string | null`); passing\n * `multiple: true` switches to the array-valued shape (`value: string[]`).\n */\nexport type ComboboxProps = ComboboxSingleProps | ComboboxMultiProps;\n\n/** If the current multi-select selection is exactly one or more *fully* selected\n * groups and nothing else, returns those groups' labels joined by \", \" (e.g. \"Team A\"\n * or \"Team A, Team B\") — so picking a manager's whole team via its header checkbox\n * shows the team's name on the trigger instead of a bare \"6 selected\". A group\n * selected alongside anything it doesn't fully cover (a partial group, or a full\n * group plus an extra individual pick) returns `null`, falling back to the count. */\nfunction resolveGroupTriggerLabel(\n options: ComboboxOption[],\n selectedValues: string[],\n groupLabel: (group: string) => string,\n): string | null {\n const selectedSet = new Set(selectedValues);\n const groupsPresent = Array.from(\n new Set(options.filter((o) => selectedSet.has(o.value) && o.group).map((o) => o.group as string)),\n );\n if (groupsPresent.length === 0) return null;\n\n const coveredValues = new Set<string>();\n const fullyCoveredGroups: string[] = [];\n for (const group of groupsPresent) {\n const members = groupMembers(options, group);\n if (members.length > 0 && members.every((v) => selectedSet.has(v))) {\n fullyCoveredGroups.push(group);\n for (const v of members) coveredValues.add(v);\n }\n }\n const hasLeftover = selectedValues.some((v) => !coveredValues.has(v));\n if (fullyCoveredGroups.length === 0 || hasLeftover) return null;\n return fullyCoveredGroups.map(groupLabel).join(\", \");\n}\n\ntype OptionRow = ImportedOptionRow<ComboboxOption>;\n\n/**\n * A searchable dropdown (\"autocomplete box\"), single- or multi-select\n * depending on the `multiple` prop: a button trigger showing the current\n * selection, opening a popover with a text filter above a scrollable option\n * list. Deliberately built on the existing `Popover` + `Input` primitives\n * rather than a `cmdk`-based `Command` component — this mirrors\n * `@bmsuisse/datagrid`'s `EnumFilter` (plain substring filter over a manually\n * rendered list), keeping the dependency footprint the same as the rest of\n * this package instead of introducing a new list/command library.\n */\nexport function Combobox(props: ComboboxProps): ReactElement {\n const {\n options,\n placeholder = \"Select…\",\n searchPlaceholder = \"Search…\",\n emptyMessage = \"No matches.\",\n disabled,\n loading = false,\n loadingMessage = \"Loading…\",\n clearable = true,\n className,\n id,\n groupLabels,\n container,\n onSearchChange,\n selectedLabel,\n columns,\n } = props;\n const testId = props[\"data-testid\"];\n const [open, setOpen] = useState(false);\n const [search, setSearch] = useState(\"\");\n const [activeIndex, setActiveIndex] = useState(0);\n const inputRef = useRef<HTMLInputElement>(null);\n\n // Normalize both modes to an array so the rest of the component (rendering,\n // active-index bookkeeping) doesn't need to branch on `multiple` at all —\n // only `selectOption` and the clear affordance need mode-specific behavior.\n const selectedValues = useMemo<string[]>(\n () => (props.multiple ? props.value : props.value ? [props.value] : []),\n [props.multiple, props.value],\n );\n\n const selectedOptions = useMemo(\n () => options.filter((option) => selectedValues.includes(option.value)),\n [options, selectedValues],\n );\n\n // In server-driven search mode (`onSearchChange` given), `options` is assumed\n // to already be the caller's current result set — filtering it again locally\n // against a possibly-stale `search` term would double-filter and could hide\n // options the server already matched on fields other than `label`.\n const visibleOptions = useMemo(() => {\n if (onSearchChange) return options;\n const term = search.trim().toLowerCase();\n if (!term) return options;\n return options.filter((option) => option.label.toLowerCase().includes(term));\n }, [options, search, onSearchChange]);\n\n // Reset the search box and re-point `activeIndex` at the current selection\n // each time the popover opens — intentionally NOT reactive to `options`/\n // `value` changes while it stays open, only to the open transition itself.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n useEffect(() => {\n if (!open) return;\n setSearch(\"\");\n onSearchChange?.(\"\");\n const firstSelected = selectedValues[0];\n const selectedIdx = firstSelected ? options.findIndex((option) => option.value === firstSelected) : -1;\n setActiveIndex(selectedIdx >= 0 ? selectedIdx : 0);\n inputRef.current?.focus();\n }, [open]);\n\n // Keep the active index in range as the visible list shrinks/grows while typing.\n useEffect(() => {\n setActiveIndex((i) => Math.min(i, Math.max(visibleOptions.length - 1, 0)));\n }, [visibleOptions.length]);\n\n function selectOption(option: ComboboxOption): void {\n if (option.disabled) return;\n if (props.multiple) {\n const next = props.value.includes(option.value)\n ? props.value.filter((v) => v !== option.value)\n : [...props.value, option.value];\n props.onChange(next);\n return; // multi-select stays open so the user can pick several\n }\n props.onChange(option.value);\n setOpen(false);\n }\n\n function handleKeyDown(event: KeyboardEvent<HTMLInputElement>): void {\n if (event.key === \"ArrowDown\") {\n event.preventDefault();\n setActiveIndex((i) => Math.min(i + 1, visibleOptions.length - 1));\n } else if (event.key === \"ArrowUp\") {\n event.preventDefault();\n setActiveIndex((i) => Math.max(i - 1, 0));\n } else if (event.key === \"Enter\") {\n event.preventDefault();\n const option = visibleOptions[activeIndex];\n if (option) selectOption(option);\n }\n }\n\n const groupLabel = (group: string): string => groupLabels?.[group] ?? group;\n\n function toggleGroup(group: string): void {\n if (!props.multiple) return;\n const members = groupMembers(options, group);\n const next =\n groupCheckState(options, selectedValues, group) === \"checked\"\n ? props.value.filter((v) => !members.includes(v))\n : Array.from(new Set([...props.value, ...members]));\n props.onChange(next);\n }\n\n // \"N selected\" once 2+ are picked (multi-select only — single-select never exceeds\n // 1); the single label at exactly 1; the placeholder at 0; a fully-selected group's\n // own label(s) in place of the count when that applies (see resolveGroupTriggerLabel).\n const triggerLabel = loading\n ? loadingMessage\n : selectedOptions.length === 0\n ? (selectedValues.length > 0 ? (selectedLabel ?? placeholder) : placeholder)\n : selectedOptions.length === 1\n ? (selectedOptions[0]?.label ?? placeholder)\n : (props.multiple ? resolveGroupTriggerLabel(options, selectedValues, groupLabel) : null) ??\n `${selectedOptions.length} selected`;\n\n // Skipped entirely in grid mode (`columns` set) — its result is only ever\n // read from the flat/grouped rendering branch below, so building it there\n // would just re-walk `visibleOptions` on every keystroke for a value\n // nothing then reads.\n const renderChunks = useMemo(() => (columns ? [] : buildRenderChunks(visibleOptions)), [visibleOptions, columns]);\n\n function renderOption({ option, index }: OptionRow): ReactElement {\n const isSelected = selectedValues.includes(option.value);\n const isActive = index === activeIndex;\n return (\n <button\n key={option.value}\n type=\"button\"\n role=\"option\"\n aria-selected={isSelected}\n disabled={option.disabled}\n data-testid={testId ? `${testId}-option` : undefined}\n data-option-value={option.value}\n onMouseEnter={() => setActiveIndex(index)}\n onClick={() => selectOption(option)}\n className={cn(\n \"flex w-full items-center gap-2 rounded-sm px-2 py-1.5 text-left text-sm outline-none disabled:pointer-events-none disabled:opacity-50\",\n isActive && \"bg-accent text-accent-foreground\",\n )}\n >\n {props.multiple ? (\n <input\n type=\"checkbox\"\n checked={isSelected}\n readOnly\n tabIndex={-1}\n className=\"pointer-events-none h-3.5 w-3.5 shrink-0 accent-primary\"\n />\n ) : (\n <Check className={cn(\"h-4 w-4 shrink-0\", isSelected ? \"opacity-100\" : \"opacity-0\")} />\n )}\n <span className=\"truncate\">{option.label}</span>\n </button>\n );\n }\n\n return (\n <Popover open={open} onOpenChange={setOpen}>\n <PopoverTrigger asChild>\n <Button\n id={id}\n data-testid={testId}\n type=\"button\"\n variant=\"outline\"\n role=\"combobox\"\n aria-expanded={open}\n disabled={disabled || loading}\n className={cn(\n \"w-full justify-between font-normal\",\n (selectedOptions.length === 0 || loading) && \"text-muted-foreground\",\n className,\n )}\n >\n <span className=\"truncate\">{triggerLabel}</span>\n <span className=\"flex items-center gap-1\">\n {clearable && !loading && selectedValues.length > 0 ? (\n <span\n role=\"button\"\n aria-label=\"Clear selection\"\n tabIndex={-1}\n className=\"rounded-sm p-0.5 opacity-60 hover:bg-accent hover:opacity-100\"\n onClick={(event) => {\n event.stopPropagation();\n if (props.multiple) {\n props.onChange([]);\n } else {\n props.onChange(null);\n }\n }}\n >\n <X className=\"h-3.5 w-3.5\" />\n </span>\n ) : null}\n <ChevronsUpDown className=\"h-4 w-4 shrink-0 opacity-50\" aria-hidden=\"true\" />\n </span>\n </Button>\n </PopoverTrigger>\n <PopoverContent\n align=\"start\"\n container={container}\n className={cn(\n \"w-[var(--radix-popover-trigger-width)] min-w-[10rem] p-2\",\n columns && \"w-max min-w-[var(--radix-popover-trigger-width)] max-w-[min(40rem,90vw)]\",\n )}\n onOpenAutoFocus={(event) => event.preventDefault()}\n >\n <div className=\"flex flex-col gap-2\">\n <Input\n ref={inputRef}\n value={search}\n onChange={(event) => {\n setSearch(event.target.value);\n onSearchChange?.(event.target.value);\n }}\n onKeyDown={handleKeyDown}\n placeholder={searchPlaceholder}\n aria-label={searchPlaceholder}\n />\n <div role=\"listbox\" className={cn(\"max-h-60 overflow-y-auto\", !columns && \"flex flex-col gap-0.5\")}>\n {visibleOptions.length === 0 ? (\n <p className=\"py-2 text-center text-sm text-muted-foreground\">{emptyMessage}</p>\n ) : columns ? (\n renderGridOptions({\n columns,\n options: visibleOptions,\n activeIndex,\n multiple: Boolean(props.multiple),\n isSelected: (option) => selectedValues.includes(option.value),\n onSelect: selectOption,\n onHover: setActiveIndex,\n testId,\n })\n ) : (\n renderChunks.map((chunk) => {\n if (chunk.kind === \"single\") return renderOption(chunk.row);\n const headerState = groupCheckState(options, selectedValues, chunk.group);\n return (\n // The header and every one of its group's rows share this wrapper --\n // its bounds are the sticky header's containing block, so `sticky top-0`\n // keeps the header pinned for the group's whole scroll extent instead of\n // just past its first row (see buildRenderChunks). Spacing above a group\n // lives on this wrapper's `pt-1`, not on the header itself -- a margin on\n // the sticky element would travel with it once stuck, leaving a gap at the\n // scrollport's top that the row behind it shows through.\n <div key={`group-${chunk.group}`} className=\"flex flex-col gap-0.5 pt-1 first:pt-0\">\n <div\n data-group-header\n className=\"sticky top-0 z-10 flex items-center gap-2 rounded-sm bg-muted px-2 py-1.5 text-sm font-semibold text-foreground\"\n >\n {props.multiple ? (\n <input\n type=\"checkbox\"\n checked={headerState === \"checked\"}\n ref={(el) => {\n if (el) el.indeterminate = headerState === \"indeterminate\";\n }}\n onChange={() => toggleGroup(chunk.group)}\n onClick={(event) => event.stopPropagation()}\n className=\"h-3.5 w-3.5 shrink-0 accent-primary\"\n aria-label={`Select all of ${groupLabel(chunk.group)}`}\n />\n ) : null}\n <span className=\"truncate\">{groupLabel(chunk.group)}</span>\n </div>\n {chunk.rows.map(renderOption)}\n </div>\n );\n })\n )}\n </div>\n </div>\n </PopoverContent>\n </Popover>\n );\n}\n","/** Minimal shape shared by `ComboboxOption` and `TagComboboxOption` — everything\n * the grouping helpers below actually touch. Both components keep their own,\n * richer option type; this exists purely so the two don't hand-duplicate the\n * same grouping logic (and risk it drifting between them on a future fix). */\nexport interface GroupableOption {\n value: string;\n group?: string;\n disabled?: boolean;\n}\n\nexport function groupMembers<T extends GroupableOption>(options: T[], group: string): string[] {\n return options.filter((o) => o.group === group && !o.disabled).map((o) => o.value);\n}\n\nexport type GroupCheckState = \"checked\" | \"unchecked\" | \"indeterminate\";\n\nexport function groupCheckState<T extends GroupableOption>(\n options: T[],\n selectedValues: string[],\n group: string,\n): GroupCheckState {\n const members = groupMembers(options, group);\n const selectedCount = members.filter((v) => selectedValues.includes(v)).length;\n if (selectedCount === 0) return \"unchecked\";\n return selectedCount === members.length ? \"checked\" : \"indeterminate\";\n}\n\nexport interface OptionRow<T extends GroupableOption> {\n option: T;\n index: number;\n}\nexport interface GroupChunk<T extends GroupableOption> {\n kind: \"group\";\n group: string;\n rows: OptionRow<T>[];\n}\nexport interface SingleChunk<T extends GroupableOption> {\n kind: \"single\";\n row: OptionRow<T>;\n}\nexport type RenderChunk<T extends GroupableOption> = GroupChunk<T> | SingleChunk<T>;\n\n/** Chunks `visibleOptions` into per-group chunks (a header plus all of that group's\n * rows, relying on the \"a group's options are contiguous\" invariant `group` already\n * documents on both option types) versus lone ungrouped rows, in one linear pass --\n * kept separate from JSX so a caller's render is a plain `.map()` with no per-row\n * bookkeeping of its own. A sticky header can only stay pinned within its own\n * containing block -- the nearest ancestor that isn't itself sticky/statically laid\n * out -- so the header and every one of its group's rows must share one wrapper\n * element. Rendering each row in its own top-level sibling div (rather than chunking\n * by group) gave the header a containing block of just itself plus the group's first\n * row, so it unstuck after a single row instead of staying pinned for the group's\n * full scroll extent. */\nexport function buildRenderChunks<T extends GroupableOption>(visibleOptions: T[]): RenderChunk<T>[] {\n const chunks: RenderChunk<T>[] = [];\n visibleOptions.forEach((option, index) => {\n const row: OptionRow<T> = { option, index };\n const last = chunks[chunks.length - 1];\n if (option.group && last?.kind === \"group\" && last.group === option.group) {\n last.rows.push(row);\n } else if (option.group) {\n chunks.push({ kind: \"group\", group: option.group, rows: [row] });\n } else {\n chunks.push({ kind: \"single\", row });\n }\n });\n return chunks;\n}\n","import type { ReactElement, ReactNode } from \"react\";\nimport { cn } from \"./utils\";\nimport type { GroupableOption } from \"./optionGrouping\";\nimport { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from \"../primitives/table\";\n\n/** A column shown in a grid-style option popup (see `renderGridOptions`). `key`\n * selects what each row shows in that column: the literal string `\"label\"` reads\n * the option's own `label`, anything else reads `option.data?.[key]`. */\nexport interface GridColumn {\n key: string;\n header: string;\n className?: string;\n}\n\n/** Minimal shape `renderGridOptions` needs from an option — both `ComboboxOption`\n * and `TagComboboxOption` satisfy this once they carry `data`. */\nexport interface GridableOption extends GroupableOption {\n label: string;\n data?: Record<string, ReactNode>;\n}\n\ninterface RenderGridOptionsProps<T extends GridableOption> {\n columns: GridColumn[];\n options: T[];\n activeIndex: number;\n multiple: boolean;\n isSelected: (option: T) => boolean;\n onSelect: (option: T) => void;\n onHover: (index: number) => void;\n testId?: string;\n}\n\n/**\n * Renders `options` as a table (built on the same `Table`/`TableRow`/`TableCell`\n * primitives every other table in this package uses, so a future styling tweak\n * there — borders, checkbox-column padding, etc. — reaches this too) instead of\n * the default flat label list — the `columns` counterpart to `buildRenderChunks`'s\n * grouped-label rendering. Deliberately ignores each option's `group` (an\n * option-grid header spanning several unrelated columns has no obvious layout,\n * and no caller has asked for it yet) — grid mode and grouping are mutually\n * exclusive, documented on the `columns` prop of both `Combobox` and `TagCombobox`.\n */\nexport function renderGridOptions<T extends GridableOption>({\n columns,\n options,\n activeIndex,\n multiple,\n isSelected,\n onSelect,\n onHover,\n testId,\n}: RenderGridOptionsProps<T>): ReactElement {\n return (\n <Table className=\"text-sm\">\n <TableHeader>\n <TableRow className=\"hover:bg-transparent\">\n {multiple && <TableHead className=\"sticky top-0 z-10 w-6 bg-muted\" />}\n {columns.map((column) => (\n <TableHead\n key={column.key}\n className={cn(\"sticky top-0 z-10 whitespace-nowrap bg-muted text-xs\", column.className)}\n >\n {column.header}\n </TableHead>\n ))}\n </TableRow>\n </TableHeader>\n <TableBody>\n {options.map((option, index) => {\n const selected = isSelected(option);\n const active = index === activeIndex;\n return (\n <TableRow\n key={option.value}\n role=\"option\"\n aria-selected={selected}\n // Otherwise a screen reader reads every column's text as the option's\n // name (e.g. \"Germany Berlin Europe\") instead of just its label,\n // unlike the flat list's <button>, whose accessible name is the\n // label alone.\n aria-label={option.label}\n aria-disabled={option.disabled}\n data-testid={testId ? `${testId}-option` : undefined}\n data-option-value={option.value}\n onMouseEnter={() => onHover(index)}\n onClick={() => {\n if (!option.disabled) onSelect(option);\n }}\n className={cn(\n \"cursor-pointer outline-none\",\n // `hover:bg-accent` repeats the active row's own background under\n // `:hover` -- otherwise TableRow's default `hover:bg-muted/50`\n // would win over the plain `bg-accent` below (later in the\n // stylesheet) and flash the active/keyboard-selected row to the\n // wrong color the instant the mouse sits over it.\n active && \"bg-accent text-accent-foreground hover:bg-accent hover:text-accent-foreground\",\n option.disabled && \"pointer-events-none opacity-50\",\n )}\n >\n {multiple && (\n <TableCell className=\"w-6\">\n <input\n type=\"checkbox\"\n checked={selected}\n readOnly\n tabIndex={-1}\n className=\"pointer-events-none h-3.5 w-3.5 shrink-0 accent-primary\"\n />\n </TableCell>\n )}\n {columns.map((column) => (\n <TableCell key={column.key} className={cn(\"truncate\", column.className)}>\n {column.key === \"label\" ? option.label : option.data?.[column.key]}\n </TableCell>\n ))}\n </TableRow>\n );\n })}\n </TableBody>\n </Table>\n );\n}\n","import { X } from \"lucide-react\";\nimport type { ComponentProps, KeyboardEvent, ReactElement, ReactNode } from \"react\";\nimport { useEffect, useMemo, useRef, useState } from \"react\";\nimport { cn } from \"../../lib/utils\";\nimport {\n buildRenderChunks,\n groupCheckState,\n groupMembers,\n type OptionRow,\n} from \"../../lib/optionGrouping\";\nimport { renderGridOptions, type GridColumn } from \"../../lib/optionGrid\";\nimport { Popover, PopoverAnchor, PopoverContent } from \"../../primitives/popover\";\n\nexport interface TagComboboxOption {\n value: string;\n label: string;\n disabled?: boolean;\n /** Groups this option under a header with the given key, rendered as a bold label\n * plus a tri-state \"select all\" checkbox (unchecked/checked/indeterminate, reflecting\n * how many of the group's members are selected — toggling it selects or clears the\n * whole group). Options sharing a `group` must be contiguous in `options` — see\n * `Combobox`'s own `group` doc for the same constraint and the reasoning behind it.\n * Ignored when `columns` is set (see that prop's own doc). */\n group?: string;\n /** Extra fields for this option, surfaced as additional columns when\n * `columns` is set — e.g. `{ email: \"a@b.com\", role: \"Admin\" }`. Ignored\n * otherwise. */\n data?: Record<string, ReactNode>;\n}\n\nexport interface TagComboboxProps {\n /** The full option list. Filtering happens client-side against `label`,\n * unless `onSearchChange` is given (see below). */\n options: TagComboboxOption[];\n /** Selected options' `value`s. */\n value: string[];\n /** Called with the full updated selection after a toggle or a chip removal. */\n onChange: (value: string[]) => void;\n /** Shown in the field when nothing is selected and nothing is typed. Defaults to `\"Select…\"`. */\n placeholder?: string;\n /** Shown when the search term matches nothing. Defaults to `\"No matches.\"`. */\n emptyMessage?: string;\n disabled?: boolean;\n /** Shows `loadingMessage` in the option list instead of `emptyMessage`, for a\n * combobox whose `options` are still being fetched (e.g. a server search whose\n * request hasn't resolved yet). Defaults to `false`. */\n loading?: boolean;\n /** Message shown in the option list while `loading` is true. Defaults to `\"Loading…\"`. */\n loadingMessage?: string;\n className?: string;\n id?: string;\n /** Forwarded to the field, for test targeting (e.g. Playwright/Testing Library). */\n \"data-testid\"?: string;\n /** Switches the search input to server-driven mode: called with the raw search\n * text on every keystroke, and `options` is rendered as-is instead of being\n * filtered locally against `label`. Omit for the default client-side filtering\n * behavior — see `Combobox`'s own `onSearchChange` for the same contract. */\n onSearchChange?: (search: string) => void;\n /** Portal target for the popover, forwarded to the underlying `PopoverContent`.\n * Needed when the combobox is opened from inside a modal Dialog/Sheet — pass the\n * Dialog/Sheet content element so the popover portals inside it instead of\n * `document.body`, which would otherwise fight with the Dialog's focus trap. */\n container?: ComponentProps<typeof PopoverContent>[\"container\"];\n /** Display label for a group key (`TagComboboxOption.group`). Falls back to the raw\n * key when an entry is missing. Only relevant when at least one option sets `group`. */\n groupLabels?: Record<string, string>;\n /** Renders the popup's option list as a multi-column grid instead of a flat\n * label list — see `Combobox`'s own `columns` doc for the full contract\n * (including its interaction with `group`, and the widened popup). */\n columns?: GridColumn[];\n}\n\n/**\n * A tags-and-search multi-select: selected options render as removable chips\n * inline inside one bordered field, with a search input immediately after\n * the last chip. Typing opens a popover listing matches below the field;\n * picking one adds a chip right where the caret was and clears the search\n * term so the user can keep typing. Complements `Combobox`'s `multiple`\n * mode (a trigger button + a summary count) for the case where every\n * individual selection needs to stay visible and removable at a glance —\n * built on the same `Popover`/keyboard-nav shape rather than forking it,\n * so both patterns share one mental model.\n */\nexport function TagCombobox({\n options,\n value,\n onChange,\n placeholder = \"Select…\",\n emptyMessage = \"No matches.\",\n disabled,\n loading = false,\n loadingMessage = \"Loading…\",\n className,\n id,\n onSearchChange,\n container,\n groupLabels,\n columns,\n ...rest\n}: TagComboboxProps): ReactElement {\n const testId = rest[\"data-testid\"];\n const [open, setOpen] = useState(false);\n const [search, setSearch] = useState(\"\");\n const [activeIndex, setActiveIndex] = useState(0);\n const inputRef = useRef<HTMLInputElement>(null);\n const fieldRef = useRef<HTMLDivElement>(null);\n\n const selectedOptions = useMemo(\n () => value.map((v) => options.find((o) => o.value === v) ?? { value: v, label: v }),\n [options, value],\n );\n\n // In server-driven search mode (`onSearchChange` given), `options` is assumed\n // to already be the caller's current result set — filtering it again locally\n // against a possibly-stale `search` term would double-filter and could hide\n // options the server already matched on fields other than `label`.\n const visibleOptions = useMemo(() => {\n if (onSearchChange) return options;\n const term = search.trim().toLowerCase();\n if (!term) return options;\n return options.filter((option) => option.label.toLowerCase().includes(term));\n }, [options, search, onSearchChange]);\n\n useEffect(() => {\n setActiveIndex((i) => Math.min(Math.max(i, 0), Math.max(visibleOptions.length - 1, 0)));\n }, [visibleOptions.length]);\n\n // Skipped entirely in grid mode (`columns` set) — see `Combobox`'s own\n // identical `renderChunks` doc for why.\n const renderChunks = useMemo(() => (columns ? [] : buildRenderChunks(visibleOptions)), [visibleOptions, columns]);\n\n // Reset the search term and re-point `activeIndex` each time the popover\n // opens -- intentionally NOT reactive to `options`/`value` changes while it\n // stays open, only to the open transition itself, mirroring `Combobox`'s\n // own identical effect. Harmless (and idempotent) when `open` becomes true\n // via focus right before the user starts typing: search is already \"\" at\n // that point, since typing is what would change it.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n useEffect(() => {\n if (!open) return;\n setSearch(\"\");\n onSearchChange?.(\"\");\n const firstSelected = value[0];\n const selectedIdx = firstSelected ? options.findIndex((o) => o.value === firstSelected) : -1;\n setActiveIndex(selectedIdx >= 0 ? selectedIdx : 0);\n }, [open]);\n\n function updateSearch(next: string): void {\n setSearch(next);\n onSearchChange?.(next);\n if (!open) setOpen(true);\n }\n\n function toggleOption(option: TagComboboxOption): void {\n if (option.disabled) return;\n const next = value.includes(option.value) ? value.filter((v) => v !== option.value) : [...value, option.value];\n onChange(next);\n updateSearch(\"\");\n inputRef.current?.focus();\n }\n\n function removeValue(v: string): void {\n // Mirrors toggleOption's own guard: an option disabled in the caller's\n // `options` list can't be deselected via its dropdown row, so its chip's\n // own remove button (and the Backspace shortcut, which calls this too)\n // must refuse it the same way instead of silently bypassing that.\n if (options.find((o) => o.value === v)?.disabled) return;\n onChange(value.filter((existing) => existing !== v));\n }\n\n const groupLabel = (group: string): string => groupLabels?.[group] ?? group;\n\n // Deliberately uses the full `options` list, not `visibleOptions` -- a\n // group's checkbox/toggle must reflect and act on every member, including\n // ones the current search term is hiding, matching `Combobox`'s own\n // `toggleGroup`/header-state contract for the same reason.\n function toggleGroup(group: string): void {\n const members = groupMembers(options, group);\n const next =\n groupCheckState(options, value, group) === \"checked\"\n ? value.filter((v) => !members.includes(v))\n : Array.from(new Set([...value, ...members]));\n onChange(next);\n inputRef.current?.focus();\n }\n\n function handleKeyDown(event: KeyboardEvent<HTMLInputElement>): void {\n if (event.key === \"ArrowDown\") {\n event.preventDefault();\n setOpen(true);\n setActiveIndex((i) => Math.min(i + 1, Math.max(visibleOptions.length - 1, 0)));\n } else if (event.key === \"ArrowUp\") {\n event.preventDefault();\n setActiveIndex((i) => Math.max(i - 1, 0));\n } else if (event.key === \"Enter\") {\n event.preventDefault();\n const option = visibleOptions[activeIndex];\n if (option) toggleOption(option);\n } else if (event.key === \"Escape\") {\n setOpen(false);\n } else if (event.key === \"Backspace\" && search === \"\") {\n // Standard tag-input convention: Backspace on an empty search field\n // removes the most recently added chip instead of doing nothing.\n const last = value[value.length - 1];\n if (last !== undefined) removeValue(last);\n }\n }\n\n function renderOption({ option, index }: OptionRow<TagComboboxOption>): ReactElement {\n const isSelected = value.includes(option.value);\n const isActive = index === activeIndex;\n return (\n <button\n key={option.value}\n type=\"button\"\n role=\"option\"\n aria-selected={isSelected}\n disabled={option.disabled}\n data-testid={testId ? `${testId}-option` : undefined}\n data-option-value={option.value}\n onMouseEnter={() => setActiveIndex(index)}\n onClick={() => toggleOption(option)}\n className={cn(\n \"flex w-full items-center gap-2 rounded-sm px-2 py-1.5 text-left text-sm outline-none disabled:pointer-events-none disabled:opacity-50\",\n isActive && \"bg-accent text-accent-foreground\",\n )}\n >\n <input\n type=\"checkbox\"\n checked={isSelected}\n readOnly\n tabIndex={-1}\n className=\"pointer-events-none h-3.5 w-3.5 shrink-0 accent-primary\"\n />\n <span className=\"truncate\">{option.label}</span>\n </button>\n );\n }\n\n return (\n <Popover open={open} onOpenChange={setOpen}>\n <PopoverAnchor asChild>\n <div\n ref={fieldRef}\n data-testid={testId}\n role=\"combobox\"\n aria-expanded={open}\n aria-disabled={disabled}\n className={cn(\n \"flex min-h-9 w-full flex-wrap items-center gap-1.5 rounded-md border border-input bg-transparent px-2 py-1.5 text-sm\",\n \"focus-within:outline-none focus-within:ring-2 focus-within:ring-ring\",\n disabled && \"cursor-not-allowed opacity-50\",\n className,\n )}\n onClick={() => {\n if (!disabled) inputRef.current?.focus();\n }}\n >\n {selectedOptions.map((option) => (\n <span\n key={option.value}\n className=\"inline-flex items-center gap-1 rounded-full bg-muted py-0.5 pr-1 pl-2.5 text-xs font-medium text-muted-foreground\"\n >\n <span className=\"max-w-48 truncate\">{option.label}</span>\n {!disabled && (\n <button\n type=\"button\"\n aria-label={`Remove ${option.label}`}\n className=\"rounded-full p-0.5 hover:bg-accent hover:text-accent-foreground\"\n onClick={(event) => {\n event.stopPropagation();\n removeValue(option.value);\n }}\n >\n <X className=\"h-3 w-3\" />\n </button>\n )}\n </span>\n ))}\n <input\n ref={inputRef}\n id={id}\n value={search}\n disabled={disabled}\n placeholder={selectedOptions.length === 0 ? placeholder : undefined}\n aria-label={placeholder}\n className=\"min-w-24 flex-1 bg-transparent outline-none placeholder:text-muted-foreground disabled:cursor-not-allowed\"\n onFocus={() => setOpen(true)}\n onChange={(event) => updateSearch(event.target.value)}\n onKeyDown={handleKeyDown}\n />\n </div>\n </PopoverAnchor>\n <PopoverContent\n align=\"start\"\n container={container}\n className={cn(\n \"w-[var(--radix-popover-trigger-width)] min-w-[10rem] p-2\",\n columns && \"w-max min-w-[var(--radix-popover-trigger-width)] max-w-[min(40rem,90vw)]\",\n )}\n onOpenAutoFocus={(event) => event.preventDefault()}\n onCloseAutoFocus={(event) => event.preventDefault()}\n // Radix's non-modal Popover content treats a focus/pointer event as\n // \"outside\" (and dismisses) unless the target is inside the content\n // itself or is the registered `PopoverTrigger` -- but this field uses\n // `PopoverAnchor`, which never registers a trigger ref, and\n // `toggleOption`/`removeValue` deliberately refocus `inputRef` (which\n // lives in the anchor, not inside this portaled content) after every\n // pick so the user can keep typing. Without this guard, that refocus\n // itself reads as \"focus left to somewhere outside\" and closes the\n // popover right after each selection.\n onInteractOutside={(event) => {\n if (fieldRef.current?.contains(event.target as Node)) event.preventDefault();\n }}\n >\n <div role=\"listbox\" className={cn(\"max-h-60 overflow-y-auto\", !columns && \"flex flex-col gap-0.5\")}>\n {loading ? (\n <p className=\"py-2 text-center text-sm text-muted-foreground\">{loadingMessage}</p>\n ) : visibleOptions.length === 0 ? (\n <p className=\"py-2 text-center text-sm text-muted-foreground\">{emptyMessage}</p>\n ) : columns ? (\n renderGridOptions({\n columns,\n options: visibleOptions,\n activeIndex,\n multiple: true,\n isSelected: (option) => value.includes(option.value),\n onSelect: toggleOption,\n onHover: setActiveIndex,\n testId,\n })\n ) : (\n renderChunks.map((chunk) => {\n if (chunk.kind === \"single\") return renderOption(chunk.row);\n const headerState = groupCheckState(options, value, chunk.group);\n return (\n // The header and every one of its group's rows share this wrapper -- its\n // bounds are the sticky header's containing block, so `sticky top-0` keeps\n // the header pinned for the group's whole scroll extent instead of just\n // past its first row. Spacing above a group lives on this wrapper's\n // `pt-1`/`first:pt-0`, not on the header itself -- see `Combobox`'s own\n // identical structure for why both of these matter.\n <div key={`group-${chunk.group}`} className=\"flex flex-col gap-0.5 pt-1 first:pt-0\">\n <div\n data-group-header\n className=\"sticky top-0 z-10 flex items-center gap-2 rounded-sm bg-muted px-2 py-1.5 text-sm font-semibold text-foreground\"\n >\n <input\n type=\"checkbox\"\n checked={headerState === \"checked\"}\n ref={(el) => {\n if (el) el.indeterminate = headerState === \"indeterminate\";\n }}\n onChange={() => toggleGroup(chunk.group)}\n onClick={(event) => event.stopPropagation()}\n className=\"h-3.5 w-3.5 shrink-0 accent-primary\"\n aria-label={`Select all of ${groupLabel(chunk.group)}`}\n />\n <span className=\"truncate\">{groupLabel(chunk.group)}</span>\n </div>\n {chunk.rows.map(renderOption)}\n </div>\n );\n })\n )}\n </div>\n </PopoverContent>\n </Popover>\n );\n}\n","import { AlertCircle, AlertTriangle, CheckCircle2, Info } from \"lucide-react\";\nimport type { ReactElement, ReactNode } from \"react\";\nimport { cn } from \"../../lib/utils\";\n\nexport type AlertBoxVariant = \"error\" | \"warning\" | \"info\" | \"success\";\n\nexport interface AlertBoxProps {\n /** Determines the color scheme and the default icon. */\n variant: AlertBoxVariant;\n /** Optional bold heading line shown above the body content. */\n title?: string;\n /** Body text/content. Always rendered. */\n children: ReactNode;\n className?: string;\n /**\n * Overrides the default variant icon entirely. Pass `null` to hide the\n * icon. Defaults to a variant-specific lucide-react icon.\n */\n icon?: ReactNode;\n}\n\n// `error` borders/background reuse the shared `destructive` theme token, but the text\n// color is a fixed red rather than `text-destructive` because that token is tuned for\n// solid button fills, not small text on a tinted background, and fails WCAG AA contrast\n// there. `warning`/`info`/`success` have no equivalent tokens in @bmsuisse/ui's theme (it\n// only defines background/foreground/primary/muted/popover/accent/destructive/border/\n// input/ring), so these three variants use fixed Tailwind palette colors instead of theme\n// tokens. A consumer app with different brand colors will need to override these via\n// `className`.\nconst variantStyles: Record<AlertBoxVariant, string> = {\n error: \"border-destructive bg-destructive/10 text-red-800 dark:text-red-300\",\n warning: \"border-amber-500 bg-amber-500/10 text-amber-900 dark:text-amber-200\",\n info: \"border-sky-500 bg-sky-500/10 text-sky-700 dark:text-sky-300\",\n success: \"border-emerald-500 bg-emerald-500/10 text-emerald-700 dark:text-emerald-300\",\n};\n\nconst defaultIcons: Record<AlertBoxVariant, ReactElement> = {\n error: <AlertCircle className=\"h-4 w-4 shrink-0\" aria-hidden=\"true\" />,\n warning: <AlertTriangle className=\"h-4 w-4 shrink-0\" aria-hidden=\"true\" />,\n info: <Info className=\"h-4 w-4 shrink-0\" aria-hidden=\"true\" />,\n success: <CheckCircle2 className=\"h-4 w-4 shrink-0\" aria-hidden=\"true\" />,\n};\n\nexport const AlertBox = ({ variant, title, children, className, icon }: AlertBoxProps): ReactElement => {\n const resolvedIcon = icon === undefined ? defaultIcons[variant] : icon;\n\n return (\n <div className={cn(\"rounded-md border p-3 text-sm\", variantStyles[variant], className)}>\n <div className=\"flex flex-row items-start gap-2\">\n {resolvedIcon != null && <span className=\"mt-0.5 shrink-0\">{resolvedIcon}</span>}\n <div className=\"flex flex-col gap-1\">\n {title && <p className=\"font-bold\">{title}</p>}\n <div>{children}</div>\n </div>\n </div>\n </div>\n );\n};\n","import type { HTMLAttributes, ReactElement } from \"react\";\nimport { cn } from \"../../lib/utils\";\nimport { Badge } from \"../../primitives/badge\";\n\n/** Semantic color intent for a {@link StatusBadge}. */\nexport type StatusTone = \"success\" | \"warning\" | \"error\" | \"info\" | \"neutral\";\n\n/**\n * Class names per tone. `success` / `warning` / `info` fall back to fixed\n * Tailwind palette shades (with `dark:` variants, since this package's dark\n * mode is a `.dark` ancestor class) because the shared theme currently only\n * defines background/foreground/primary/muted/popover/accent/destructive/\n * border/input/ring tokens — no warning/info/success tokens exist yet, same\n * reasoning AlertBox uses for those tones. `neutral` reuses the `muted` token\n * directly; `error` reuses `destructive` for the tint but, like AlertBox, uses a\n * fixed red for the text because `text-destructive` is tuned for solid button\n * fills and only reaches ~3.9:1 (light) / ~3.5:1 (dark) on its own 15% tint.\n */\nconst TONE_CLASSES: Record<StatusTone, string> = {\n success: \"border-transparent bg-emerald-500/15 text-emerald-700 dark:bg-emerald-500/20 dark:text-emerald-300\",\n warning: \"border-transparent bg-amber-500/15 text-amber-800 dark:bg-amber-500/20 dark:text-amber-300\",\n info: \"border-transparent bg-sky-500/15 text-sky-700 dark:bg-sky-500/20 dark:text-sky-300\",\n error: \"border-transparent bg-destructive/15 text-red-800 dark:text-red-300\",\n neutral: \"border-transparent bg-muted text-muted-foreground\",\n};\n\n/** Built-in status vocabulary, matched case-insensitively against `status.toLowerCase()`. */\nconst DEFAULT_TONE_MAP: Record<string, StatusTone> = {\n active: \"success\",\n approved: \"success\",\n completed: \"success\",\n paid: \"success\",\n done: \"success\",\n pending: \"warning\",\n draft: \"warning\",\n in_review: \"warning\",\n inreview: \"warning\",\n rejected: \"error\",\n failed: \"error\",\n cancelled: \"error\",\n canceled: \"error\",\n overdue: \"error\",\n inactive: \"neutral\",\n archived: \"neutral\",\n new: \"info\",\n};\n\n/** Title-cases a raw status value and replaces underscores/hyphens with spaces, e.g. `\"in_review\"` -> `\"In Review\"`. */\nfunction deriveLabel(status: string): string {\n return status\n .replace(/[_-]+/g, \" \")\n .trim()\n .split(/\\s+/)\n .filter(Boolean)\n .map((word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase())\n .join(\" \");\n}\n\n/**\n * Resolves a status to a {@link StatusTone}.\n *\n * Resolution order: explicit `tone` prop > caller's `toneMap` (case-insensitive\n * key match) > built-in default map (case-insensitive) > `neutral` fallback.\n */\nfunction resolveTone(status: string, tone?: StatusTone, toneMap?: Record<string, StatusTone>): StatusTone {\n if (tone) {\n return tone;\n }\n\n const key = status.toLowerCase();\n\n if (toneMap) {\n for (const [candidate, candidateTone] of Object.entries(toneMap)) {\n if (candidate.toLowerCase() === key) {\n return candidateTone;\n }\n }\n }\n\n return DEFAULT_TONE_MAP[key] ?? \"neutral\";\n}\n\nexport interface StatusBadgeProps extends Omit<HTMLAttributes<HTMLDivElement>, \"children\"> {\n /** Raw status value from the caller's domain, e.g. `\"pending\"`, `\"APPROVED\"`, `\"in_review\"`. */\n status: string;\n /** Overrides the displayed text. Defaults to a title-cased, space-separated derivation of `status`. */\n label?: string;\n /** Explicit tone override. When provided, `toneMap` and the built-in default map are skipped entirely. */\n tone?: StatusTone;\n /** Caller-supplied status-to-tone mapping (case-insensitive keys), checked before the built-in default map. */\n toneMap?: Record<string, StatusTone>;\n}\n\n/**\n * A status-to-color badge, built on the shared `Badge` primitive.\n *\n * Centralizes the status->color mapping that's otherwise reimplemented ad hoc\n * per app: callers can rely on the built-in English status vocabulary, supply\n * their own `toneMap` for domain-specific statuses, or force a `tone`\n * outright.\n */\nexport const StatusBadge = ({ status, label, tone, toneMap, className, ...props }: StatusBadgeProps): ReactElement => {\n const resolvedTone = resolveTone(status, tone, toneMap);\n const displayLabel = label ?? deriveLabel(status);\n\n return (\n <Badge variant=\"outline\" className={cn(TONE_CLASSES[resolvedTone], className)} {...props}>\n {displayLabel}\n </Badge>\n );\n};\n","import type { ComponentType, ReactElement } from \"react\";\nimport { cn } from \"../../lib/utils\";\nimport { Button, type ButtonProps } from \"../../primitives/button\";\n\n/** One segment of a {@link ButtonGroup}. */\nexport interface ButtonGroupOption<T extends string = string> {\n value: T;\n label: string;\n icon?: ComponentType<{ className?: string }>;\n}\n\nexport interface ButtonGroupProps<T extends string = string> {\n options: ButtonGroupOption<T>[];\n value: T;\n onValueChange: (value: T) => void;\n /** Forwarded to every segment's `Button`. @default \"default\" */\n size?: ButtonProps[\"size\"];\n disabled?: boolean;\n /** Accessible name for the group's `role=\"group\"` wrapper. */\n \"aria-label\"?: string;\n className?: string;\n \"data-testid\"?: string;\n}\n\n/**\n * A row of mutually exclusive, connected buttons (single-select segmented\n * control) — e.g. an ignore/create/update choice per row. Built on the\n * `Button` primitive rather than a bespoke element so segments inherit its\n * variant styling, sizes, and disabled/focus-visible behavior for free.\n *\n * Segments share borders (each button after the first overlaps its left\n * border by 1px via `-ml-px`) with `hover:z-10`/`focus-visible:z-10` so the\n * active/hovered segment's own border still draws on top of its neighbor\n * instead of being clipped underneath it.\n */\nexport function ButtonGroup<T extends string = string>({\n options,\n value,\n onValueChange,\n size = \"default\",\n disabled,\n className,\n ...props\n}: ButtonGroupProps<T>): ReactElement {\n return (\n <div role=\"group\" aria-label={props[\"aria-label\"]} className={cn(\"inline-flex\", className)} data-testid={props[\"data-testid\"]}>\n {options.map((option, index) => {\n const selected = option.value === value;\n const Icon = option.icon;\n return (\n <Button\n key={option.value}\n type=\"button\"\n variant={selected ? \"default\" : \"outline\"}\n size={size}\n disabled={disabled}\n aria-pressed={selected}\n data-testid={props[\"data-testid\"] ? `${props[\"data-testid\"]}-option-${option.value}` : undefined}\n onClick={() => onValueChange(option.value)}\n className={cn(\n \"relative rounded-none focus-visible:z-10\",\n !selected && \"hover:z-10\",\n index === 0 && \"rounded-l-md\",\n index === options.length - 1 && \"rounded-r-md\",\n index > 0 && \"-ml-px\",\n )}\n >\n {Icon && <Icon className=\"h-4 w-4\" />}\n {option.label}\n </Button>\n );\n })}\n </div>\n );\n}\n","import { type VariantProps, cva } from \"class-variance-authority\";\nimport { Loader2 } from \"lucide-react\";\nimport type { HTMLAttributes, ReactElement } from \"react\";\nimport { cn } from \"../../lib/utils\";\n\nexport const loadingSpinnerIconVariants = cva(\"animate-spin text-muted-foreground\", {\n variants: {\n size: {\n sm: \"h-3.5 w-3.5\",\n default: \"h-4 w-4\",\n lg: \"h-6 w-6\",\n },\n },\n defaultVariants: {\n size: \"default\",\n },\n});\n\nexport interface LoadingSpinnerProps\n extends HTMLAttributes<HTMLSpanElement>,\n VariantProps<typeof loadingSpinnerIconVariants> {\n /** Optional text rendered next to the spinner. Omitted entirely renders an icon-only spinner. */\n label?: string;\n}\n\n/** Inline loading indicator: a spinning icon with an optional label, e.g. `<LoadingSpinner label=\"Saving…\" />`. */\nexport const LoadingSpinner = ({\n size,\n label,\n className,\n ...props\n}: LoadingSpinnerProps): ReactElement => (\n <span role=\"status\" className={cn(\"inline-flex items-center gap-2\", className)} {...props}>\n <Loader2 className={cn(loadingSpinnerIconVariants({ size }))} aria-hidden=\"true\" />\n {label ? <span>{label}</span> : null}\n </span>\n);\n\nexport interface LoadingOverlayProps\n extends HTMLAttributes<HTMLDivElement>,\n Pick<LoadingSpinnerProps, \"label\"> {\n size?: LoadingSpinnerProps[\"size\"];\n}\n\n/** Centers a larger `LoadingSpinner` inside a full container/page — use as a route or panel loading state. */\nexport const LoadingOverlay = ({\n size = \"lg\",\n label,\n className,\n ...props\n}: LoadingOverlayProps): ReactElement => (\n <div\n className={cn(\"flex h-full min-h-32 w-full items-center justify-center\", className)}\n {...props}\n >\n <LoadingSpinner size={size} label={label} />\n </div>\n);\n","import { Search, X } from \"lucide-react\";\nimport type { InputHTMLAttributes, ReactElement, Ref } from \"react\";\nimport { cn } from \"../../lib/utils\";\nimport { LoadingSpinner } from \"../loading-spinner/LoadingSpinner\";\n\nexport interface SearchBarProps\n extends Omit<InputHTMLAttributes<HTMLInputElement>, \"type\" | \"value\" | \"onChange\" | \"size\"> {\n value: string;\n onChange: (value: string) => void;\n /** Swaps the leading search icon for a spinner while a search request is in flight. */\n isLoading?: boolean;\n /** Called when the clear (×) button is pressed. Defaults to `onChange(\"\")`. Pass `false` to hide the button entirely, even with a non-empty value. */\n onClear?: (() => void) | false;\n /** Accessible label for the clear button. @default \"Clear search\" */\n clearLabel?: string;\n /** Forwarded ref so a caller can focus the input programmatically. */\n inputRef?: Ref<HTMLInputElement>;\n className?: string;\n}\n\n/**\n * Pill-shaped search input: leading icon (swaps to a spinner while\n * `isLoading`), trailing clear button once there's a value. The shape\n * duplicated across several consuming apps' own hand-rolled search boxes —\n * unlike `Combobox`, this has no dropdown/result list of its own, just the\n * input chrome; the caller owns whatever renders the results.\n */\nexport function SearchBar({\n value,\n onChange,\n isLoading,\n onClear,\n clearLabel = \"Clear search\",\n inputRef,\n className,\n ...props\n}: SearchBarProps): ReactElement {\n const showClear = onClear !== false && value.length > 0;\n return (\n <div className={cn(\"relative\", className)}>\n <span className=\"pointer-events-none absolute top-1/2 left-4 -translate-y-1/2 text-muted-foreground\">\n {isLoading ? (\n <LoadingSpinner size=\"sm\" />\n ) : (\n <Search className=\"h-4 w-4\" aria-hidden=\"true\" />\n )}\n </span>\n <input\n ref={inputRef}\n type=\"search\"\n value={value}\n onChange={(event) => onChange(event.target.value)}\n className={cn(\n \"h-11 w-full rounded-full border border-input bg-background text-[15px] text-foreground placeholder:text-muted-foreground focus-visible:ring-1 focus-visible:ring-ring focus-visible:outline-none\",\n // Chromium/Safari render their own native clear (×) control on\n // type=\"search\" inputs -- left alone, it stacks on top of our own\n // custom clear button below instead of replacing it.\n \"[&::-webkit-search-cancel-button]:appearance-none [&::-webkit-search-decoration]:appearance-none\",\n showClear ? \"pr-11\" : \"pr-4\",\n \"pl-11\",\n )}\n {...props}\n />\n {showClear && (\n <button\n type=\"button\"\n onClick={() => (onClear ? onClear() : onChange(\"\"))}\n aria-label={clearLabel}\n className=\"absolute top-1/2 right-2 flex h-7 w-7 -translate-y-1/2 items-center justify-center rounded-full text-muted-foreground hover:bg-accent hover:text-foreground\"\n >\n <X className=\"h-4 w-4\" aria-hidden=\"true\" />\n </button>\n )}\n </div>\n );\n}\n","import { memo, type ComponentType, type ReactElement } from \"react\";\nimport { cn } from \"../../lib/utils\";\nimport { Skeleton } from \"../../primitives/skeleton\";\n\nexport interface KpiCardProps {\n label: string;\n value?: string | number | null;\n icon?: ComponentType<{ className?: string }>;\n badge?: { text: string; positive?: boolean };\n badgeLabel?: string;\n /** @default \"default\" */\n variant?: \"hero\" | \"mini\" | \"default\" | \"donut\";\n loading?: boolean;\n sub?: string;\n /** Colors `sub` on the mini variant — \"warn\"/\"danger\" flag something worth acting on (overdue, at-risk), \"default\" stays muted. */\n subTone?: \"default\" | \"warn\" | \"danger\";\n /** Makes the icon (mini variant) or the whole card clickable. */\n href?: string;\n sparkline?: number[];\n /** @default \"var(--color-primary, #3b82f6)\" */\n sparklineColor?: string;\n /** Hero variant only: 0-100 achievement-vs-target bar rendered under `sub`. */\n progress?: number;\n progressLabel?: string;\n /** Donut variant only: the proportions to render as a ring chart, with a legend listing each segment's share. */\n segments?: DonutSegment[];\n /** Donut variant only: big label centered in the ring. Defaults to the sum of `segments`' values. */\n centerValue?: string;\n /** For E2E tests to target a specific tile unambiguously when `label` also appears elsewhere on the page (e.g. a chart legend). */\n testId?: string;\n}\n\nexport interface DonutSegment {\n label: string;\n value: number;\n /** @default a color from the built-in palette, cycling by index */\n color?: string;\n}\n\n/** Falls back to a fixed palette when the consuming app hasn't registered `--chart-1`..`--chart-6` — see the \"Chart tokens\" docs. */\nconst DONUT_COLORS = [\n \"var(--chart-1, #3b82f6)\",\n \"var(--chart-2, #22c55e)\",\n \"var(--chart-3, #f59e0b)\",\n \"var(--chart-4, #8b5cf6)\",\n \"var(--chart-5, #ef4444)\",\n \"var(--chart-6, #06b6d4)\",\n];\n\nexport function DonutChart({\n data,\n size = 96,\n thickness = 14,\n centerValue,\n centerLabel,\n}: {\n data: DonutSegment[];\n size?: number;\n thickness?: number;\n centerValue?: string;\n centerLabel?: string;\n}): ReactElement | null {\n const total = data.reduce((sum, d) => sum + d.value, 0);\n if (total <= 0) return null;\n\n const radius = (size - thickness) / 2;\n const circumference = 2 * Math.PI * radius;\n let offset = 0;\n\n return (\n <div className=\"relative inline-flex shrink-0 items-center justify-center\" style={{ width: size, height: size }}>\n <svg width={size} height={size} viewBox={`0 0 ${size} ${size}`} className=\"-rotate-90\">\n <circle cx={size / 2} cy={size / 2} r={radius} fill=\"none\" stroke=\"currentColor\" className=\"text-muted/40\" strokeWidth={thickness} />\n {data.map((segment, i) => {\n const fraction = segment.value / total;\n const dash = fraction * circumference;\n const el = (\n <circle\n key={segment.label}\n cx={size / 2}\n cy={size / 2}\n r={radius}\n fill=\"none\"\n stroke={segment.color ?? DONUT_COLORS[i % DONUT_COLORS.length]}\n strokeWidth={thickness}\n strokeDasharray={`${dash} ${circumference - dash}`}\n strokeDashoffset={-offset}\n strokeLinecap={data.length > 1 ? \"butt\" : \"round\"}\n />\n );\n offset += dash;\n return el;\n })}\n </svg>\n {(centerValue || centerLabel) && (\n <div className=\"absolute inset-0 flex flex-col items-center justify-center\">\n {centerValue && <span className=\"text-base font-black tracking-tight text-foreground tabular-nums\">{centerValue}</span>}\n {centerLabel && <span className=\"text-[9px] font-medium text-muted-foreground uppercase\">{centerLabel}</span>}\n </div>\n )}\n </div>\n );\n}\n\nexport function Sparkline({ data, color }: { data: number[]; color: string }): ReactElement | null {\n if (data.length < 2) return null;\n const min = Math.min(...data);\n const max = Math.max(...data);\n const range = max - min || 1;\n const W = 72;\n const H = 28;\n const pts = data\n .map((v, i) => `${(i / (data.length - 1)) * W},${H - ((v - min) / range) * (H - 2) - 1}`)\n .join(\" \");\n return (\n <svg width={W} height={H} viewBox={`0 0 ${W} ${H}`} className=\"overflow-visible opacity-70\">\n <polyline points={pts} fill=\"none\" stroke={color} strokeWidth=\"1.5\" strokeLinecap=\"round\" strokeLinejoin=\"round\" />\n </svg>\n );\n}\n\nfunction AreaSparkline({ data, color }: { data: number[]; color: string }): ReactElement | null {\n if (data.length < 2) return null;\n const min = Math.min(...data);\n const max = Math.max(...data);\n const range = max - min || 1;\n const W = 200;\n const H = 28;\n const P = 2;\n const xs = data.map((_, i) => (i / (data.length - 1)) * W);\n const ys = data.map((v) => H - ((v - min) / range) * (H - 2 * P) - P);\n const linePts = xs.map((x, i) => `${x},${ys[i]}`).join(\" \");\n const areaPath = `M${xs[0]},${H} ` + xs.map((x, i) => `L${x},${ys[i]}`).join(\" \") + ` L${xs[xs.length - 1]},${H} Z`;\n\n return (\n <svg width={W} height={H} viewBox={`0 0 ${W} ${H}`} className=\"overflow-visible\" preserveAspectRatio=\"none\">\n <defs>\n <linearGradient id=\"kpi-card-spark-fill\" x1=\"0\" y1=\"0\" x2=\"0\" y2=\"1\">\n <stop offset=\"0%\" stopColor={color} stopOpacity=\"0.22\" />\n <stop offset=\"100%\" stopColor={color} stopOpacity=\"0\" />\n </linearGradient>\n </defs>\n <path d={areaPath} fill=\"url(#kpi-card-spark-fill)\" />\n <polyline points={linePts} fill=\"none\" stroke={color} strokeWidth=\"1.75\" strokeLinecap=\"round\" strokeLinejoin=\"round\" />\n <circle cx={xs[xs.length - 1]} cy={ys[ys.length - 1]} r=\"2.5\" fill={color} />\n </svg>\n );\n}\n\nconst rowBetween = \"flex items-center justify-between\";\n\n/**\n * Dashboard KPI tile in three variants — `hero` (large, primary-colored,\n * for the single headline metric), `default` (bordered card for a KPI\n * grid), and `mini` (compact, for dense grids of secondary metrics).\n * Optionally shows a badge, a trend sparkline, and (hero only) a\n * progress-vs-target bar.\n */\nexport const KpiCard = memo(function KpiCard({\n label,\n value,\n icon: Icon,\n badge,\n badgeLabel,\n variant = \"default\",\n loading = false,\n sub,\n subTone = \"default\",\n href,\n sparkline,\n sparklineColor = \"var(--color-primary, #3b82f6)\",\n progress,\n progressLabel,\n segments,\n centerValue,\n testId,\n}: KpiCardProps): ReactElement {\n if (variant === \"hero\") {\n return (\n <div\n data-testid={testId}\n className=\"relative col-span-2 flex min-w-0 flex-1 flex-col gap-1.5 overflow-hidden rounded-2xl p-4 md:p-3 lg:col-span-1 lg:max-w-[340px] lg:min-w-[260px]\"\n style={{\n background: \"var(--color-primary)\",\n boxShadow: \"0 2px 10px color-mix(in oklch, var(--color-primary) 18%, transparent)\",\n }}\n >\n <div className=\"relative flex items-start justify-between\">\n <p className=\"text-[11px] font-bold tracking-[0.14em] text-white/70 uppercase\">{label}</p>\n {Icon && (\n <div className=\"flex h-6 w-6 items-center justify-center rounded-lg bg-white/15 ring-1 ring-white/20\">\n <Icon className=\"h-3 w-3 text-white/90\" aria-hidden=\"true\" />\n </div>\n )}\n </div>\n\n <div className=\"relative\">\n {loading ? (\n <div className=\"h-6 w-28 animate-pulse rounded-lg bg-white/15\" />\n ) : (\n <p className=\"text-2xl leading-none font-black tracking-tight text-white tabular-nums md:text-[22px]\">\n {value ?? \"—\"}\n </p>\n )}\n </div>\n\n {(badge || badgeLabel) && !loading && (\n <div className=\"relative flex items-center gap-2\">\n {badge && (\n <span\n className={cn(\n \"inline-flex items-center gap-1 rounded-full px-2.5 py-0.5 text-[11px] font-bold tabular-nums ring-1\",\n badge.positive ? \"bg-white/15 text-white ring-white/25\" : \"bg-black/25 text-white ring-white/15\",\n )}\n >\n {badge.text}\n </span>\n )}\n {badgeLabel && <span className=\"text-[11px] text-white/70\">{badgeLabel}</span>}\n </div>\n )}\n\n {sub && !loading && (\n <p className=\"relative -mt-1 text-[11px] font-medium text-white/75 tabular-nums\">{sub}</p>\n )}\n\n {progress != null && !loading && (\n <div className=\"relative flex items-center gap-1.5\">\n <div className=\"h-1 flex-1 overflow-hidden rounded-full bg-white/20\">\n <div className=\"h-1 rounded-full bg-white/85\" style={{ width: `${Math.min(100, Math.max(0, progress))}%` }} />\n </div>\n {progressLabel && <span className=\"shrink-0 text-[11px] font-semibold text-white/80 tabular-nums\">{progressLabel}</span>}\n </div>\n )}\n\n {/* Area sparkline pinned to bottom, always white: the hero card's own\n background is the `var(--color-primary)` gradient above, so a\n primary-colored line (the default) disappears against it. */}\n {sparkline && sparkline.length > 1 && !loading && (\n <div className=\"relative -mx-4 mt-auto -mb-4 md:-mx-3 md:-mb-3\">\n <AreaSparkline data={sparkline} color=\"#ffffff\" />\n </div>\n )}\n </div>\n );\n }\n\n if (variant === \"mini\") {\n const iconSlot = Icon ? (\n href ? (\n <a\n href={href}\n className=\"tap-target flex h-7 w-7 shrink-0 items-center justify-center rounded-xl bg-primary/10 text-primary transition-[background-color,scale] hover:bg-primary/20 active:scale-90 motion-reduce:transition-none md:h-6 md:w-6\"\n >\n <Icon className=\"h-4 w-4 md:h-3.5 md:w-3.5\" aria-hidden=\"true\" />\n </a>\n ) : (\n <div className=\"flex h-7 w-7 shrink-0 items-center justify-center rounded-xl bg-primary/10 text-primary md:h-6 md:w-6\">\n <Icon className=\"h-4 w-4 md:h-3.5 md:w-3.5\" aria-hidden=\"true\" />\n </div>\n )\n ) : null;\n\n return (\n <div\n data-testid={testId}\n className={cn(\n \"flex h-full min-w-0 flex-1 flex-col gap-1.5 overflow-hidden rounded-2xl border border-border bg-card p-3 transition-shadow md:p-2.5\",\n href && \"hover:border-primary/20 hover:shadow-md\",\n )}\n >\n <div className={rowBetween}>\n <p className=\"text-[11px] font-bold tracking-[0.12em] text-muted-foreground uppercase\">{label}</p>\n {iconSlot}\n </div>\n\n <div className=\"flex min-w-0 flex-1 items-center gap-2\">\n {loading ? (\n <Skeleton className=\"h-6 w-16\" />\n ) : (\n <>\n <p className=\"min-w-0 animate-in truncate text-[20px] leading-none font-black tracking-tight text-foreground duration-200 fade-in-0 tabular-nums motion-reduce:animate-none md:text-[16px]\">\n {value ?? \"—\"}\n </p>\n {badge && (\n <span\n className={cn(\n \"shrink-0 animate-in rounded-md px-1.5 py-0.5 text-[11px] font-bold duration-200 fade-in-0 tabular-nums motion-reduce:animate-none\",\n badge.positive\n ? \"bg-emerald-100 text-emerald-700 dark:bg-emerald-900/30 dark:text-emerald-400\"\n : \"bg-muted text-muted-foreground\",\n )}\n >\n {badge.text}\n </span>\n )}\n </>\n )}\n </div>\n\n {(sub || sparkline) && !loading && (\n <div className=\"flex items-end justify-between gap-2\">\n {sub && (\n <p\n className={cn(\n \"text-[11px]\",\n subTone === \"danger\"\n ? \"font-semibold text-red-600 dark:text-red-400\"\n : subTone === \"warn\"\n ? \"font-semibold text-amber-700 dark:text-amber-300\"\n : \"text-muted-foreground\",\n )}\n >\n {sub}\n </p>\n )}\n {sparkline && <Sparkline data={sparkline} color={sparklineColor} />}\n </div>\n )}\n </div>\n );\n }\n\n if (variant === \"donut\") {\n const total = segments?.reduce((sum, s) => sum + s.value, 0) ?? 0;\n\n return (\n <div data-testid={testId} className=\"rounded-xl border border-border bg-card p-5\">\n <div className={rowBetween}>\n <p className=\"text-[11px] font-bold tracking-[0.12em] text-muted-foreground uppercase\">{label}</p>\n {Icon && (\n <div className=\"flex h-7 w-7 shrink-0 items-center justify-center rounded-xl bg-primary/8 text-primary\">\n <Icon className=\"h-3.5 w-3.5\" aria-hidden=\"true\" />\n </div>\n )}\n </div>\n\n {loading ? (\n <div className=\"mt-3 flex items-center gap-4\">\n <Skeleton className=\"h-24 w-24 shrink-0 rounded-full\" />\n <div className=\"flex flex-1 flex-col gap-2\">\n <Skeleton className=\"h-3 w-full\" />\n <Skeleton className=\"h-3 w-3/4\" />\n <Skeleton className=\"h-3 w-1/2\" />\n </div>\n </div>\n ) : segments && segments.length > 0 ? (\n <div className=\"mt-3 flex items-center gap-4\">\n <DonutChart data={segments} centerValue={centerValue ?? String(total)} />\n <ul className=\"flex min-w-0 flex-1 flex-col gap-1.5\">\n {segments.map((segment, i) => (\n <li key={segment.label} className=\"flex items-center gap-2 text-[12px]\">\n <span\n className=\"h-2 w-2 shrink-0 rounded-full\"\n style={{ backgroundColor: segment.color ?? DONUT_COLORS[i % DONUT_COLORS.length] }}\n aria-hidden=\"true\"\n />\n <span className=\"min-w-0 flex-1 truncate text-muted-foreground\">{segment.label}</span>\n <span className=\"shrink-0 font-semibold text-foreground tabular-nums\">\n {total > 0 ? `${Math.round((segment.value / total) * 100)}%` : segment.value}\n </span>\n </li>\n ))}\n </ul>\n </div>\n ) : (\n <span className=\"mt-3 block text-2xl font-black text-muted-foreground/40\">—</span>\n )}\n\n {sub && !loading && <p className=\"mt-2.5 text-[11px] text-muted-foreground tabular-nums\">{sub}</p>}\n </div>\n );\n }\n\n // Default variant: splits a value like \"12 kunden\" or \"42 %\" into a\n // large number plus a small prefix/suffix unit.\n const strValue = value != null ? String(value) : null;\n const parts = strValue ? strValue.split(/\\s(.+)/) : null;\n const plain = !parts || parts.length === 1;\n const isSuffix = !plain && /^\\d/.test(parts![0]!) && parts![1]!.length <= 3;\n const prefix = isSuffix ? null : parts?.[0];\n const number = isSuffix ? parts![0] : (parts?.[1] ?? parts?.[0]);\n const suffix = isSuffix ? parts![1] : null;\n\n return (\n <div data-testid={testId} className=\"rounded-xl border border-border bg-card p-5\">\n <div className={rowBetween}>\n <p className=\"text-[11px] font-bold tracking-[0.12em] text-muted-foreground uppercase\">{label}</p>\n {Icon && (\n <div className=\"flex h-7 w-7 shrink-0 items-center justify-center rounded-xl bg-primary/8 text-primary\">\n <Icon className=\"h-3.5 w-3.5\" aria-hidden=\"true\" />\n </div>\n )}\n </div>\n\n <div className=\"mt-3\">\n {loading ? (\n <Skeleton className=\"h-7 w-20\" />\n ) : value == null ? (\n <span className=\"text-2xl font-black text-muted-foreground/40\">—</span>\n ) : plain ? (\n <span className=\"animate-in text-2xl font-black tracking-tight text-foreground duration-200 fade-in-0 tabular-nums motion-reduce:animate-none\">\n {strValue}\n </span>\n ) : (\n <span className=\"animate-in font-black tracking-tight text-foreground duration-200 fade-in-0 tabular-nums motion-reduce:animate-none\">\n {prefix && <span className=\"text-sm text-muted-foreground\">{prefix} </span>}\n <span className=\"text-2xl\">{number}</span>\n {suffix && <span className=\"text-sm text-muted-foreground\"> {suffix}</span>}\n </span>\n )}\n {sub && !loading && <p className=\"mt-0.5 text-[11px] text-muted-foreground tabular-nums\">{sub}</p>}\n </div>\n\n {(badge || badgeLabel || sparkline) && !loading && (\n <div className=\"mt-2.5 flex items-end justify-between gap-2\">\n <div className=\"flex flex-wrap items-center gap-2\">\n {badge && (\n <span\n className={cn(\n \"rounded-md px-1.5 py-0.5 text-[11px] font-semibold tabular-nums\",\n badge.positive\n ? \"bg-emerald-100 text-emerald-700 dark:bg-emerald-900/30 dark:text-emerald-400\"\n : \"bg-muted text-muted-foreground\",\n )}\n >\n {badge.text}\n </span>\n )}\n {badgeLabel && <span className=\"text-[11px] text-muted-foreground\">{badgeLabel}</span>}\n </div>\n {sparkline && <Sparkline data={sparkline} color={sparklineColor} />}\n </div>\n )}\n </div>\n );\n});\n","import { Search } from \"lucide-react\";\nimport type { ComponentType, InputHTMLAttributes, ReactElement, ReactNode, Ref } from \"react\";\nimport { cn } from \"../../lib/utils\";\nimport { LoadingSpinner } from \"../loading-spinner/LoadingSpinner\";\n\nexport interface SearchPanelMode {\n key: string;\n label: string;\n icon?: ComponentType<{ className?: string }>;\n}\n\nexport interface SearchPanelProps\n extends Omit<InputHTMLAttributes<HTMLInputElement>, \"type\" | \"value\" | \"onChange\" | \"size\"> {\n value: string;\n onChange: (value: string) => void;\n /** Swaps the leading search icon for a spinner while a search request is in flight. */\n isLoading?: boolean;\n /** Extra content after the input, e.g. a mic button. */\n trailingSlot?: ReactNode;\n /** Keyboard-shortcut hint rendered after `trailingSlot`, e.g. `\"⌘K\"`. Omit to hide it. */\n shortcutHint?: string;\n /** Mode-switcher pills rendered below the input row (e.g. \"Search\" / \"Ask AI\"). Omit to hide the row entirely. */\n modes?: SearchPanelMode[];\n activeMode?: string;\n onModeChange?: (key: string) => void;\n /** Squares the panel's bottom corners so a results dropdown anchored directly below it reads as one continuous surface. */\n expanded?: boolean;\n inputRef?: Ref<HTMLInputElement>;\n className?: string;\n}\n\n/**\n * Bordered search card: an input row (leading icon/spinner, input, optional\n * trailing slot and keyboard-shortcut hint) plus an optional row of\n * mode-switcher pills below it. Headless on results — the caller renders\n * whatever dropdown or inline results belong under it.\n */\nexport function SearchPanel({\n value,\n onChange,\n isLoading,\n trailingSlot,\n shortcutHint,\n modes,\n activeMode,\n onModeChange,\n expanded = false,\n inputRef,\n className,\n ...props\n}: SearchPanelProps): ReactElement {\n return (\n <div\n className={cn(\n \"flex flex-col border border-border bg-card shadow-sm\",\n expanded ? \"rounded-t-2xl border-b-transparent\" : \"rounded-2xl\",\n className,\n )}\n >\n <div className=\"flex h-14 items-center gap-3 px-4\">\n {isLoading ? (\n <LoadingSpinner size=\"sm\" />\n ) : (\n <Search className=\"h-5 w-5 shrink-0 text-muted-foreground\" aria-hidden=\"true\" />\n )}\n <input\n ref={inputRef}\n type=\"text\"\n value={value}\n onChange={(event) => onChange(event.target.value)}\n className=\"min-w-0 flex-1 bg-transparent text-[15px] text-foreground outline-none placeholder:text-muted-foreground\"\n {...props}\n />\n {trailingSlot}\n {shortcutHint && (\n <kbd\n aria-hidden=\"true\"\n className=\"hidden shrink-0 items-center rounded border border-border bg-muted/60 px-1.5 py-0.5 text-[10px] font-medium text-muted-foreground select-none sm:inline-flex\"\n >\n {shortcutHint}\n </kbd>\n )}\n </div>\n\n {modes && modes.length > 0 && (\n <div className=\"flex items-center gap-2 px-4 pb-3\">\n {modes.map(({ key, label, icon: Icon }) => (\n <button\n key={key}\n type=\"button\"\n onClick={() => onModeChange?.(key)}\n className={cn(\n \"flex items-center gap-1.5 rounded-full px-3 py-1.5 text-[13px] font-medium transition-colors\",\n activeMode === key\n ? \"bg-primary text-primary-foreground\"\n : \"text-muted-foreground hover:bg-muted\",\n )}\n >\n {Icon && <Icon className=\"h-3.5 w-3.5\" aria-hidden=\"true\" />}\n {label}\n </button>\n ))}\n </div>\n )}\n </div>\n );\n}\n","import { Search } from \"lucide-react\";\nimport type { ButtonHTMLAttributes, ReactElement } from \"react\";\nimport { Button } from \"../../primitives/button\";\n\nexport interface SearchTriggerProps extends Omit<ButtonHTMLAttributes<HTMLButtonElement>, \"children\"> {\n /** Accessible label, also used as the tooltip text by callers that wrap this in one. @default \"Search\" */\n label?: string;\n}\n\n/**\n * Icon-only header button that opens a search overlay (a `SearchPanel`, a\n * dropdown, a `Sheet` — this owns no state or panel of its own). For a\n * full-width always-visible input instead, use `SearchBar`.\n */\nexport function SearchTrigger({ label = \"Search\", ...props }: SearchTriggerProps): ReactElement {\n return (\n <Button type=\"button\" variant=\"ghost\" size=\"icon\" aria-label={label} {...props}>\n <Search className=\"h-[18px] w-[18px]\" aria-hidden=\"true\" />\n </Button>\n );\n}\n","import { createContext, useContext } from \"react\";\n\ninterface SidebarContextValue {\n /** True when the nearest `<Sidebar>` is showing its icon-only rail (labels/group headers hidden). */\n collapsed: boolean;\n}\n\nconst SidebarContext = createContext<SidebarContextValue>({ collapsed: false });\n\nexport const SidebarContextProvider = SidebarContext.Provider;\n\n/**\n * Whether the nearest ancestor `<Sidebar>` is rail-collapsed. Defaults to\n * `false` when there is no ancestor `<Sidebar>` — this is what lets\n * `NavGroup`/`NavItem` be reused standalone inside a mobile drawer (`Sheet`),\n * which is never rail-collapsed.\n */\nexport function useSidebarCollapsed(): boolean {\n return useContext(SidebarContext).collapsed;\n}\n","import type { ComponentPropsWithoutRef, ElementType, ReactElement, ReactNode } from \"react\";\nimport { cn } from \"../../lib/utils\";\nimport { Tooltip, TooltipContent, TooltipTrigger } from \"../../primitives/tooltip\";\nimport { useSidebarCollapsed } from \"./context\";\n\n/** Shape a `lucide-react` icon component satisfies — `NavItem` sizes and colors it itself. */\nexport interface NavIconProps {\n className?: string;\n strokeWidth?: string | number;\n \"aria-hidden\"?: boolean | \"true\" | \"false\";\n}\n\nexport type NavItemProps<T extends ElementType = \"a\"> = {\n /** The element (or router `Link`) this renders as, e.g. `as={Link} to=\"/overview\"`. @default \"a\" */\n as?: T;\n icon?: ElementType<NavIconProps>;\n label: ReactNode;\n /** Highlights this row as the current page. The caller computes this from its own router — `NavItem` has no router opinion. */\n active?: boolean;\n /** Rendered after the label, and again in the collapsed-rail tooltip — e.g. an experimental-status `Badge`. */\n badge?: ReactNode;\n className?: string;\n} & Omit<ComponentPropsWithoutRef<T>, \"as\" | \"className\">;\n\n/**\n * One row inside a `Sidebar`/`NavGroup`. Polymorphic via `as` so it renders a\n * plain `<a>` by default or a router's own `Link` (extra props like `to`/\n * `href` pass straight through). When the nearest `Sidebar` is rail-\n * collapsed, the row shrinks to icon-only and shows `label`/`badge` in a\n * hover tooltip instead.\n */\nexport function NavItem<T extends ElementType = \"a\">({\n as,\n icon: Icon,\n label,\n active = false,\n badge,\n className,\n ...rest\n}: NavItemProps<T>): ReactElement {\n const collapsed = useSidebarCollapsed();\n const Comp = (as ?? \"a\") as ElementType;\n\n const row = (\n <Comp\n className={cn(\n \"group relative flex items-center rounded-lg px-2.5 py-2 text-[13px] font-medium transition-colors\",\n \"focus-visible:ring-2 focus-visible:ring-primary focus-visible:ring-inset focus-visible:outline-none\",\n collapsed ? \"justify-center gap-0\" : \"gap-2.5\",\n active\n ? \"bg-nav-primary/8 font-semibold text-foreground\"\n : \"text-foreground/55 hover:bg-muted/60 hover:text-foreground\",\n className,\n )}\n {...rest}\n >\n {Icon && (\n <Icon\n className={cn(\"h-[18px] w-[18px] shrink-0\", active ? \"text-nav-primary\" : \"text-muted-foreground\")}\n strokeWidth={active ? 2 : 1.75}\n aria-hidden\n />\n )}\n <span\n className={cn(\n \"truncate transition-[opacity,max-width] duration-150\",\n collapsed ? \"max-w-0 opacity-0\" : \"max-w-[10rem] opacity-100\",\n )}\n >\n {label}\n </span>\n {!collapsed && badge}\n </Comp>\n );\n\n if (!collapsed) return row;\n\n return (\n <Tooltip>\n <TooltipTrigger asChild>{row}</TooltipTrigger>\n <TooltipContent side=\"right\" className=\"flex items-center gap-1.5\">\n {label}\n {badge}\n </TooltipContent>\n </Tooltip>\n );\n}\n","import { ChevronDown } from \"lucide-react\";\nimport { useState, type ReactElement, type ReactNode } from \"react\";\nimport { cn } from \"../../lib/utils\";\nimport { useSidebarCollapsed } from \"./context\";\n\nexport interface NavGroupProps {\n /** Section header. Omit for a flat group with no header/collapse affordance. */\n label?: ReactNode;\n /** Uncontrolled starting collapsed state. @default false */\n defaultCollapsed?: boolean;\n /** Controlled collapsed state. */\n collapsed?: boolean;\n onCollapsedChange?: (collapsed: boolean) => void;\n children: ReactNode;\n className?: string;\n}\n\n/**\n * A labeled, independently collapsible section of `NavItem`s inside a\n * `Sidebar`. This group's own collapsed state (items hidden/shown) is\n * separate from the sidebar's rail-collapse: when the sidebar itself is\n * rail-collapsed, this group's header shrinks to a thin divider (its items\n * stay visible as icons) rather than disappearing, since there's no room for\n * a clickable label to toggle.\n */\nexport function NavGroup({\n label,\n defaultCollapsed = false,\n collapsed,\n onCollapsedChange,\n children,\n className,\n}: NavGroupProps): ReactElement {\n const [internalCollapsed, setInternalCollapsed] = useState(defaultCollapsed);\n const groupCollapsed = collapsed ?? internalCollapsed;\n const railCollapsed = useSidebarCollapsed();\n\n const setGroupCollapsed = (next: boolean) => {\n onCollapsedChange?.(next);\n if (collapsed === undefined) setInternalCollapsed(next);\n };\n\n return (\n <div className={cn(\"flex flex-col gap-0.5\", className)}>\n {label &&\n (railCollapsed ? (\n <div className=\"mx-2 my-1 h-px bg-border/50\" aria-hidden />\n ) : (\n <button\n type=\"button\"\n onClick={() => setGroupCollapsed(!groupCollapsed)}\n aria-expanded={!groupCollapsed}\n className=\"group flex w-full items-center justify-between px-2.5 py-0.5 text-[11px] font-medium text-muted-foreground/80 hover:text-foreground\"\n >\n <span>{label}</span>\n <ChevronDown\n className={cn(\n \"h-4 w-4 opacity-40 transition-transform group-hover:opacity-100\",\n groupCollapsed && \"-rotate-90\",\n )}\n aria-hidden\n />\n </button>\n ))}\n {!groupCollapsed && <div className=\"flex flex-col gap-0.5\">{children}</div>}\n </div>\n );\n}\n","import { PanelLeftClose, PanelLeftOpen } from \"lucide-react\";\nimport {\n useCallback,\n useEffect,\n useRef,\n useState,\n type ComponentPropsWithoutRef,\n type PointerEvent as ReactPointerEvent,\n type ReactElement,\n type ReactNode,\n} from \"react\";\nimport { cn } from \"../../lib/utils\";\nimport { TooltipProvider } from \"../../primitives/tooltip\";\nimport { SidebarContextProvider } from \"./context\";\n\nfunction resolve<T>(value: T | ((collapsed: boolean) => T), collapsed: boolean): T {\n return typeof value === \"function\" ? (value as (collapsed: boolean) => T)(collapsed) : value;\n}\n\nexport interface SidebarProps {\n /** Rail-collapse the whole sidebar to an icon-only strip. Controlled. */\n collapsed?: boolean;\n /** Renders a built-in collapse/expand toggle button and fires when it's clicked. Omit to hide the toggle and drive `collapsed` some other way. */\n onCollapsedChange?: (collapsed: boolean) => void;\n /** Lets the user drag the trailing edge to resize. @default false */\n resizable?: boolean;\n /** Controlled width in px (only meaningful while expanded). */\n width?: number;\n onWidthChange?: (width: number) => void;\n /** Uncontrolled starting width in px, and the double-click-to-reset target. @default 240 */\n defaultWidth?: number;\n minWidth?: number;\n maxWidth?: number;\n /** Width of the icon-only rail. @default 56 */\n railWidth?: number;\n /** Logo/wordmark slot. Pass a function to swap in a compact mark once `collapsed` — the shared component only owns the collapse *toggle button*, not your branding. */\n header?: ReactNode | ((collapsed: boolean) => ReactNode);\n /** Pinned below the scrollable nav area (e.g. a user-profile row), outside the scroll-fade. */\n footer?: ReactNode | ((collapsed: boolean) => ReactNode);\n children: ReactNode;\n className?: string;\n}\n\n/**\n * App shell's left navigation panel: fixed-width or drag-resizable, with an\n * optional icon-only rail-collapse mode (tooltips on hover, via `NavItem`).\n * Renders `children` (typically one or more `NavGroup`s of `NavItem`s)\n * inside a scrollable area with a bottom scroll-fade once content overflows.\n *\n * For a mobile drawer, don't reuse `Sidebar` itself (its resize handle and\n * rail-collapse don't apply there) — render the same `NavGroup`/`NavItem`\n * children inside a `Sheet`, wrapped in the separately-exported `SidebarNav`\n * for the scroll-fade behavior.\n */\nexport function Sidebar({\n collapsed = false,\n onCollapsedChange,\n resizable = false,\n width,\n onWidthChange,\n defaultWidth = 240,\n minWidth = 180,\n maxWidth = 420,\n railWidth = 56,\n header,\n footer,\n children,\n className,\n}: SidebarProps): ReactElement {\n const [internalWidth, setInternalWidth] = useState(defaultWidth);\n const currentWidth = width ?? internalWidth;\n const [isDragging, setIsDragging] = useState(false);\n\n const setWidth = useCallback(\n (next: number) => {\n const clamped = Math.min(maxWidth, Math.max(minWidth, next));\n onWidthChange?.(clamped);\n if (width === undefined) setInternalWidth(clamped);\n },\n [maxWidth, minWidth, onWidthChange, width],\n );\n\n const dragStartRef = useRef<{ x: number; width: number } | null>(null);\n\n const handlePointerDown = (event: ReactPointerEvent<HTMLDivElement>) => {\n event.currentTarget.setPointerCapture(event.pointerId);\n dragStartRef.current = { x: event.clientX, width: currentWidth };\n setIsDragging(true);\n };\n const handlePointerMove = (event: ReactPointerEvent<HTMLDivElement>) => {\n if (!dragStartRef.current) return;\n setWidth(dragStartRef.current.width + (event.clientX - dragStartRef.current.x));\n };\n const endDrag = (event: ReactPointerEvent<HTMLDivElement>) => {\n if (event.currentTarget.hasPointerCapture(event.pointerId)) {\n event.currentTarget.releasePointerCapture(event.pointerId);\n }\n dragStartRef.current = null;\n setIsDragging(false);\n };\n\n return (\n <SidebarContextProvider value={{ collapsed }}>\n <TooltipProvider delayDuration={200}>\n <aside\n style={{ width: collapsed ? railWidth : currentWidth }}\n className={cn(\n \"relative flex h-full shrink-0 flex-col border-r border-border bg-sidebar\",\n !isDragging && \"transition-[width] duration-150\",\n className,\n )}\n >\n {(header || onCollapsedChange) && (\n <div className=\"flex h-16 items-center gap-2 border-b border-border px-3\">\n {collapsed && onCollapsedChange ? (\n // Collapsed rail: the header slot (e.g. a compact logo mark) and the\n // expand toggle would otherwise compete for the narrow rail's width\n // and clip each other, so they're stacked instead — the header shows\n // by default and cross-fades to the toggle icon on hover, matching\n // the same affordance OneSales' own sidebar rail uses.\n <button\n type=\"button\"\n onClick={() => onCollapsedChange(!collapsed)}\n aria-label=\"Expand sidebar\"\n className=\"group relative flex h-9 w-9 shrink-0 items-center justify-center\"\n >\n {header && (\n <span className=\"transition-opacity group-hover:opacity-0\">\n {resolve(header, collapsed)}\n </span>\n )}\n <PanelLeftOpen\n className=\"absolute h-4 w-4 text-muted-foreground opacity-0 transition-opacity group-hover:opacity-100\"\n aria-hidden\n />\n </button>\n ) : (\n <>\n {header && <div className=\"min-w-0 flex-1\">{resolve(header, collapsed)}</div>}\n {onCollapsedChange && (\n <button\n type=\"button\"\n onClick={() => onCollapsedChange(!collapsed)}\n aria-label=\"Collapse sidebar\"\n className=\"flex h-7 w-7 shrink-0 items-center justify-center rounded-md text-muted-foreground hover:bg-muted hover:text-foreground\"\n >\n <PanelLeftClose className=\"h-4 w-4\" aria-hidden />\n </button>\n )}\n </>\n )}\n </div>\n )}\n\n <SidebarNav>{children}</SidebarNav>\n\n {footer && <div className=\"border-t border-border/50 px-2 py-2\">{resolve(footer, collapsed)}</div>}\n\n {resizable && !collapsed && (\n <div\n onPointerDown={handlePointerDown}\n onPointerMove={handlePointerMove}\n onPointerUp={endDrag}\n onDoubleClick={() => setWidth(defaultWidth)}\n className=\"absolute top-0 right-0 h-full w-1.5 cursor-col-resize touch-none hover:bg-primary/40\"\n />\n )}\n </aside>\n </TooltipProvider>\n </SidebarContextProvider>\n );\n}\n\nexport type SidebarNavProps = {\n children: ReactNode;\n className?: string;\n} & Omit<ComponentPropsWithoutRef<\"div\">, \"className\" | \"children\" | \"ref\">;\n\n/**\n * The scrollable nav-item area, with a bottom scroll-fade once content\n * overflows. Used internally by `Sidebar`; exported separately so a mobile\n * drawer can wrap the same `NavGroup`/`NavItem` children in it without the\n * rest of the `Sidebar` shell. Extra props (`onClick`, `data-testid`, …)\n * forward to the scrollable element itself — e.g. `onClick` to close a\n * mobile drawer when any nav link inside is tapped.\n */\nexport function SidebarNav({ children, className, ...rest }: SidebarNavProps): ReactElement {\n const ref = useRef<HTMLDivElement>(null);\n const [showFade, setShowFade] = useState(false);\n\n useEffect(() => {\n const el = ref.current;\n if (!el) return;\n const update = () => setShowFade(el.scrollHeight - el.scrollTop - el.clientHeight > 1);\n update();\n el.addEventListener(\"scroll\", update);\n const observer = new ResizeObserver(update);\n observer.observe(el);\n return () => {\n el.removeEventListener(\"scroll\", update);\n observer.disconnect();\n };\n }, []);\n\n return (\n <div className=\"relative flex min-h-0 flex-1 flex-col\">\n <div\n ref={ref}\n className={cn(\"flex flex-1 flex-col gap-3 overflow-y-auto px-2 py-2\", className)}\n {...rest}\n >\n {children}\n </div>\n {showFade && (\n <div\n className=\"pointer-events-none absolute right-0 bottom-0 left-0 h-6 bg-gradient-to-t from-sidebar to-transparent\"\n aria-hidden\n />\n )}\n </div>\n );\n}\n","import { useEffect, useRef } from \"react\";\nimport { Check, Plus } from \"lucide-react\";\nimport { cn } from \"../../lib/utils\";\n\n/** The minimal shape this component needs to render one chip in the stepper. */\nexport interface StepperStep {\n /** 1-based step number, also used as the React key and navigation target. */\n n: number;\n /** Visible label under the chip. */\n label: string;\n /** Small uppercase caption under the label (e.g. a phase/section name). */\n phase: string;\n}\n\nexport interface StepperProps {\n /** The current step number (1-based, matches a `StepperStep.n`). */\n step: number;\n /** Highest step number reachable so far -- steps beyond this aren't clickable. */\n maxStep: number;\n /** Called with a step's `n` when a navigable chip is clicked. */\n onNavigate: (n: number) => void;\n /** Called when the trailing \"new\" button is clicked. Omit to hide that button entirely. */\n onNew?: () => void;\n /** The steps to render, in order. */\n steps: StepperStep[];\n /** Accessible label for the stepper's `<nav>`. @default \"Steps\" */\n navLabel?: string;\n /** Visible text and title of the trailing `onNew` button. Only relevant when `onNew` is passed. @default \"New\" */\n newLabel?: string;\n /** `data-testid` for the horizontally-scrolling steps region. @default \"stepper-scroll\" */\n scrollTestId?: string;\n /** `data-testid` for the trailing `onNew` button, when rendered. */\n newTestId?: string;\n}\n\n/**\n * Numbered-chip wizard progress indicator: a horizontally-scrolling row of\n * step chips (done/active/upcoming, connected by a line that fills in as\n * steps complete) plus an optional trailing \"start over\" button. Replaces\n * the same shape hand-rolled independently by more than one multi-step\n * wizard.\n *\n * Note: the original OneSales `Stepper` this was ported from also supported\n * a one-off `tinderSubStep` prop that injected a bespoke \"matcher\" chip\n * between two specific steps for a single screen's own sub-flow. That was\n * deliberately left out of this generic version -- it doesn't generalize\n * meaningfully beyond that one screen. Don't re-add it here; a consumer\n * that needs a one-off extra chip should compose its own around this\n * component instead.\n */\nexport function Stepper({\n step,\n maxStep,\n onNavigate,\n onNew,\n steps,\n navLabel = \"Steps\",\n newLabel = \"New\",\n scrollTestId = \"stepper-scroll\",\n newTestId,\n}: StepperProps) {\n const stepRefs = useRef(new Map<number, HTMLButtonElement>());\n\n useEffect(() => {\n const activeStep = stepRefs.current.get(step);\n activeStep?.scrollIntoView({ block: \"nearest\", inline: \"center\" });\n }, [step]);\n\n return (\n // onNew is pinned outside the horizontally-scrolling region below (a sibling of\n // it, not a child) so its own edge never scrolls off-screen along with the\n // later steps once the scroller's min-width doesn't fit the viewport.\n <div className=\"flex w-full shrink-0 items-center gap-2\">\n <nav aria-label={navLabel} className=\"min-w-0 flex-1\">\n <div\n data-testid={scrollTestId}\n className=\"flex w-full items-center gap-0 overflow-x-auto px-2 py-1\"\n >\n <ol className=\"flex min-w-[700px] flex-1 items-start\">\n {steps.map(({ n, label, phase }, i) => {\n const done = step > n;\n const active = step === n;\n const navigable = n <= maxStep && n !== step;\n const last = i === steps.length - 1;\n return (\n <li key={n} className={cn(\"flex items-start\", !last && \"flex-1\")}>\n <button\n ref={(element) => {\n if (element) stepRefs.current.set(n, element);\n else stepRefs.current.delete(n);\n }}\n data-testid={`step-${n}`}\n aria-disabled={!navigable}\n aria-current={active ? \"step\" : undefined}\n onClick={() => navigable && onNavigate(n)}\n className={cn(\n \"flex min-w-[68px] flex-col items-center gap-0.5 transition-opacity\",\n navigable ? \"cursor-pointer hover:opacity-80\" : \"cursor-default\",\n )}\n >\n <div\n className={cn(\n \"flex h-7 w-7 shrink-0 items-center justify-center rounded-full text-[11px] font-bold transition-colors\",\n done\n ? \"bg-primary/15 text-primary\"\n : active\n ? \"bg-primary text-primary-foreground\"\n : \"bg-muted text-muted-foreground\",\n )}\n >\n {done ? <Check className=\"h-3 w-3\" /> : n}\n </div>\n <span\n className={cn(\n \"text-center whitespace-nowrap transition-colors\",\n active\n ? \"text-[12px] font-semibold text-foreground\"\n : done\n ? \"text-[12px] font-medium text-primary\"\n : \"text-[12px] font-medium text-muted-foreground\",\n )}\n >\n {label}\n </span>\n <span className=\"text-[9px] tracking-[0.5px] text-muted-foreground/50 uppercase\">\n {phase}\n </span>\n </button>\n {!last && (\n <div\n className={cn(\n \"mx-1.5 mt-3.5 h-px flex-1 transition-colors\",\n done ? \"bg-primary\" : \"bg-border\",\n )}\n />\n )}\n </li>\n );\n })}\n </ol>\n </div>\n </nav>\n {onNew && (\n <button\n data-testid={newTestId}\n onClick={onNew}\n title={newLabel}\n className=\"flex shrink-0 items-center gap-1.5 rounded-lg border border-border px-3 py-1.5 text-[12px] font-semibold text-foreground transition-colors hover:bg-muted/50\"\n >\n <Plus className=\"h-3.5 w-3.5\" />\n {newLabel}\n </button>\n )}\n </div>\n );\n}\n"],"mappings":";AAAA,SAAS,YAAY;AACrB,SAA4B,WAAW;AAEvC,SAAS,kBAAkB;;;ACH3B,SAA0B,YAAY;AACtC,SAAS,eAAe;AAGjB,SAAS,MAAM,QAA8B;AAClD,SAAO,QAAQ,KAAK,MAAM,CAAC;AAC7B;;;ADiDM;AAjDC,IAAM,iBAAiB;AAAA,EAC5B;AAAA,EACA;AAAA,IACE,UAAU;AAAA,MACR,SAAS;AAAA,QACP,SAAS;AAAA,QACT,SAAS;AAAA,QACT,OAAO;AAAA,QACP,aAAa;AAAA,QACb,WAAW;AAAA,QACX,MAAM;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,QAMN,iBACE;AAAA,QACF,mBACE;AAAA,MACJ;AAAA,MACA,MAAM;AAAA,QACJ,SAAS;AAAA,QACT,IAAI;AAAA,QACJ,IAAI;AAAA,QACJ,IAAI;AAAA,QACJ,MAAM;AAAA,QACN,WAAW;AAAA,QACX,WAAW;AAAA,QACX,WAAW;AAAA,MACb;AAAA,IACF;AAAA,IACA,iBAAiB;AAAA,MACf,SAAS;AAAA,MACT,MAAM;AAAA,IACR;AAAA,EACF;AACF;AAQO,IAAM,SAAS;AAAA,EACpB,CAAC,EAAE,WAAW,SAAS,MAAM,UAAU,OAAO,GAAG,MAAM,GAAG,QAAQ;AAChE,UAAM,OAAO,UAAU,OAAO;AAC9B,WACE,oBAAC,QAAK,WAAW,GAAG,eAAe,EAAE,SAAS,MAAM,UAAU,CAAC,CAAC,GAAG,KAAW,GAAG,OAAO;AAAA,EAE5F;AACF;AACA,OAAO,cAAc;;;AE1DrB,SAAS,cAAAA,mBAAkB;AAOvB,gBAAAC,YAAA;AAFG,IAAM,QAAQC,YAAyC,CAAC,EAAE,WAAW,MAAM,GAAG,MAAM,GAAG,QAAQ;AACpG,SACE,gBAAAD;AAAA,IAAC;AAAA;AAAA,MACC;AAAA,MACA,WAAW;AAAA,QACT;AAAA,QACA;AAAA,MACF;AAAA,MACA;AAAA,MACC,GAAG;AAAA;AAAA,EACN;AAEJ,CAAC;AACD,MAAM,cAAc;;;AClBpB,SAAS,cAAAE,mBAAkB;AAKvB,gBAAAC,YAAA;AAFG,IAAM,QAAQC;AAAA,EACnB,CAAC,EAAE,WAAW,GAAG,MAAM,GAAG,QACxB,gBAAAD;AAAA,IAAC;AAAA;AAAA,MACC;AAAA,MACA,WAAW;AAAA,QACT;AAAA,QACA;AAAA,MACF;AAAA,MACC,GAAG;AAAA;AAAA,EACN;AAEJ;AACA,MAAM,cAAc;;;ACfpB,SAAS,cAAAE,mBAAkB;AAOvB,gBAAAC,YAAA;AAFG,IAAM,WAAWC;AAAA,EACtB,CAAC,EAAE,WAAW,GAAG,MAAM,GAAG,QACxB,gBAAAD;AAAA,IAAC;AAAA;AAAA,MACC,WAAW;AAAA,QACT;AAAA,QACA;AAAA,MACF;AAAA,MACA;AAAA,MACC,GAAG;AAAA;AAAA,EACN;AAEJ;AACA,SAAS,cAAc;;;ACTrB,gBAAAE,YAAA;AADK,IAAM,OAAO,CAAC,EAAE,WAAW,GAAG,MAAM,MACzC,gBAAAA,KAAC,SAAI,WAAW,GAAG,6DAA6D,SAAS,GAAI,GAAG,OAAO;AAGlG,IAAM,aAAa,CAAC;AAAA,EACzB;AAAA,EACA,GAAG;AACL,MACE,gBAAAA,KAAC,SAAI,WAAW,GAAG,6BAA6B,SAAS,GAAI,GAAG,OAAO;AAGlE,IAAM,YAAY,CAAC,EAAE,WAAW,GAAG,MAAM,MAC9C,gBAAAA,KAAC,SAAI,WAAW,GAAG,qDAAqD,SAAS,GAAI,GAAG,OAAO;AAG1F,IAAM,kBAAkB,CAAC;AAAA,EAC9B;AAAA,EACA,GAAG;AACL,MACE,gBAAAA,KAAC,SAAI,WAAW,GAAG,iCAAiC,SAAS,GAAI,GAAG,OAAO;AAGtE,IAAM,cAAc,CAAC;AAAA,EAC1B;AAAA,EACA,GAAG;AACL,MAAoD,gBAAAA,KAAC,SAAI,WAAW,GAAG,YAAY,SAAS,GAAI,GAAG,OAAO;AAEnG,IAAM,aAAa,CAAC;AAAA,EACzB;AAAA,EACA,GAAG;AACL,MACE,gBAAAA,KAAC,SAAI,WAAW,GAAG,oCAAoC,SAAS,GAAI,GAAG,OAAO;;;ACvChF,SAA4B,OAAAC,YAAW;AA2BrC,gBAAAC,YAAA;AAvBK,IAAM,gBAAgBC;AAAA,EAC3B;AAAA,EACA;AAAA,IACE,UAAU;AAAA,MACR,SAAS;AAAA,QACP,SAAS;AAAA,QACT,WAAW;AAAA,QACX,aAAa;AAAA,QACb,SAAS;AAAA;AAAA;AAAA,QAGT,SAAS;AAAA,MACX;AAAA,IACF;AAAA,IACA,iBAAiB;AAAA,MACf,SAAS;AAAA,IACX;AAAA,EACF;AACF;AAIO,IAAM,QAAQ,CAAC,EAAE,WAAW,SAAS,GAAG,MAAM,MACnD,gBAAAD,KAAC,SAAI,WAAW,GAAG,cAAc,EAAE,QAAQ,CAAC,GAAG,SAAS,GAAI,GAAG,OAAO;;;AC3BxE,YAAY,qBAAqB;AACjC,SAAS,SAAS;AAElB,SAAS,cAAAE,mBAAkB;AAUzB,gBAAAC,MA4BM,YA5BN;AAPK,IAAM,SAAyB;AAC/B,IAAM,gBAAgC;AAEtC,IAAM,gBAAgBC,YAG3B,CAAC,EAAE,WAAW,GAAG,MAAM,GAAG,QAC1B,gBAAAD;AAAA,EAAiB;AAAA,EAAhB;AAAA,IACC;AAAA,IACA,WAAW,GAAG,kCAAkC,SAAS;AAAA,IACxD,GAAG;AAAA;AACN,CACD;AACD,cAAc,cAAc;AAErB,IAAM,gBAAgBC,YAO3B,CAAC,EAAE,WAAW,UAAU,kBAAkB,MAAM,mBAAmB,GAAG,MAAM,GAAG,QAC/E,qBAAiB,wBAAhB,EACC;AAAA,kBAAAD,KAAC,iBAAc;AAAA,EACf;AAAA,IAAiB;AAAA,IAAhB;AAAA,MACC;AAAA,MACA,WAAW;AAAA,QACT;AAAA,QACA;AAAA,MACF;AAAA,MACC,GAAG;AAAA,MAEH;AAAA;AAAA,QACA,kBACC;AAAA,UAAiB;AAAA,UAAhB;AAAA,YACC,eAAa;AAAA,YACb,WAAU;AAAA,YAEV;AAAA,8BAAAA,KAAC,KAAE,WAAU,WAAU;AAAA,cACvB,gBAAAA,KAAC,UAAK,WAAU,WAAU,mBAAK;AAAA;AAAA;AAAA,QACjC,IACE;AAAA;AAAA;AAAA,EACN;AAAA,GACF,CACD;AACD,cAAc,cAAc;AAErB,IAAM,eAAe,CAAC;AAAA,EAC3B;AAAA,EACA,GAAG;AACL,MACE,gBAAAA,KAAC,SAAI,WAAW,GAAG,yBAAyB,SAAS,GAAI,GAAG,OAAO;AAG9D,IAAM,cAAcC,YAGzB,CAAC,EAAE,WAAW,GAAG,MAAM,GAAG,QAC1B,gBAAAD,KAAiB,uBAAhB,EAAsB,KAAU,WAAW,GAAG,yBAAyB,SAAS,GAAI,GAAG,OAAO,CAChG;AACD,YAAY,cAAc;AAEnB,IAAM,oBAAoBC,YAG/B,CAAC,EAAE,WAAW,GAAG,MAAM,GAAG,QAC1B,gBAAAD;AAAA,EAAiB;AAAA,EAAhB;AAAA,IACC;AAAA,IACA,WAAW,GAAG,iCAAiC,SAAS;AAAA,IACvD,GAAG;AAAA;AACN,CACD;AACD,kBAAkB,cAAc;AAEzB,IAAM,eAAe,CAAC;AAAA,EAC3B;AAAA,EACA,GAAG;AACL,MACE,gBAAAA,KAAC,SAAI,WAAW,GAAG,+BAA+B,SAAS,GAAI,GAAG,OAAO;;;ACrF3E,YAAY,sBAAsB;AAElC,SAAS,cAAAE,mBAAkB;AAoBvB,gBAAAC,YAAA;AAjBG,IAAM,UAA2B;AACjC,IAAM,iBAAkC;AACxC,IAAM,gBAAiC;AAEvC,IAAM,iBAAiBC,YAW5B,CAAC,EAAE,WAAW,QAAQ,SAAS,aAAa,GAAG,WAAW,GAAG,MAAM,GAAG,QACtE,gBAAAD,KAAkB,yBAAjB,EAAwB,WACvB,0BAAAA;AAAA,EAAkB;AAAA,EAAjB;AAAA,IACC;AAAA,IACA;AAAA,IACA;AAAA,IACA,WAAW;AAAA,MACT;AAAA,MACA;AAAA,IACF;AAAA,IACC,GAAG;AAAA;AACN,GACF,CACD;AACD,eAAe,cAAc;;;AClC7B,YAAY,qBAAqB;AACjC,SAAS,OAAO,mBAAmB;AAEnC,SAAS,cAAAE,mBAAkB;AAavB,SAWI,OAAAC,MAXJ,QAAAC,aAAA;AAVG,IAAM,SAAyB;AAC/B,IAAM,cAA8B;AACpC,IAAM,cAA8B;AAMpC,IAAM,gBAAgBC;AAAA,EAC3B,CAAC,EAAE,WAAW,UAAU,OAAO,WAAW,GAAG,MAAM,GAAG,QACpD,gBAAAD;AAAA,IAAiB;AAAA,IAAhB;AAAA,MACC;AAAA,MACA,WAAW;AAAA,QACT;AAAA,QACA,SAAS,OAAO,QAAQ;AAAA,QACxB;AAAA,MACF;AAAA,MACC,GAAG;AAAA,MAEH;AAAA;AAAA,QACD,gBAAAD,KAAiB,sBAAhB,EAAqB,SAAO,MAC3B,0BAAAA,KAAC,eAAY,WAAU,sBAAqB,GAC9C;AAAA;AAAA;AAAA,EACF;AAEJ;AACA,cAAc,cAAc;AAErB,IAAM,gBAAgBE,YAG3B,CAAC,EAAE,WAAW,UAAU,WAAW,UAAU,GAAG,MAAM,GAAG,QACzD,gBAAAF,KAAiB,wBAAhB,EACC,0BAAAA;AAAA,EAAiB;AAAA,EAAhB;AAAA,IACC;AAAA,IACA;AAAA,IACA,WAAW;AAAA,MACT;AAAA,MACA,aAAa,YAAY;AAAA,MACzB;AAAA,IACF;AAAA,IACC,GAAG;AAAA,IAEJ,0BAAAA,KAAiB,0BAAhB,EAAyB,WAAU,OAAO,UAAS;AAAA;AACtD,GACF,CACD;AACD,cAAc,cAAc;AAErB,IAAM,aAAaE,YAGxB,CAAC,EAAE,WAAW,UAAU,GAAG,MAAM,GAAG,QACpC,gBAAAD;AAAA,EAAiB;AAAA,EAAhB;AAAA,IACC;AAAA,IACA,WAAW;AAAA,MACT;AAAA,MACA;AAAA,IACF;AAAA,IACC,GAAG;AAAA,IAEJ;AAAA,sBAAAD,KAAC,UAAK,WAAU,gEACd,0BAAAA,KAAiB,+BAAhB,EACC,0BAAAA,KAAC,SAAM,WAAU,WAAU,GAC7B,GACF;AAAA,MACA,gBAAAA,KAAiB,0BAAhB,EAA0B,UAAS;AAAA;AAAA;AACtC,CACD;AACD,WAAW,cAAc;;;ACvEvB,gBAAAG,aAAA;AADK,IAAM,WAAW,CAAC,EAAE,WAAW,GAAG,MAAM,MAC7C,gBAAAA,MAAC,SAAI,WAAW,GAAG,qCAAqC,SAAS,GAAI,GAAG,OAAO;;;ACJjF,YAAY,uBAAuB;AACnC,SAAS,SAAAC,cAAa;AAEtB,SAAS,cAAAC,mBAAkB;AAgBrB,gBAAAC,aAAA;AAbC,IAAM,WAAWC,YAGtB,CAAC,EAAE,WAAW,GAAG,MAAM,GAAG,QAC1B,gBAAAD;AAAA,EAAmB;AAAA,EAAlB;AAAA,IACC;AAAA,IACA,WAAW;AAAA,MACT;AAAA,MACA;AAAA,IACF;AAAA,IACC,GAAG;AAAA,IAEJ,0BAAAA,MAAmB,6BAAlB,EAA4B,WAAU,iDACrC,0BAAAA,MAACE,QAAA,EAAM,WAAU,eAAc,GACjC;AAAA;AACF,CACD;AACD,SAAS,cAAc;;;ACvBvB,YAAY,qBAAqB;AAEjC,SAAS,cAAAC,mBAAkB;AAkBrB,gBAAAC,aAAA;AAXC,IAAM,SAASC;AAAA,EACpB,CAAC,EAAE,WAAW,OAAO,WAAW,GAAG,MAAM,GAAG,QAC1C,gBAAAD;AAAA,IAAiB;AAAA,IAAhB;AAAA,MACC;AAAA,MACA,WAAW;AAAA,QACT;AAAA,QACA,SAAS,OAAO,cAAc;AAAA,QAC9B;AAAA,MACF;AAAA,MACC,GAAG;AAAA,MAEJ,0BAAAA;AAAA,QAAiB;AAAA,QAAhB;AAAA,UACC,WAAW;AAAA,YACT;AAAA,YACA,SAAS,OACL,iDACA;AAAA,UACN;AAAA;AAAA,MACF;AAAA;AAAA,EACF;AAEJ;AACA,OAAO,cAAc;;;AC/BrB,YAAY,mBAAmB;AAE/B,SAAS,cAAAE,oBAAkB;AASzB,gBAAAC,aAAA;AANK,IAAM,OAAqB;AAE3B,IAAM,WAAWC,aAGtB,CAAC,EAAE,WAAW,GAAG,MAAM,GAAG,QAC1B,gBAAAD;AAAA,EAAe;AAAA,EAAd;AAAA,IACC;AAAA,IACA,WAAW;AAAA,MACT;AAAA,MACA;AAAA,IACF;AAAA,IACC,GAAG;AAAA;AACN,CACD;AACD,SAAS,cAAc;AAEhB,IAAM,cAAcC,aAGzB,CAAC,EAAE,WAAW,GAAG,MAAM,GAAG,QAC1B,gBAAAD;AAAA,EAAe;AAAA,EAAd;AAAA,IACC;AAAA,IACA,WAAW;AAAA,MACT;AAAA,MACA;AAAA,IACF;AAAA,IACC,GAAG;AAAA;AACN,CACD;AACD,YAAY,cAAc;AAEnB,IAAM,cAAcC,aAGzB,CAAC,EAAE,WAAW,GAAG,MAAM,GAAG,QAC1B,gBAAAD,MAAe,uBAAd,EAAsB,KAAU,WAAW,GAAG,uBAAuB,SAAS,GAAI,GAAG,OAAO,CAC9F;AACD,YAAY,cAAc;;;AC3C1B,YAAY,wBAAwB;AAEpC,SAAS,cAAAE,oBAAkB;AAOzB,gBAAAC,aAAA;AAJK,IAAM,YAAYC,aAGvB,CAAC,EAAE,WAAW,cAAc,cAAc,aAAa,MAAM,GAAG,MAAM,GAAG,QACzE,gBAAAD;AAAA,EAAoB;AAAA,EAAnB;AAAA,IACC;AAAA,IACA;AAAA,IACA;AAAA,IACA,WAAW;AAAA,MACT;AAAA,MACA,gBAAgB,eAAe,gBAAgB;AAAA,MAC/C;AAAA,IACF;AAAA,IACC,GAAG;AAAA;AACN,CACD;AACD,UAAU,cAAc;;;ACrBxB,YAAY,yBAAyB;AAErC,SAAS,cAAAE,oBAAkB;AAkBvB,gBAAAC,OASF,QAAAC,aATE;AAfG,IAAM,YAAYC,aAGvB,CAAC,EAAE,WAAW,cAAc,YAAY,GAAG,MAAM,GAAG,QACpD,gBAAAF;AAAA,EAAqB;AAAA,EAApB;AAAA,IACC;AAAA,IACA;AAAA,IACA,WAAW;AAAA,MACT;AAAA,MACA,gBAAgB,cAAc;AAAA,MAC9B,gBAAgB,gBAAgB;AAAA,MAChC;AAAA,IACF;AAAA,IACC,GAAG;AAAA,IAEJ,0BAAAA,MAAqB,qCAApB,EAAoC,WAAU,0CAAyC;AAAA;AAC1F,CACD;AACD,UAAU,cAAc;AAEjB,IAAM,aAAaE,aAGxB,CAAC,EAAE,WAAW,UAAU,GAAG,MAAM,GAAG,QACpC,gBAAAD,MAAqB,0BAApB,EAAyB,KAAU,WAAW,GAAG,4BAA4B,SAAS,GAAI,GAAG,OAC5F;AAAA,kBAAAD,MAAqB,8BAApB,EAA6B,WAAU,mCACrC,UACH;AAAA,EACA,gBAAAA,MAAC,aAAU;AAAA,EACX,gBAAAA,MAAqB,4BAApB,EAA2B;AAAA,GAC9B,CACD;AACD,WAAW,cAAc;;;ACpCzB,SAAS,cAAAG,oBAAkB;AAMrB,gBAAAC,aAAA;AAHC,IAAM,QAAQC;AAAA,EACnB,CAAC,EAAE,WAAW,GAAG,MAAM,GAAG,QACxB,gBAAAD,MAAC,SAAI,WAAU,mCACb,0BAAAA,MAAC,WAAM,KAAU,WAAW,GAAG,iCAAiC,SAAS,GAAI,GAAG,OAAO,GACzF;AAEJ;AACA,MAAM,cAAc;AAEb,IAAM,cAAcC;AAAA,EACzB,CAAC,EAAE,WAAW,GAAG,MAAM,GAAG,QACxB,gBAAAD,MAAC,WAAM,KAAU,WAAW,GAAG,mBAAmB,SAAS,GAAI,GAAG,OAAO;AAE7E;AACA,YAAY,cAAc;AAEnB,IAAM,YAAYC;AAAA,EACvB,CAAC,EAAE,WAAW,GAAG,MAAM,GAAG,QACxB,gBAAAD,MAAC,WAAM,KAAU,WAAW,GAAG,8BAA8B,SAAS,GAAI,GAAG,OAAO;AAExF;AACA,UAAU,cAAc;AAEjB,IAAM,cAAcC;AAAA,EACzB,CAAC,EAAE,WAAW,GAAG,MAAM,GAAG,QACxB,gBAAAD;AAAA,IAAC;AAAA;AAAA,MACC;AAAA,MACA,WAAW,GAAG,2DAA2D,SAAS;AAAA,MACjF,GAAG;AAAA;AAAA,EACN;AAEJ;AACA,YAAY,cAAc;AAEnB,IAAM,WAAWC;AAAA,EACtB,CAAC,EAAE,WAAW,GAAG,MAAM,GAAG,QACxB,gBAAAD;AAAA,IAAC;AAAA;AAAA,MACC;AAAA,MACA,WAAW,GAAG,+EAA+E,SAAS;AAAA,MACrG,GAAG;AAAA;AAAA,EACN;AAEJ;AACA,SAAS,cAAc;AAEhB,IAAM,YAAYC;AAAA,EACvB,CAAC,EAAE,WAAW,GAAG,MAAM,GAAG,QACxB,gBAAAD;AAAA,IAAC;AAAA;AAAA,MACC;AAAA,MACA,WAAW;AAAA,QACT;AAAA,QACA;AAAA,MACF;AAAA,MACC,GAAG;AAAA;AAAA,EACN;AAEJ;AACA,UAAU,cAAc;AAEjB,IAAM,YAAYC;AAAA,EACvB,CAAC,EAAE,WAAW,GAAG,MAAM,GAAG,QACxB,gBAAAD;AAAA,IAAC;AAAA;AAAA,MACC;AAAA,MACA,WAAW,GAAG,oEAAoE,SAAS;AAAA,MAC1F,GAAG;AAAA;AAAA,EACN;AAEJ;AACA,UAAU,cAAc;AAEjB,IAAM,eAAeC;AAAA,EAC1B,CAAC,EAAE,WAAW,GAAG,MAAM,GAAG,QACxB,gBAAAD,MAAC,aAAQ,KAAU,WAAW,GAAG,sCAAsC,SAAS,GAAI,GAAG,OAAO;AAElG;AACA,aAAa,cAAc;;;AC/E3B,YAAY,2BAA2B;AACvC,SAAS,SAAAE,QAAO,cAAc,cAAc;AAE5C,SAAS,cAAAC,oBAAkB;AAevB,gBAAAC,OAiCF,QAAAC,aAjCE;AAZG,IAAM,eAAqC;AAC3C,IAAM,sBAA4C;AAClD,IAAM,oBAA0C;AAChD,IAAM,qBAA2C;AACjD,IAAM,kBAAwC;AAC9C,IAAM,yBAA+C;AAErD,IAAM,sBAAsBC,aAGjC,CAAC,EAAE,WAAW,aAAa,GAAG,GAAG,MAAM,GAAG,QAC1C,gBAAAF,MAAuB,8BAAtB,EACC,0BAAAA;AAAA,EAAuB;AAAA,EAAtB;AAAA,IACC;AAAA,IACA;AAAA,IACA,WAAW;AAAA,MACT;AAAA,MACA;AAAA,IACF;AAAA,IACC,GAAG;AAAA;AACN,GACF,CACD;AACD,oBAAoB,cAAc;AAE3B,IAAM,mBAAmBE,aAG9B,CAAC,EAAE,WAAW,QAAQ,GAAG,MAAM,GAAG,QAClC,gBAAAF;AAAA,EAAuB;AAAA,EAAtB;AAAA,IACC;AAAA,IACA,WAAW;AAAA,MACT;AAAA,MACA,UAAU;AAAA,MACV;AAAA,IACF;AAAA,IACC,GAAG;AAAA;AACN,CACD;AACD,iBAAiB,cAAc;AAExB,IAAM,2BAA2BE,aAGtC,CAAC,EAAE,WAAW,UAAU,SAAS,GAAG,MAAM,GAAG,QAC7C,gBAAAD;AAAA,EAAuB;AAAA,EAAtB;AAAA,IACC;AAAA,IACA;AAAA,IACA,WAAW;AAAA,MACT;AAAA,MACA;AAAA,IACF;AAAA,IACC,GAAG;AAAA,IAEJ;AAAA,sBAAAD,MAAC,UAAK,WAAU,gEACd,0BAAAA,MAAuB,qCAAtB,EACC,0BAAAA,MAACG,QAAA,EAAM,WAAU,WAAU,GAC7B,GACF;AAAA,MACC;AAAA;AAAA;AACH,CACD;AACD,yBAAyB,cAAc;AAEhC,IAAM,wBAAwBD,aAGnC,CAAC,EAAE,WAAW,UAAU,GAAG,MAAM,GAAG,QACpC,gBAAAD;AAAA,EAAuB;AAAA,EAAtB;AAAA,IACC;AAAA,IACA,WAAW;AAAA,MACT;AAAA,MACA;AAAA,IACF;AAAA,IACC,GAAG;AAAA,IAEJ;AAAA,sBAAAD,MAAC,UAAK,WAAU,gEACd,0BAAAA,MAAuB,qCAAtB,EACC,0BAAAA,MAAC,UAAO,WAAU,wBAAuB,GAC3C,GACF;AAAA,MACC;AAAA;AAAA;AACH,CACD;AACD,sBAAsB,cAAc;AAE7B,IAAM,wBAAwBE,aAGnC,CAAC,EAAE,WAAW,GAAG,MAAM,GAAG,QAC1B,gBAAAF;AAAA,EAAuB;AAAA,EAAtB;AAAA,IACC;AAAA,IACA,WAAW,GAAG,4BAA4B,SAAS;AAAA,IAClD,GAAG;AAAA;AACN,CACD;AACD,sBAAsB,cAAc;AAE7B,IAAM,oBAAoBE,aAG/B,CAAC,EAAE,WAAW,GAAG,MAAM,GAAG,QAC1B,gBAAAF;AAAA,EAAuB;AAAA,EAAtB;AAAA,IACC;AAAA,IACA,WAAW,GAAG,yDAAyD,SAAS;AAAA,IAC/E,GAAG;AAAA;AACN,CACD;AACD,kBAAkB,cAAc;AAEzB,IAAM,uBAAuB,CAAC;AAAA,EACnC;AAAA,EACA,GAAG;AACL,MACE,gBAAAA,MAAC,UAAK,WAAW,GAAG,yDAAyD,SAAS,GAAI,GAAG,OAAO;AAG/F,IAAM,yBAAyBE,aAGpC,CAAC,EAAE,WAAW,UAAU,GAAG,MAAM,GAAG,QACpC,gBAAAD;AAAA,EAAuB;AAAA,EAAtB;AAAA,IACC;AAAA,IACA,WAAW;AAAA,MACT;AAAA,MACA;AAAA,IACF;AAAA,IACC,GAAG;AAAA,IAEH;AAAA;AAAA,MACD,gBAAAD,MAAC,gBAAa,WAAU,mBAAkB;AAAA;AAAA;AAC5C,CACD;AACD,uBAAuB,cAAc;AAE9B,IAAM,yBAAyBE,aAGpC,CAAC,EAAE,WAAW,GAAG,MAAM,GAAG,QAC1B,gBAAAF;AAAA,EAAuB;AAAA,EAAtB;AAAA,IACC;AAAA,IACA,WAAW;AAAA,MACT;AAAA,MACA;AAAA,IACF;AAAA,IACC,GAAG;AAAA;AACN,CACD;AACD,uBAAuB,cAAc;;;AC1JrC,SAA4B,OAAAI,YAAW;AACvC,YAAYC,sBAAqB;AACjC,SAAS,KAAAC,UAAS;AASlB,SAAS,cAAAC,cAAY,WAAW,QAAQ,gBAAgB;AAYtD,gBAAAC,OAwIQ,QAAAC,aAxIR;AATK,IAAM,QAAwB;AAC9B,IAAM,eAA+B;AACrC,IAAM,aAA6B;AACnC,IAAM,cAA8B;AAEpC,IAAM,eAAeC,aAG1B,CAAC,EAAE,WAAW,GAAG,MAAM,GAAG,QAC1B,gBAAAF;AAAA,EAAiB;AAAA,EAAhB;AAAA,IACC;AAAA,IACA,WAAW,GAAG,kCAAkC,SAAS;AAAA,IACxD,GAAG;AAAA;AACN,CACD;AACD,aAAa,cAAc;AAUpB,IAAM,gBAAgBG;AAAA,EAC3B;AAAA,EACA;AAAA,IACE,UAAU;AAAA,MACR,MAAM;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,QAMJ,KAAK;AAAA,QACL,QACE;AAAA,QACF,MAAM;AAAA,QACN,OACE;AAAA,MACJ;AAAA,IACF;AAAA,IACA,iBAAiB;AAAA,MACf,MAAM;AAAA,IACR;AAAA,EACF;AACF;AAgBA,IAAM,qBAA0E;AAAA,EAC9E,KAAK;AAAA,EACL,QAAQ;AAAA,EACR,MAAM;AAAA,EACN,OAAO;AACT;AAEO,IAAM,eAAeD;AAAA,EAC1B,CAAC,EAAE,OAAO,SAAS,WAAW,UAAU,YAAY,OAAO,OAAO,WAAW,GAAG,MAAM,GAAG,QAAQ;AAQ/F,UAAM,CAAC,SAAS,UAAU,IAAI,SAAS,KAAK;AAC5C,cAAU,MAAM;AACd,YAAM,KAAK,sBAAsB,MAAM,WAAW,IAAI,CAAC;AACvD,aAAO,MAAM,qBAAqB,EAAE;AAAA,IACtC,GAAG,CAAC,CAAC;AAKL,UAAM,CAAC,YAAY,aAAa,IAAI,SAAwB,IAAI;AAChE,UAAM,CAAC,YAAY,aAAa,IAAI,SAAS,KAAK;AAClD,UAAM,YAAY,OAA6C,IAAI;AACnE,UAAM,YAAY,aAAa,SAAS;AAExC,UAAM,sBAAsB,CAAC,MAA+C;AAC1E,YAAM,QAAQ,EAAE,cAAc,QAAQ,6BAA6B;AACnE,UAAI,EAAE,iBAAiB,aAAc;AACrC,QAAE,cAAc,kBAAkB,EAAE,SAAS;AAC7C,gBAAU,UAAU,EAAE,GAAG,EAAE,SAAS,QAAQ,MAAM,sBAAsB,EAAE,OAAO;AACjF,oBAAc,IAAI;AAAA,IACpB;AACA,UAAM,sBAAsB,CAAC,MAA+C;AAC1E,UAAI,CAAC,UAAU,QAAS;AACxB,YAAM,QAAQ,UAAU,QAAQ,IAAI,EAAE;AACtC,YAAM,OAAO,UAAU,QAAQ,SAAS;AACxC,YAAM,MAAM,OAAO,cAAc;AACjC,YAAM,MAAM,OAAO,cAAc;AACjC,oBAAc,KAAK,IAAI,KAAK,KAAK,IAAI,KAAK,IAAI,CAAC,CAAC;AAAA,IAClD;AACA,UAAM,oBAAoB,MAAY;AACpC,gBAAU,UAAU;AACpB,oBAAc,KAAK;AAAA,IACrB;AAEA,UAAM,QAAmC,UACrC,EAAE,GAAG,WAAW,GAAI,aAAa,cAAc,OAAO,EAAE,QAAQ,YAAY,WAAW,WAAW,IAAI,KAAM,IAC5G,EAAE,GAAG,WAAW,WAAW,mBAAmB,QAAQ,OAAO,EAAE;AAEnE,WACE,gBAAAD,MAAC,eACC;AAAA,sBAAAD,MAAC,gBAAa;AAAA,MACd,gBAAAC;AAAA,QAAiB;AAAA,QAAhB;AAAA,UACC;AAAA,UACA,aAAU;AAAA,UACV;AAAA,UACA,WAAW,GAAG,cAAc,EAAE,KAAK,CAAC,GAAG,cAAc,cAAc,SAAS;AAAA,UAC3E,GAAG;AAAA,UAEH;AAAA,yBACC,gBAAAD;AAAA,cAAC;AAAA;AAAA,gBACC,eAAY;AAAA,gBACZ,WAAU;AAAA,gBACV,eAAe;AAAA,gBACf,eAAe;AAAA,gBACf,aAAa;AAAA,gBACb,iBAAiB;AAAA,gBAEjB,0BAAAA;AAAA,kBAAC;AAAA;AAAA,oBACC,WAAW;AAAA,sBACT;AAAA,sBACA,cAAc;AAAA,oBAChB;AAAA;AAAA,gBACF;AAAA;AAAA,YACF;AAAA,YAED;AAAA,YACD,gBAAAC,MAAiB,wBAAhB,EAAsB,WAAU,kEAC/B;AAAA,8BAAAD,MAACI,IAAA,EAAE,WAAU,WAAU;AAAA,cACvB,gBAAAJ,MAAC,UAAK,WAAU,WAAU,mBAAK;AAAA,eACjC;AAAA;AAAA;AAAA,MACF;AAAA,OACF;AAAA,EAEJ;AACF;AACA,aAAa,cAAc;AAEpB,IAAM,cAAc,CAAC;AAAA,EAC1B;AAAA,EACA,GAAG;AACL,MACE,gBAAAA,MAAC,SAAI,WAAW,GAAG,yBAAyB,SAAS,GAAI,GAAG,OAAO;AAG9D,IAAM,cAAc,CAAC;AAAA,EAC1B;AAAA,EACA,GAAG;AACL,MACE,gBAAAA,MAAC,SAAI,WAAW,GAAG,0BAA0B,SAAS,GAAI,GAAG,OAAO;AAG/D,IAAM,aAAaE,aAGxB,CAAC,EAAE,WAAW,GAAG,MAAM,GAAG,QAC1B,gBAAAF,MAAiB,wBAAhB,EAAsB,KAAU,WAAW,GAAG,yBAAyB,SAAS,GAAI,GAAG,OAAO,CAChG;AACD,WAAW,cAAc;AAElB,IAAM,mBAAmBE,aAG9B,CAAC,EAAE,WAAW,GAAG,MAAM,GAAG,QAC1B,gBAAAF;AAAA,EAAiB;AAAA,EAAhB;AAAA,IACC;AAAA,IACA,WAAW,GAAG,iCAAiC,SAAS;AAAA,IACvD,GAAG;AAAA;AACN,CACD;AACD,iBAAiB,cAAc;;;AC1M/B,YAAY,sBAAsB;AAElC,SAAS,cAAAK,oBAAkB;AAYvB,gBAAAC,aAAA;AATG,IAAM,kBAAmC;AACzC,IAAM,UAA2B;AACjC,IAAM,iBAAkC;AAExC,IAAM,iBAAiBC,aAG5B,CAAC,EAAE,WAAW,aAAa,GAAG,GAAG,MAAM,GAAG,QAC1C,gBAAAD,MAAkB,yBAAjB,EACC,0BAAAA;AAAA,EAAkB;AAAA,EAAjB;AAAA,IACC;AAAA,IACA;AAAA,IACA,WAAW;AAAA,MACT;AAAA,MACA;AAAA,IACF;AAAA,IACC,GAAG;AAAA;AACN,GACF,CACD;AACD,eAAe,cAAc;;;ACmBvB,SACE,OAAAE,OADF,QAAAC,aAAA;AAXC,IAAM,QAAQ,CAAC;AAAA,EACpB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,MACE,gBAAAD,MAAC,UAAO,MAAY,cAClB,0BAAAC,MAAC,iBAAc,WACb;AAAA,kBAAAA,MAAC,gBACC;AAAA,oBAAAD,MAAC,eAAa,iBAAM;AAAA,IACnB,cAAc,gBAAAA,MAAC,qBAAmB,uBAAY,IAAuB;AAAA,KACxE;AAAA,EACC;AAAA,EACA,SAAS,gBAAAA,MAAC,gBAAc,kBAAO,IAAkB;AAAA,GACpD,GACF;;;AClDF,SAAS,YAAAE,iBAAgB;;;ACAzB,SAAS,UAAU,YAAAC,iBAAgB;;;ACI5B,SAAS,oBAA6B;AAC3C,MAAI,OAAO,cAAc,YAAa,QAAO;AAC7C,SAAO,WAAW,KAAK,UAAU,SAAS;AAC5C;AAaO,SAAS,4BAAoD;AAClE,SAAO,kBAAkB,IAAI,YAAY;AAC3C;;;ADuBI,SAIA,YAAAC,WAJA,OAAAC,OAIA,QAAAC,aAJA;AARG,SAAS,cAAc,EAAE,SAAS,OAAO,GAAqC;AAGnF,QAAM,CAAC,SAAS,IAAIC,UAAS,yBAAyB;AACtD,QAAM,gBAAgB,cAAc;AACpC,QAAM,UAAU,gBAAgB,UAAU,CAAC,GAAG,OAAO,EAAE,QAAQ;AAE/D,QAAM,kBAAkB,QAAQ,IAAI,CAAC,QAAQ,UAC3C,gBAAAF,MAAC,YAAyC,oBAA3B,UAAU,QAAQ,KAAK,CAAW,CAClD;AAED,SAAO,gBACL,gBAAAC,MAAAF,WAAA,EACG;AAAA;AAAA,IACA;AAAA,KACH,IAEA,gBAAAE,MAAAF,WAAA,EACG;AAAA;AAAA,IACA;AAAA,KACH;AAEJ;AAEA,SAAS,UAAU,QAAmB,OAAoB;AACxD,MAAI,UAAU,OAAO,WAAW,YAAY,SAAS,UAAU,OAAO,QAAQ,KAAM,QAAO,OAAO;AAClG,SAAO;AACT;;;ADOI,gBAAAI,aAAA;AAnCG,IAAM,gBAAgB,CAAC;AAAA,EAC5B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,eAAe;AAAA,EACf,cAAc;AAAA,EACd;AAAA,EACA,UAAU;AAAA,EACV;AAAA,EACA;AACF,MAAwC;AACtC,QAAM,CAAC,SAAS,UAAU,IAAIC,UAAS,KAAK;AAE5C,QAAM,eAAe,MAAY;AAC/B,iBAAa,KAAK;AAAA,EACpB;AAEA,QAAM,gBAAgB,YAA2B;AAC/C,eAAW,IAAI;AACf,QAAI;AACF,YAAM,UAAU;AAChB,mBAAa,KAAK;AAAA,IACpB,SAAS,OAAO;AAKd,cAAQ,MAAM,KAAK;AAAA,IACrB,UAAE;AACA,iBAAW,KAAK;AAAA,IAClB;AAAA,EACF;AAEA,QAAM,eACJ,gBAAAD,MAAC,UAAO,SAAQ,WAAU,SAAS,cAAc,UAAU,SAAS,eAAa,cAC9E,uBACH;AAEF,QAAM,gBACJ,gBAAAA;AAAA,IAAC;AAAA;AAAA,MACC,SAAS,YAAY,gBAAgB,gBAAgB;AAAA,MACrD,SAAS;AAAA,MACT,UAAU;AAAA,MACV,eAAa;AAAA,MAEZ,oBAAU,GAAG,YAAY,WAAM;AAAA;AAAA,EAClC;AAGF,SACE,gBAAAA;AAAA,IAAC;AAAA;AAAA,MACC;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,QAAQ,gBAAAA,MAAC,iBAAc,SAAS,CAAC,aAAa,GAAG,QAAQ,cAAc;AAAA,MAEtE;AAAA;AAAA,EACH;AAEJ;;;AGjGA,SAAS,YAAAE,iBAAgB;AAmFf,SACE,OAAAC,OADF,QAAAC,aAAA;AAlCH,IAAM,YAAY,CAAC;AAAA,EACxB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,cAAc;AAAA,EACd,cAAc;AAAA,EACd,iBAAiB;AAAA,EACjB;AAAA,EACA;AAAA,EACA;AACF,MAAoC;AAClC,QAAM,CAAC,SAAS,UAAU,IAAIC,UAAS,KAAK;AAE5C,QAAM,eAAe,OAAO,UAAqD;AAC/E,UAAM,eAAe;AACrB,eAAW,IAAI;AACf,QAAI;AACF,YAAM,SAAS;AAAA,IACjB,UAAE;AACA,iBAAW,KAAK;AAAA,IAClB;AAAA,EACF;AAEA,QAAM,eAAe,MAAY;AAC/B,iBAAa,KAAK;AAAA,EACpB;AAEA,SACE,gBAAAF,MAAC,UAAO,MAAY,cAClB,0BAAAA,MAAC,iBAAc,WACb,0BAAAC,MAAC,UAAK,UAAU,cACd;AAAA,oBAAAA,MAAC,gBACC;AAAA,sBAAAD,MAAC,eAAa,iBAAM;AAAA,MACnB,cAAc,gBAAAA,MAAC,qBAAmB,uBAAY,IAAuB;AAAA,OACxE;AAAA,IACC;AAAA,IACD,gBAAAC,MAAC,gBACC;AAAA,sBAAAD;AAAA,QAAC;AAAA;AAAA,UACC,MAAK;AAAA,UACL,SAAQ;AAAA,UACR,SAAS;AAAA,UACT,UAAU;AAAA,UACV,eAAa;AAAA,UAEZ;AAAA;AAAA,MACH;AAAA,MACA,gBAAAA,MAAC,UAAO,MAAK,UAAS,UAAU,WAAW,gBAAgB,eAAa,cACrE,oBAAU,GAAG,WAAW,WAAM,aACjC;AAAA,OACF;AAAA,KACF,GACF,GACF;AAEJ;;;AC1GA,SAAS,UAAAG,SAAQ,YAAAC,iBAAgB;;;ACDjC,SAAS,aAAAC,YAAW,YAAAC,iBAAgB;AAM7B,SAAS,cAAc,OAAwB;AACpD,QAAM,CAAC,SAAS,UAAU,IAAIA;AAAA,IAAS,MACrC,OAAO,WAAW,cAAc,OAAO,WAAW,KAAK,EAAE,UAAU;AAAA,EACrE;AAEA,EAAAD,WAAU,MAAM;AACd,UAAM,KAAK,OAAO,WAAW,KAAK;AAClC,eAAW,GAAG,OAAO;AACrB,UAAM,UAAU,CAAC,MAAiC,WAAW,EAAE,OAAO;AACtE,OAAG,iBAAiB,UAAU,OAAO;AACrC,WAAO,MAAM,GAAG,oBAAoB,UAAU,OAAO;AAAA,EACvD,GAAG,CAAC,KAAK,CAAC;AAEV,SAAO;AACT;;;ADiRgB,gBAAAE,OAQN,QAAAC,aARM;AAhRhB,IAAM,qBAAqB;AAAA,EACzB,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,IAAI;AACN;AAEA,IAAM,oBAAoB;AAAA,EACxB,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,IAAI;AACN;AAIA,IAAM,kBAAkB;AACxB,IAAM,mBAAmB;AACzB,IAAM,kBAAkB;AAIxB,IAAM,eAAuC;AAAA,EAC3C,YAAY;AAAA,EACZ,gBAAgB;AAAA,EAChB,aAAa;AAAA,EACb,eAAe;AACjB;AAEA,IAAM,iBAAyC;AAAA,EAC7C,YAAY;AAAA,EACZ,aAAa;AAAA,EACb,eAAe;AAAA,EACf,gBAAgB;AAClB;AAEA,IAAM,qBAA6C;AAAA,EACjD,YAAY;AAAA,EACZ,aAAa;AAAA,EACb,eAAe;AAAA,EACf,gBAAgB;AAClB;AA+BA,SAAS,0BAOP;AACA,QAAM,CAAC,OAAO,QAAQ,IAAIC,UAAoC,MAAS;AACvE,QAAM,CAAC,YAAY,aAAa,IAAIA,UAAS,KAAK;AAClD,QAAM,OAAOC,QAAyB,IAAI;AAC1C,QAAM,WAAWA,QAAoB,IAAI;AAEzC,QAAM,YACJ,CAAC,MAAyB,WAC1B,CAAC,MAA+C;AAC9C,UAAM,UAAU,EAAE,cAAc,QAAQ,8BAA8B;AACtE,QAAI,EAAE,mBAAmB,aAAc;AACvC,MAAE,cAAc,kBAAkB,EAAE,SAAS;AAC7C,UAAM,UAAU,QAAQ,sBAAsB;AAC9C,UAAM,OAAO,SAAS,WAAW;AAAA,MAC/B,MAAM,QAAQ;AAAA,MACd,KAAK,QAAQ;AAAA,MACb,OAAO,QAAQ;AAAA,MACf,QAAQ,QAAQ;AAAA,IAClB;AACA,SAAK,UAAU,EAAE,MAAM,QAAQ,GAAG,EAAE,SAAS,GAAG,EAAE,SAAS,KAAK;AAChE,kBAAc,IAAI;AAAA,EACpB;AAEF,QAAM,gBAAgB,CAAC,MAA+C;AACpE,UAAM,QAAQ,KAAK;AACnB,QAAI,CAAC,MAAO;AACZ,UAAM,SAAS,EAAE,UAAU,MAAM;AACjC,UAAM,SAAS,EAAE,UAAU,MAAM;AAEjC,QAAI,MAAM,SAAS,QAAQ;AACzB,YAAM,UAAU,OAAO,aAAa,kBAAkB,MAAM,KAAK;AACjE,YAAM,SAAS,OAAO,cAAc,kBAAkB,MAAM,KAAK;AACjE,YAAMC,QAAa;AAAA,QACjB,MAAM,KAAK,IAAI,SAAS,KAAK,IAAI,iBAAiB,MAAM,KAAK,OAAO,MAAM,CAAC;AAAA,QAC3E,KAAK,KAAK,IAAI,QAAQ,KAAK,IAAI,iBAAiB,MAAM,KAAK,MAAM,MAAM,CAAC;AAAA,QACxE,OAAO,MAAM,KAAK;AAAA,QAClB,QAAQ,MAAM,KAAK;AAAA,MACrB;AACA,eAAS,UAAUA;AACnB,eAAS,EAAE,UAAU,SAAS,WAAW,QAAQ,WAAW,QAAQ,UAAU,QAAQ,WAAW,QAAQ,GAAGA,MAAK,CAAC;AAClH;AAAA,IACF;AAEA,UAAM,SAAS,MAAM,UAAU;AAC/B,UAAM,YAAY,WAAW,cAAc,WAAW;AACtD,UAAM,UAAU,WAAW,cAAc,WAAW;AACpD,UAAM,QAAQ,MAAM,KAAK,OAAO,MAAM,KAAK;AAC3C,UAAM,SAAS,MAAM,KAAK,MAAM,MAAM,KAAK;AAC3C,UAAM,WAAW,OAAO,aAAa,kBAAkB;AACvD,UAAM,YAAY,OAAO,cAAc,kBAAkB;AAEzD,QAAI,QAAQ,KAAK;AAAA,MACf;AAAA,MACA,KAAK,IAAI,UAAU,YAAY,MAAM,KAAK,QAAQ,SAAS,MAAM,KAAK,QAAQ,MAAM;AAAA,IACtF;AACA,QAAI,SAAS,KAAK;AAAA,MAChB;AAAA,MACA,KAAK,IAAI,WAAW,UAAU,MAAM,KAAK,SAAS,SAAS,MAAM,KAAK,SAAS,MAAM;AAAA,IACvF;AAIA,UAAM,OAAO,YAAY,QAAQ,KAAK,IAAI,OAAO,QAAQ,eAAe,IAAI,MAAM,KAAK;AACvF,YAAQ,YAAY,QAAQ,OAAO,KAAK,IAAI,OAAO,OAAO,aAAa,kBAAkB,MAAM,KAAK,IAAI;AAExG,UAAM,MAAM,UAAU,SAAS,KAAK,IAAI,QAAQ,SAAS,eAAe,IAAI,MAAM,KAAK;AACvF,aAAS,UAAU,SAAS,MAAM,KAAK,IAAI,QAAQ,OAAO,cAAc,kBAAkB,MAAM,KAAK,GAAG;AAExG,UAAM,OAAa,EAAE,MAAM,KAAK,OAAO,OAAO;AAC9C,aAAS,UAAU;AACnB,aAAS,EAAE,UAAU,SAAS,WAAW,QAAQ,WAAW,QAAQ,UAAU,QAAQ,WAAW,QAAQ,GAAG,KAAK,CAAC;AAAA,EACpH;AAEA,QAAM,cAAc,MAAY;AAC9B,SAAK,UAAU;AACf,kBAAc,KAAK;AAAA,EACrB;AAEA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,WAAW,UAAU,MAAM;AAAA,IAC3B,aAAa,CAAC,WAAW,UAAU,UAAU,MAAM;AAAA,IACnD;AAAA,IACA;AAAA,EACF;AACF;AA2DO,IAAM,kBAAkB,CAAC;AAAA,EAC9B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,aAAa;AAAA,EACb,OAAO;AAAA,EACP,YAAY;AAAA,EACZ,YAAY;AAAA,EACZ,sBAAsB;AACxB,MAA0C;AACxC,QAAM,YAAY,cAAc,UAAU;AAC1C,QAAM,WAAW,wBAAwB;AACzC,QAAM,oBAAoB,sBAAsB,SAAY,CAAC,MAAmB,EAAE,eAAe;AAEjG,MAAI,WAAW;AACb,UAAM,UAAoB,CAAC,YAAY,aAAa,eAAe,cAAc;AACjF,WACE,gBAAAJ,MAAC,UAAO,MAAY,cAClB,0BAAAC;AAAA,MAAC;AAAA;AAAA,QACC,aAAU;AAAA,QACV;AAAA,QACA,OAAO,aAAa,YAAY,SAAS,QAAQ;AAAA,QACjD,WAAW;AAAA,UACT;AAAA,UACA,SAAS,cAAc;AAAA,UACvB,mBAAmB,IAAI;AAAA,UACvB;AAAA,QACF;AAAA,QAEC;AAAA,uBACC,QAAQ,IAAI,CAAC,WACX,gBAAAD;AAAA,YAAC;AAAA;AAAA,cAEC,eAAa,uBAAuB,MAAM;AAAA,cAC1C,WAAW;AAAA,gBACT;AAAA,gBACA,eAAe,MAAM;AAAA,gBACrB,aAAa,MAAM;AAAA,cACrB;AAAA,cACA,eAAe,SAAS,YAAY,MAAM;AAAA,cAC1C,eAAe,SAAS;AAAA,cACxB,aAAa,SAAS;AAAA,cACtB,iBAAiB,SAAS;AAAA,cAE1B,0BAAAA;AAAA,gBAAC;AAAA;AAAA,kBACC,WAAW;AAAA,oBACT;AAAA,oBACA,mBAAmB,MAAM;AAAA,kBAC3B;AAAA;AAAA,cACF;AAAA;AAAA,YAjBK;AAAA,UAkBP,CACD;AAAA,UACH,gBAAAC;AAAA,YAAC;AAAA;AAAA,cACC,WAAW,GAAG,aAAa,oCAAoC;AAAA,cAC/D,eAAe,YAAY,SAAS,YAAY;AAAA,cAChD,eAAe,YAAY,SAAS,gBAAgB;AAAA,cACpD,aAAa,YAAY,SAAS,cAAc;AAAA,cAChD,iBAAiB,YAAY,SAAS,cAAc;AAAA,cAEpD;AAAA,gCAAAD,MAAC,eAAa,iBAAM;AAAA,gBACnB,cAAc,gBAAAA,MAAC,qBAAmB,uBAAY,IAAuB;AAAA;AAAA;AAAA,UACxE;AAAA,UACC;AAAA,UACA,SAAS,gBAAAA,MAAC,gBAAc,kBAAO,IAAkB;AAAA;AAAA;AAAA,IACpD,GACF;AAAA,EAEJ;AAEA,SACE,gBAAAA,MAAC,SAAM,MAAY,cACjB,0BAAAC;AAAA,IAAC;AAAA;AAAA,MACC,MAAK;AAAA,MACL;AAAA,MACA;AAAA,MACA,WAAW;AAAA,QACT;AAAA,QACA,kBAAkB,IAAI;AAAA,QACtB;AAAA,MACF;AAAA,MAEA;AAAA,wBAAAA,MAAC,eACC;AAAA,0BAAAD,MAAC,cAAY,iBAAM;AAAA,UAClB,cAAc,gBAAAA,MAAC,oBAAkB,uBAAY,IAAsB;AAAA,WACtE;AAAA,QACC;AAAA,QACA,SAAS,gBAAAA,MAAC,eAAa,kBAAO,IAAiB;AAAA;AAAA;AAAA,EAClD,GACF;AAEJ;;;AElVA,SAAS,YAAAK,iBAAgB;AA6Fb,gBAAAC,aAAA;AAzCL,IAAM,iBAAiB,CAAC;AAAA,EAC7B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,cAAc;AAAA,EACd;AACF,MAAyC;AACvC,QAAM,CAAC,cAAc,eAAe,IAAIC,UAAwB,IAAI;AACpE,QAAM,UAAU,iBAAiB;AAEjC,QAAM,eAAe,MAAY;AAC/B,iBAAa,KAAK;AAAA,EACpB;AAEA,QAAM,oBAAoB,OAAO,QAA8B,UAAiC;AAC9F,oBAAgB,KAAK;AACrB,QAAI;AACF,YAAM,OAAO,QAAQ;AACrB,mBAAa,KAAK;AAAA,IACpB,SAAS,OAAO;AAKd,cAAQ,MAAM,KAAK;AAAA,IACrB,UAAE;AACA,sBAAgB,IAAI;AAAA,IACtB;AAAA,EACF;AAEA,SACE,gBAAAD;AAAA,IAAC;AAAA;AAAA,MACC;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,QACE,gBAAAA;AAAA,QAAC;AAAA;AAAA,UACC,SAAS,QAAQ,IAAI,CAAC,QAAQ,UAC5B,gBAAAA;AAAA,YAAC;AAAA;AAAA,cAEC,SAAS,OAAO,WAAW;AAAA,cAC3B,SAAS,MAAM,kBAAkB,QAAQ,KAAK;AAAA,cAC9C,UAAU;AAAA,cACV,eAAa,OAAO;AAAA,cAEnB,2BAAiB,QAAQ,GAAG,OAAO,KAAK,WAAM,OAAO;AAAA;AAAA,YANjD,OAAO;AAAA,UAOd,CACD;AAAA,UACD,QACE,gBAAAA,MAAC,UAAO,SAAQ,WAAU,SAAS,cAAc,UAAU,SAAS,eAAa,cAC9E,uBACH;AAAA;AAAA,MAEJ;AAAA,MAGD;AAAA;AAAA,EACH;AAEJ;;;AClHA,SAAS,cAAc,gBAAgB,aAAa;AAuE1C,SAQF,OAAAE,OARE,QAAAC,cAAA;AAxCH,SAAS,UAAU;AAAA,EACxB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAAiC;AAC/B,QAAM,cAAc,MAAM;AAC1B,QAAM,aAAa,WAAW;AAC9B,QAAM,kBAAkB,eAAe,QAAQ;AAC/C,QAAM,kBAAkB,kBACnB,SAAS,MAA0B,KACpC;AACJ,QAAM,cAAc,mBAAmB;AAEvC,QAAM,UAAU,SAAS;AACzB,QAAM,YAAY,UAAU,GAAG,WAAW,aAAa;AAEvD,QAAM,QAAQ,kBACV;AAAA,IACE;AAAA,IAKA;AAAA,MACE,IAAI;AAAA,MACJ,GAAI,QAAQ,EAAE,gBAAgB,KAAK,IAAI,CAAC;AAAA,MACxC,GAAI,YAAY,EAAE,oBAAoB,UAAU,IAAI,CAAC;AAAA,IACvD;AAAA,EACF,IACA;AAEJ,SACE,gBAAAA,OAAC,SAAI,WAAW,GAAG,yBAAyB,SAAS,GACnD;AAAA,oBAAAA,OAAC,SAAM,SAAS,aACb;AAAA;AAAA,MACA,WACC,gBAAAA,OAAC,UAAK,WAAU,oBAAmB,eAAY,QAC5C;AAAA;AAAA,QAAI;AAAA,SAEP,IACE;AAAA,OACN;AAAA,IACC;AAAA,IACA,QACC,gBAAAD,MAAC,OAAE,IAAI,WAAW,WAAU,4BACzB,iBACH,IACE,cACF,gBAAAA,MAAC,OAAE,IAAI,WAAW,WAAU,iCACzB,uBACH,IACE;AAAA,KACN;AAEJ;;;AC1FA,SAAS,SAAAE,QAAO,gBAAgB,KAAAC,UAAS;AAEzC,SAAS,aAAAC,YAAW,SAAS,UAAAC,SAAQ,YAAAC,iBAAgB;;;ACQ9C,SAAS,aAAwC,SAAc,OAAyB;AAC7F,SAAO,QAAQ,OAAO,CAAC,MAAM,EAAE,UAAU,SAAS,CAAC,EAAE,QAAQ,EAAE,IAAI,CAAC,MAAM,EAAE,KAAK;AACnF;AAIO,SAAS,gBACd,SACA,gBACA,OACiB;AACjB,QAAM,UAAU,aAAa,SAAS,KAAK;AAC3C,QAAM,gBAAgB,QAAQ,OAAO,CAAC,MAAM,eAAe,SAAS,CAAC,CAAC,EAAE;AACxE,MAAI,kBAAkB,EAAG,QAAO;AAChC,SAAO,kBAAkB,QAAQ,SAAS,YAAY;AACxD;AA4BO,SAAS,kBAA6C,gBAAuC;AAClG,QAAM,SAA2B,CAAC;AAClC,iBAAe,QAAQ,CAAC,QAAQ,UAAU;AACxC,UAAM,MAAoB,EAAE,QAAQ,MAAM;AAC1C,UAAM,OAAO,OAAO,OAAO,SAAS,CAAC;AACrC,QAAI,OAAO,SAAS,MAAM,SAAS,WAAW,KAAK,UAAU,OAAO,OAAO;AACzE,WAAK,KAAK,KAAK,GAAG;AAAA,IACpB,WAAW,OAAO,OAAO;AACvB,aAAO,KAAK,EAAE,MAAM,SAAS,OAAO,OAAO,OAAO,MAAM,CAAC,GAAG,EAAE,CAAC;AAAA,IACjE,OAAO;AACL,aAAO,KAAK,EAAE,MAAM,UAAU,IAAI,CAAC;AAAA,IACrC;AAAA,EACF,CAAC;AACD,SAAO;AACT;;;ACZQ,SACe,OAAAC,OADf,QAAAC,cAAA;AAbD,SAAS,kBAA4C;AAAA,EAC1D;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAA4C;AAC1C,SACE,gBAAAA,OAAC,SAAM,WAAU,WACf;AAAA,oBAAAD,MAAC,eACC,0BAAAC,OAAC,YAAS,WAAU,wBACjB;AAAA,kBAAY,gBAAAD,MAAC,aAAU,WAAU,kCAAiC;AAAA,MAClE,QAAQ,IAAI,CAAC,WACZ,gBAAAA;AAAA,QAAC;AAAA;AAAA,UAEC,WAAW,GAAG,wDAAwD,OAAO,SAAS;AAAA,UAErF,iBAAO;AAAA;AAAA,QAHH,OAAO;AAAA,MAId,CACD;AAAA,OACH,GACF;AAAA,IACA,gBAAAA,MAAC,aACE,kBAAQ,IAAI,CAAC,QAAQ,UAAU;AAC9B,YAAM,WAAW,WAAW,MAAM;AAClC,YAAM,SAAS,UAAU;AACzB,aACE,gBAAAC;AAAA,QAAC;AAAA;AAAA,UAEC,MAAK;AAAA,UACL,iBAAe;AAAA,UAKf,cAAY,OAAO;AAAA,UACnB,iBAAe,OAAO;AAAA,UACtB,eAAa,SAAS,GAAG,MAAM,YAAY;AAAA,UAC3C,qBAAmB,OAAO;AAAA,UAC1B,cAAc,MAAM,QAAQ,KAAK;AAAA,UACjC,SAAS,MAAM;AACb,gBAAI,CAAC,OAAO,SAAU,UAAS,MAAM;AAAA,UACvC;AAAA,UACA,WAAW;AAAA,YACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,YAMA,UAAU;AAAA,YACV,OAAO,YAAY;AAAA,UACrB;AAAA,UAEC;AAAA,wBACC,gBAAAD,MAAC,aAAU,WAAU,OACnB,0BAAAA;AAAA,cAAC;AAAA;AAAA,gBACC,MAAK;AAAA,gBACL,SAAS;AAAA,gBACT,UAAQ;AAAA,gBACR,UAAU;AAAA,gBACV,WAAU;AAAA;AAAA,YACZ,GACF;AAAA,YAED,QAAQ,IAAI,CAAC,WACZ,gBAAAA,MAAC,aAA2B,WAAW,GAAG,YAAY,OAAO,SAAS,GACnE,iBAAO,QAAQ,UAAU,OAAO,QAAQ,OAAO,OAAO,OAAO,GAAG,KADnD,OAAO,GAEvB,CACD;AAAA;AAAA;AAAA,QAzCI,OAAO;AAAA,MA0Cd;AAAA,IAEJ,CAAC,GACH;AAAA,KACF;AAEJ;;;AF+JM,SAgBI,OAAAE,OAhBJ,QAAAC,cAAA;AArKN,SAAS,yBACP,SACA,gBACA,YACe;AACf,QAAM,cAAc,IAAI,IAAI,cAAc;AAC1C,QAAM,gBAAgB,MAAM;AAAA,IAC1B,IAAI,IAAI,QAAQ,OAAO,CAAC,MAAM,YAAY,IAAI,EAAE,KAAK,KAAK,EAAE,KAAK,EAAE,IAAI,CAAC,MAAM,EAAE,KAAe,CAAC;AAAA,EAClG;AACA,MAAI,cAAc,WAAW,EAAG,QAAO;AAEvC,QAAM,gBAAgB,oBAAI,IAAY;AACtC,QAAM,qBAA+B,CAAC;AACtC,aAAW,SAAS,eAAe;AACjC,UAAM,UAAU,aAAa,SAAS,KAAK;AAC3C,QAAI,QAAQ,SAAS,KAAK,QAAQ,MAAM,CAAC,MAAM,YAAY,IAAI,CAAC,CAAC,GAAG;AAClE,yBAAmB,KAAK,KAAK;AAC7B,iBAAW,KAAK,QAAS,eAAc,IAAI,CAAC;AAAA,IAC9C;AAAA,EACF;AACA,QAAM,cAAc,eAAe,KAAK,CAAC,MAAM,CAAC,cAAc,IAAI,CAAC,CAAC;AACpE,MAAI,mBAAmB,WAAW,KAAK,YAAa,QAAO;AAC3D,SAAO,mBAAmB,IAAI,UAAU,EAAE,KAAK,IAAI;AACrD;AAcO,SAAS,SAAS,OAAoC;AAC3D,QAAM;AAAA,IACJ;AAAA,IACA,cAAc;AAAA,IACd,oBAAoB;AAAA,IACpB,eAAe;AAAA,IACf;AAAA,IACA,UAAU;AAAA,IACV,iBAAiB;AAAA,IACjB,YAAY;AAAA,IACZ;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,IAAI;AACJ,QAAM,SAAS,MAAM,aAAa;AAClC,QAAM,CAAC,MAAM,OAAO,IAAIC,UAAS,KAAK;AACtC,QAAM,CAAC,QAAQ,SAAS,IAAIA,UAAS,EAAE;AACvC,QAAM,CAAC,aAAa,cAAc,IAAIA,UAAS,CAAC;AAChD,QAAM,WAAWC,QAAyB,IAAI;AAK9C,QAAM,iBAAiB;AAAA,IACrB,MAAO,MAAM,WAAW,MAAM,QAAQ,MAAM,QAAQ,CAAC,MAAM,KAAK,IAAI,CAAC;AAAA,IACrE,CAAC,MAAM,UAAU,MAAM,KAAK;AAAA,EAC9B;AAEA,QAAM,kBAAkB;AAAA,IACtB,MAAM,QAAQ,OAAO,CAAC,WAAW,eAAe,SAAS,OAAO,KAAK,CAAC;AAAA,IACtE,CAAC,SAAS,cAAc;AAAA,EAC1B;AAMA,QAAM,iBAAiB,QAAQ,MAAM;AACnC,QAAI,eAAgB,QAAO;AAC3B,UAAM,OAAO,OAAO,KAAK,EAAE,YAAY;AACvC,QAAI,CAAC,KAAM,QAAO;AAClB,WAAO,QAAQ,OAAO,CAAC,WAAW,OAAO,MAAM,YAAY,EAAE,SAAS,IAAI,CAAC;AAAA,EAC7E,GAAG,CAAC,SAAS,QAAQ,cAAc,CAAC;AAMpC,EAAAC,WAAU,MAAM;AACd,QAAI,CAAC,KAAM;AACX,cAAU,EAAE;AACZ,qBAAiB,EAAE;AACnB,UAAM,gBAAgB,eAAe,CAAC;AACtC,UAAM,cAAc,gBAAgB,QAAQ,UAAU,CAAC,WAAW,OAAO,UAAU,aAAa,IAAI;AACpG,mBAAe,eAAe,IAAI,cAAc,CAAC;AACjD,aAAS,SAAS,MAAM;AAAA,EAC1B,GAAG,CAAC,IAAI,CAAC;AAGT,EAAAA,WAAU,MAAM;AACd,mBAAe,CAAC,MAAM,KAAK,IAAI,GAAG,KAAK,IAAI,eAAe,SAAS,GAAG,CAAC,CAAC,CAAC;AAAA,EAC3E,GAAG,CAAC,eAAe,MAAM,CAAC;AAE1B,WAAS,aAAa,QAA8B;AAClD,QAAI,OAAO,SAAU;AACrB,QAAI,MAAM,UAAU;AAClB,YAAM,OAAO,MAAM,MAAM,SAAS,OAAO,KAAK,IAC1C,MAAM,MAAM,OAAO,CAAC,MAAM,MAAM,OAAO,KAAK,IAC5C,CAAC,GAAG,MAAM,OAAO,OAAO,KAAK;AACjC,YAAM,SAAS,IAAI;AACnB;AAAA,IACF;AACA,UAAM,SAAS,OAAO,KAAK;AAC3B,YAAQ,KAAK;AAAA,EACf;AAEA,WAAS,cAAc,OAA8C;AACnE,QAAI,MAAM,QAAQ,aAAa;AAC7B,YAAM,eAAe;AACrB,qBAAe,CAAC,MAAM,KAAK,IAAI,IAAI,GAAG,eAAe,SAAS,CAAC,CAAC;AAAA,IAClE,WAAW,MAAM,QAAQ,WAAW;AAClC,YAAM,eAAe;AACrB,qBAAe,CAAC,MAAM,KAAK,IAAI,IAAI,GAAG,CAAC,CAAC;AAAA,IAC1C,WAAW,MAAM,QAAQ,SAAS;AAChC,YAAM,eAAe;AACrB,YAAM,SAAS,eAAe,WAAW;AACzC,UAAI,OAAQ,cAAa,MAAM;AAAA,IACjC;AAAA,EACF;AAEA,QAAM,aAAa,CAAC,UAA0B,cAAc,KAAK,KAAK;AAEtE,WAAS,YAAY,OAAqB;AACxC,QAAI,CAAC,MAAM,SAAU;AACrB,UAAM,UAAU,aAAa,SAAS,KAAK;AAC3C,UAAM,OACJ,gBAAgB,SAAS,gBAAgB,KAAK,MAAM,YAChD,MAAM,MAAM,OAAO,CAAC,MAAM,CAAC,QAAQ,SAAS,CAAC,CAAC,IAC9C,MAAM,KAAK,oBAAI,IAAI,CAAC,GAAG,MAAM,OAAO,GAAG,OAAO,CAAC,CAAC;AACtD,UAAM,SAAS,IAAI;AAAA,EACrB;AAKA,QAAM,eAAe,UACjB,iBACA,gBAAgB,WAAW,IACxB,eAAe,SAAS,IAAK,iBAAiB,cAAe,cAC9D,gBAAgB,WAAW,IACxB,gBAAgB,CAAC,GAAG,SAAS,eAC7B,MAAM,WAAW,yBAAyB,SAAS,gBAAgB,UAAU,IAAI,SAClF,GAAG,gBAAgB,MAAM;AAMjC,QAAM,eAAe,QAAQ,MAAO,UAAU,CAAC,IAAI,kBAAkB,cAAc,GAAI,CAAC,gBAAgB,OAAO,CAAC;AAEhH,WAAS,aAAa,EAAE,QAAQ,MAAM,GAA4B;AAChE,UAAM,aAAa,eAAe,SAAS,OAAO,KAAK;AACvD,UAAM,WAAW,UAAU;AAC3B,WACE,gBAAAH;AAAA,MAAC;AAAA;AAAA,QAEC,MAAK;AAAA,QACL,MAAK;AAAA,QACL,iBAAe;AAAA,QACf,UAAU,OAAO;AAAA,QACjB,eAAa,SAAS,GAAG,MAAM,YAAY;AAAA,QAC3C,qBAAmB,OAAO;AAAA,QAC1B,cAAc,MAAM,eAAe,KAAK;AAAA,QACxC,SAAS,MAAM,aAAa,MAAM;AAAA,QAClC,WAAW;AAAA,UACT;AAAA,UACA,YAAY;AAAA,QACd;AAAA,QAEC;AAAA,gBAAM,WACL,gBAAAD;AAAA,YAAC;AAAA;AAAA,cACC,MAAK;AAAA,cACL,SAAS;AAAA,cACT,UAAQ;AAAA,cACR,UAAU;AAAA,cACV,WAAU;AAAA;AAAA,UACZ,IAEA,gBAAAA,MAACK,QAAA,EAAM,WAAW,GAAG,oBAAoB,aAAa,gBAAgB,WAAW,GAAG;AAAA,UAEtF,gBAAAL,MAAC,UAAK,WAAU,YAAY,iBAAO,OAAM;AAAA;AAAA;AAAA,MAzBpC,OAAO;AAAA,IA0Bd;AAAA,EAEJ;AAEA,SACE,gBAAAC,OAAC,WAAQ,MAAY,cAAc,SACjC;AAAA,oBAAAD,MAAC,kBAAe,SAAO,MACrB,0BAAAC;AAAA,MAAC;AAAA;AAAA,QACC;AAAA,QACA,eAAa;AAAA,QACb,MAAK;AAAA,QACL,SAAQ;AAAA,QACR,MAAK;AAAA,QACL,iBAAe;AAAA,QACf,UAAU,YAAY;AAAA,QACtB,WAAW;AAAA,UACT;AAAA,WACC,gBAAgB,WAAW,KAAK,YAAY;AAAA,UAC7C;AAAA,QACF;AAAA,QAEA;AAAA,0BAAAD,MAAC,UAAK,WAAU,YAAY,wBAAa;AAAA,UACzC,gBAAAC,OAAC,UAAK,WAAU,2BACb;AAAA,yBAAa,CAAC,WAAW,eAAe,SAAS,IAChD,gBAAAD;AAAA,cAAC;AAAA;AAAA,gBACC,MAAK;AAAA,gBACL,cAAW;AAAA,gBACX,UAAU;AAAA,gBACV,WAAU;AAAA,gBACV,SAAS,CAAC,UAAU;AAClB,wBAAM,gBAAgB;AACtB,sBAAI,MAAM,UAAU;AAClB,0BAAM,SAAS,CAAC,CAAC;AAAA,kBACnB,OAAO;AACL,0BAAM,SAAS,IAAI;AAAA,kBACrB;AAAA,gBACF;AAAA,gBAEA,0BAAAA,MAACM,IAAA,EAAE,WAAU,eAAc;AAAA;AAAA,YAC7B,IACE;AAAA,YACJ,gBAAAN,MAAC,kBAAe,WAAU,+BAA8B,eAAY,QAAO;AAAA,aAC7E;AAAA;AAAA;AAAA,IACF,GACF;AAAA,IACA,gBAAAA;AAAA,MAAC;AAAA;AAAA,QACC,OAAM;AAAA,QACN;AAAA,QACA,WAAW;AAAA,UACT;AAAA,UACA,WAAW;AAAA,QACb;AAAA,QACA,iBAAiB,CAAC,UAAU,MAAM,eAAe;AAAA,QAEjD,0BAAAC,OAAC,SAAI,WAAU,uBACb;AAAA,0BAAAD;AAAA,YAAC;AAAA;AAAA,cACC,KAAK;AAAA,cACL,OAAO;AAAA,cACP,UAAU,CAAC,UAAU;AACnB,0BAAU,MAAM,OAAO,KAAK;AAC5B,iCAAiB,MAAM,OAAO,KAAK;AAAA,cACrC;AAAA,cACA,WAAW;AAAA,cACX,aAAa;AAAA,cACb,cAAY;AAAA;AAAA,UACd;AAAA,UACA,gBAAAA,MAAC,SAAI,MAAK,WAAU,WAAW,GAAG,4BAA4B,CAAC,WAAW,uBAAuB,GAC9F,yBAAe,WAAW,IACzB,gBAAAA,MAAC,OAAE,WAAU,kDAAkD,wBAAa,IAC1E,UACF,kBAAkB;AAAA,YAChB;AAAA,YACA,SAAS;AAAA,YACT;AAAA,YACA,UAAU,QAAQ,MAAM,QAAQ;AAAA,YAChC,YAAY,CAAC,WAAW,eAAe,SAAS,OAAO,KAAK;AAAA,YAC5D,UAAU;AAAA,YACV,SAAS;AAAA,YACT;AAAA,UACF,CAAC,IAED,aAAa,IAAI,CAAC,UAAU;AAC1B,gBAAI,MAAM,SAAS,SAAU,QAAO,aAAa,MAAM,GAAG;AAC1D,kBAAM,cAAc,gBAAgB,SAAS,gBAAgB,MAAM,KAAK;AACxE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,cAQE,gBAAAC,OAAC,SAAiC,WAAU,yCAC1C;AAAA,gCAAAA;AAAA,kBAAC;AAAA;AAAA,oBACC,qBAAiB;AAAA,oBACjB,WAAU;AAAA,oBAET;AAAA,4BAAM,WACL,gBAAAD;AAAA,wBAAC;AAAA;AAAA,0BACC,MAAK;AAAA,0BACL,SAAS,gBAAgB;AAAA,0BACzB,KAAK,CAAC,OAAO;AACX,gCAAI,GAAI,IAAG,gBAAgB,gBAAgB;AAAA,0BAC7C;AAAA,0BACA,UAAU,MAAM,YAAY,MAAM,KAAK;AAAA,0BACvC,SAAS,CAAC,UAAU,MAAM,gBAAgB;AAAA,0BAC1C,WAAU;AAAA,0BACV,cAAY,iBAAiB,WAAW,MAAM,KAAK,CAAC;AAAA;AAAA,sBACtD,IACE;AAAA,sBACJ,gBAAAA,MAAC,UAAK,WAAU,YAAY,qBAAW,MAAM,KAAK,GAAE;AAAA;AAAA;AAAA,gBACtD;AAAA,gBACC,MAAM,KAAK,IAAI,YAAY;AAAA,mBApBpB,SAAS,MAAM,KAAK,EAqB9B;AAAA;AAAA,UAEJ,CAAC,GAEL;AAAA,WACF;AAAA;AAAA,IACF;AAAA,KACF;AAEJ;;;AG7aA,SAAS,KAAAO,UAAS;AAElB,SAAS,aAAAC,YAAW,WAAAC,UAAS,UAAAC,SAAQ,YAAAC,iBAAgB;AAkN/C,SAeE,OAAAC,OAfF,QAAAC,cAAA;AAjIC,SAAS,YAAY;AAAA,EAC1B;AAAA,EACA;AAAA,EACA;AAAA,EACA,cAAc;AAAA,EACd,eAAe;AAAA,EACf;AAAA,EACA,UAAU;AAAA,EACV,iBAAiB;AAAA,EACjB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,GAAG;AACL,GAAmC;AACjC,QAAM,SAAS,KAAK,aAAa;AACjC,QAAM,CAAC,MAAM,OAAO,IAAIC,UAAS,KAAK;AACtC,QAAM,CAAC,QAAQ,SAAS,IAAIA,UAAS,EAAE;AACvC,QAAM,CAAC,aAAa,cAAc,IAAIA,UAAS,CAAC;AAChD,QAAM,WAAWC,QAAyB,IAAI;AAC9C,QAAM,WAAWA,QAAuB,IAAI;AAE5C,QAAM,kBAAkBC;AAAA,IACtB,MAAM,MAAM,IAAI,CAAC,MAAM,QAAQ,KAAK,CAAC,MAAM,EAAE,UAAU,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,EAAE,CAAC;AAAA,IACnF,CAAC,SAAS,KAAK;AAAA,EACjB;AAMA,QAAM,iBAAiBA,SAAQ,MAAM;AACnC,QAAI,eAAgB,QAAO;AAC3B,UAAM,OAAO,OAAO,KAAK,EAAE,YAAY;AACvC,QAAI,CAAC,KAAM,QAAO;AAClB,WAAO,QAAQ,OAAO,CAAC,WAAW,OAAO,MAAM,YAAY,EAAE,SAAS,IAAI,CAAC;AAAA,EAC7E,GAAG,CAAC,SAAS,QAAQ,cAAc,CAAC;AAEpC,EAAAC,WAAU,MAAM;AACd,mBAAe,CAAC,MAAM,KAAK,IAAI,KAAK,IAAI,GAAG,CAAC,GAAG,KAAK,IAAI,eAAe,SAAS,GAAG,CAAC,CAAC,CAAC;AAAA,EACxF,GAAG,CAAC,eAAe,MAAM,CAAC;AAI1B,QAAM,eAAeD,SAAQ,MAAO,UAAU,CAAC,IAAI,kBAAkB,cAAc,GAAI,CAAC,gBAAgB,OAAO,CAAC;AAShH,EAAAC,WAAU,MAAM;AACd,QAAI,CAAC,KAAM;AACX,cAAU,EAAE;AACZ,qBAAiB,EAAE;AACnB,UAAM,gBAAgB,MAAM,CAAC;AAC7B,UAAM,cAAc,gBAAgB,QAAQ,UAAU,CAAC,MAAM,EAAE,UAAU,aAAa,IAAI;AAC1F,mBAAe,eAAe,IAAI,cAAc,CAAC;AAAA,EACnD,GAAG,CAAC,IAAI,CAAC;AAET,WAAS,aAAa,MAAoB;AACxC,cAAU,IAAI;AACd,qBAAiB,IAAI;AACrB,QAAI,CAAC,KAAM,SAAQ,IAAI;AAAA,EACzB;AAEA,WAAS,aAAa,QAAiC;AACrD,QAAI,OAAO,SAAU;AACrB,UAAM,OAAO,MAAM,SAAS,OAAO,KAAK,IAAI,MAAM,OAAO,CAAC,MAAM,MAAM,OAAO,KAAK,IAAI,CAAC,GAAG,OAAO,OAAO,KAAK;AAC7G,aAAS,IAAI;AACb,iBAAa,EAAE;AACf,aAAS,SAAS,MAAM;AAAA,EAC1B;AAEA,WAAS,YAAY,GAAiB;AAKpC,QAAI,QAAQ,KAAK,CAAC,MAAM,EAAE,UAAU,CAAC,GAAG,SAAU;AAClD,aAAS,MAAM,OAAO,CAAC,aAAa,aAAa,CAAC,CAAC;AAAA,EACrD;AAEA,QAAM,aAAa,CAAC,UAA0B,cAAc,KAAK,KAAK;AAMtE,WAAS,YAAY,OAAqB;AACxC,UAAM,UAAU,aAAa,SAAS,KAAK;AAC3C,UAAM,OACJ,gBAAgB,SAAS,OAAO,KAAK,MAAM,YACvC,MAAM,OAAO,CAAC,MAAM,CAAC,QAAQ,SAAS,CAAC,CAAC,IACxC,MAAM,KAAK,oBAAI,IAAI,CAAC,GAAG,OAAO,GAAG,OAAO,CAAC,CAAC;AAChD,aAAS,IAAI;AACb,aAAS,SAAS,MAAM;AAAA,EAC1B;AAEA,WAAS,cAAc,OAA8C;AACnE,QAAI,MAAM,QAAQ,aAAa;AAC7B,YAAM,eAAe;AACrB,cAAQ,IAAI;AACZ,qBAAe,CAAC,MAAM,KAAK,IAAI,IAAI,GAAG,KAAK,IAAI,eAAe,SAAS,GAAG,CAAC,CAAC,CAAC;AAAA,IAC/E,WAAW,MAAM,QAAQ,WAAW;AAClC,YAAM,eAAe;AACrB,qBAAe,CAAC,MAAM,KAAK,IAAI,IAAI,GAAG,CAAC,CAAC;AAAA,IAC1C,WAAW,MAAM,QAAQ,SAAS;AAChC,YAAM,eAAe;AACrB,YAAM,SAAS,eAAe,WAAW;AACzC,UAAI,OAAQ,cAAa,MAAM;AAAA,IACjC,WAAW,MAAM,QAAQ,UAAU;AACjC,cAAQ,KAAK;AAAA,IACf,WAAW,MAAM,QAAQ,eAAe,WAAW,IAAI;AAGrD,YAAM,OAAO,MAAM,MAAM,SAAS,CAAC;AACnC,UAAI,SAAS,OAAW,aAAY,IAAI;AAAA,IAC1C;AAAA,EACF;AAEA,WAAS,aAAa,EAAE,QAAQ,MAAM,GAA+C;AACnF,UAAM,aAAa,MAAM,SAAS,OAAO,KAAK;AAC9C,UAAM,WAAW,UAAU;AAC3B,WACE,gBAAAJ;AAAA,MAAC;AAAA;AAAA,QAEC,MAAK;AAAA,QACL,MAAK;AAAA,QACL,iBAAe;AAAA,QACf,UAAU,OAAO;AAAA,QACjB,eAAa,SAAS,GAAG,MAAM,YAAY;AAAA,QAC3C,qBAAmB,OAAO;AAAA,QAC1B,cAAc,MAAM,eAAe,KAAK;AAAA,QACxC,SAAS,MAAM,aAAa,MAAM;AAAA,QAClC,WAAW;AAAA,UACT;AAAA,UACA,YAAY;AAAA,QACd;AAAA,QAEA;AAAA,0BAAAD;AAAA,YAAC;AAAA;AAAA,cACC,MAAK;AAAA,cACL,SAAS;AAAA,cACT,UAAQ;AAAA,cACR,UAAU;AAAA,cACV,WAAU;AAAA;AAAA,UACZ;AAAA,UACA,gBAAAA,MAAC,UAAK,WAAU,YAAY,iBAAO,OAAM;AAAA;AAAA;AAAA,MArBpC,OAAO;AAAA,IAsBd;AAAA,EAEJ;AAEA,SACE,gBAAAC,OAAC,WAAQ,MAAY,cAAc,SACjC;AAAA,oBAAAD,MAAC,iBAAc,SAAO,MACpB,0BAAAC;AAAA,MAAC;AAAA;AAAA,QACC,KAAK;AAAA,QACL,eAAa;AAAA,QACb,MAAK;AAAA,QACL,iBAAe;AAAA,QACf,iBAAe;AAAA,QACf,WAAW;AAAA,UACT;AAAA,UACA;AAAA,UACA,YAAY;AAAA,UACZ;AAAA,QACF;AAAA,QACA,SAAS,MAAM;AACb,cAAI,CAAC,SAAU,UAAS,SAAS,MAAM;AAAA,QACzC;AAAA,QAEC;AAAA,0BAAgB,IAAI,CAAC,WACpB,gBAAAA;AAAA,YAAC;AAAA;AAAA,cAEC,WAAU;AAAA,cAEV;AAAA,gCAAAD,MAAC,UAAK,WAAU,qBAAqB,iBAAO,OAAM;AAAA,gBACjD,CAAC,YACA,gBAAAA;AAAA,kBAAC;AAAA;AAAA,oBACC,MAAK;AAAA,oBACL,cAAY,UAAU,OAAO,KAAK;AAAA,oBAClC,WAAU;AAAA,oBACV,SAAS,CAAC,UAAU;AAClB,4BAAM,gBAAgB;AACtB,kCAAY,OAAO,KAAK;AAAA,oBAC1B;AAAA,oBAEA,0BAAAA,MAACM,IAAA,EAAE,WAAU,WAAU;AAAA;AAAA,gBACzB;AAAA;AAAA;AAAA,YAfG,OAAO;AAAA,UAiBd,CACD;AAAA,UACD,gBAAAN;AAAA,YAAC;AAAA;AAAA,cACC,KAAK;AAAA,cACL;AAAA,cACA,OAAO;AAAA,cACP;AAAA,cACA,aAAa,gBAAgB,WAAW,IAAI,cAAc;AAAA,cAC1D,cAAY;AAAA,cACZ,WAAU;AAAA,cACV,SAAS,MAAM,QAAQ,IAAI;AAAA,cAC3B,UAAU,CAAC,UAAU,aAAa,MAAM,OAAO,KAAK;AAAA,cACpD,WAAW;AAAA;AAAA,UACb;AAAA;AAAA;AAAA,IACF,GACF;AAAA,IACA,gBAAAA;AAAA,MAAC;AAAA;AAAA,QACC,OAAM;AAAA,QACN;AAAA,QACA,WAAW;AAAA,UACT;AAAA,UACA,WAAW;AAAA,QACb;AAAA,QACA,iBAAiB,CAAC,UAAU,MAAM,eAAe;AAAA,QACjD,kBAAkB,CAAC,UAAU,MAAM,eAAe;AAAA,QAUlD,mBAAmB,CAAC,UAAU;AAC5B,cAAI,SAAS,SAAS,SAAS,MAAM,MAAc,EAAG,OAAM,eAAe;AAAA,QAC7E;AAAA,QAEA,0BAAAA,MAAC,SAAI,MAAK,WAAU,WAAW,GAAG,4BAA4B,CAAC,WAAW,uBAAuB,GAC9F,oBACC,gBAAAA,MAAC,OAAE,WAAU,kDAAkD,0BAAe,IAC5E,eAAe,WAAW,IAC5B,gBAAAA,MAAC,OAAE,WAAU,kDAAkD,wBAAa,IAC1E,UACF,kBAAkB;AAAA,UAChB;AAAA,UACA,SAAS;AAAA,UACT;AAAA,UACA,UAAU;AAAA,UACV,YAAY,CAAC,WAAW,MAAM,SAAS,OAAO,KAAK;AAAA,UACnD,UAAU;AAAA,UACV,SAAS;AAAA,UACT;AAAA,QACF,CAAC,IAED,aAAa,IAAI,CAAC,UAAU;AAC1B,cAAI,MAAM,SAAS,SAAU,QAAO,aAAa,MAAM,GAAG;AAC1D,gBAAM,cAAc,gBAAgB,SAAS,OAAO,MAAM,KAAK;AAC/D;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,YAOE,gBAAAC,OAAC,SAAiC,WAAU,yCAC1C;AAAA,8BAAAA;AAAA,gBAAC;AAAA;AAAA,kBACC,qBAAiB;AAAA,kBACjB,WAAU;AAAA,kBAEV;AAAA,oCAAAD;AAAA,sBAAC;AAAA;AAAA,wBACC,MAAK;AAAA,wBACL,SAAS,gBAAgB;AAAA,wBACzB,KAAK,CAAC,OAAO;AACX,8BAAI,GAAI,IAAG,gBAAgB,gBAAgB;AAAA,wBAC7C;AAAA,wBACA,UAAU,MAAM,YAAY,MAAM,KAAK;AAAA,wBACvC,SAAS,CAAC,UAAU,MAAM,gBAAgB;AAAA,wBAC1C,WAAU;AAAA,wBACV,cAAY,iBAAiB,WAAW,MAAM,KAAK,CAAC;AAAA;AAAA,oBACtD;AAAA,oBACA,gBAAAA,MAAC,UAAK,WAAU,YAAY,qBAAW,MAAM,KAAK,GAAE;AAAA;AAAA;AAAA,cACtD;AAAA,cACC,MAAM,KAAK,IAAI,YAAY;AAAA,iBAlBpB,SAAS,MAAM,KAAK,EAmB9B;AAAA;AAAA,QAEJ,CAAC,GAEL;AAAA;AAAA,IACF;AAAA,KACF;AAEJ;;;ACjXA,SAAS,aAAa,eAAe,cAAc,YAAY;AAqCtD,gBAAAO,OAaD,QAAAC,cAbC;AART,IAAM,gBAAiD;AAAA,EACrD,OAAO;AAAA,EACP,SAAS;AAAA,EACT,MAAM;AAAA,EACN,SAAS;AACX;AAEA,IAAM,eAAsD;AAAA,EAC1D,OAAO,gBAAAD,MAAC,eAAY,WAAU,oBAAmB,eAAY,QAAO;AAAA,EACpE,SAAS,gBAAAA,MAAC,iBAAc,WAAU,oBAAmB,eAAY,QAAO;AAAA,EACxE,MAAM,gBAAAA,MAAC,QAAK,WAAU,oBAAmB,eAAY,QAAO;AAAA,EAC5D,SAAS,gBAAAA,MAAC,gBAAa,WAAU,oBAAmB,eAAY,QAAO;AACzE;AAEO,IAAM,WAAW,CAAC,EAAE,SAAS,OAAO,UAAU,WAAW,KAAK,MAAmC;AACtG,QAAM,eAAe,SAAS,SAAY,aAAa,OAAO,IAAI;AAElE,SACE,gBAAAA,MAAC,SAAI,WAAW,GAAG,iCAAiC,cAAc,OAAO,GAAG,SAAS,GACnF,0BAAAC,OAAC,SAAI,WAAU,mCACZ;AAAA,oBAAgB,QAAQ,gBAAAD,MAAC,UAAK,WAAU,mBAAmB,wBAAa;AAAA,IACzE,gBAAAC,OAAC,SAAI,WAAU,uBACZ;AAAA,eAAS,gBAAAD,MAAC,OAAE,WAAU,aAAa,iBAAM;AAAA,MAC1C,gBAAAA,MAAC,SAAK,UAAS;AAAA,OACjB;AAAA,KACF,GACF;AAEJ;;;ACiDI,gBAAAE,aAAA;AAxFJ,IAAM,eAA2C;AAAA,EAC/C,SAAS;AAAA,EACT,SAAS;AAAA,EACT,MAAM;AAAA,EACN,OAAO;AAAA,EACP,SAAS;AACX;AAGA,IAAM,mBAA+C;AAAA,EACnD,QAAQ;AAAA,EACR,UAAU;AAAA,EACV,WAAW;AAAA,EACX,MAAM;AAAA,EACN,MAAM;AAAA,EACN,SAAS;AAAA,EACT,OAAO;AAAA,EACP,WAAW;AAAA,EACX,UAAU;AAAA,EACV,UAAU;AAAA,EACV,QAAQ;AAAA,EACR,WAAW;AAAA,EACX,UAAU;AAAA,EACV,SAAS;AAAA,EACT,UAAU;AAAA,EACV,UAAU;AAAA,EACV,KAAK;AACP;AAGA,SAAS,YAAY,QAAwB;AAC3C,SAAO,OACJ,QAAQ,UAAU,GAAG,EACrB,KAAK,EACL,MAAM,KAAK,EACX,OAAO,OAAO,EACd,IAAI,CAAC,SAAS,KAAK,OAAO,CAAC,EAAE,YAAY,IAAI,KAAK,MAAM,CAAC,EAAE,YAAY,CAAC,EACxE,KAAK,GAAG;AACb;AAQA,SAAS,YAAY,QAAgB,MAAmB,SAAkD;AACxG,MAAI,MAAM;AACR,WAAO;AAAA,EACT;AAEA,QAAM,MAAM,OAAO,YAAY;AAE/B,MAAI,SAAS;AACX,eAAW,CAAC,WAAW,aAAa,KAAK,OAAO,QAAQ,OAAO,GAAG;AAChE,UAAI,UAAU,YAAY,MAAM,KAAK;AACnC,eAAO;AAAA,MACT;AAAA,IACF;AAAA,EACF;AAEA,SAAO,iBAAiB,GAAG,KAAK;AAClC;AAqBO,IAAM,cAAc,CAAC,EAAE,QAAQ,OAAO,MAAM,SAAS,WAAW,GAAG,MAAM,MAAsC;AACpH,QAAM,eAAe,YAAY,QAAQ,MAAM,OAAO;AACtD,QAAM,eAAe,SAAS,YAAY,MAAM;AAEhD,SACE,gBAAAA,MAAC,SAAM,SAAQ,WAAU,WAAW,GAAG,aAAa,YAAY,GAAG,SAAS,GAAI,GAAG,OAChF,wBACH;AAEJ;;;AC5DU,SAiBW,OAAAC,OAjBX,QAAAC,cAAA;AAfH,SAAS,YAAuC;AAAA,EACrD;AAAA,EACA;AAAA,EACA;AAAA,EACA,OAAO;AAAA,EACP;AAAA,EACA;AAAA,EACA,GAAG;AACL,GAAsC;AACpC,SACE,gBAAAD,MAAC,SAAI,MAAK,SAAQ,cAAY,MAAM,YAAY,GAAG,WAAW,GAAG,eAAe,SAAS,GAAG,eAAa,MAAM,aAAa,GACzH,kBAAQ,IAAI,CAAC,QAAQ,UAAU;AAC9B,UAAM,WAAW,OAAO,UAAU;AAClC,UAAME,QAAO,OAAO;AACpB,WACE,gBAAAD;AAAA,MAAC;AAAA;AAAA,QAEC,MAAK;AAAA,QACL,SAAS,WAAW,YAAY;AAAA,QAChC;AAAA,QACA;AAAA,QACA,gBAAc;AAAA,QACd,eAAa,MAAM,aAAa,IAAI,GAAG,MAAM,aAAa,CAAC,WAAW,OAAO,KAAK,KAAK;AAAA,QACvF,SAAS,MAAM,cAAc,OAAO,KAAK;AAAA,QACzC,WAAW;AAAA,UACT;AAAA,UACA,CAAC,YAAY;AAAA,UACb,UAAU,KAAK;AAAA,UACf,UAAU,QAAQ,SAAS,KAAK;AAAA,UAChC,QAAQ,KAAK;AAAA,QACf;AAAA,QAEC;AAAA,UAAAC,SAAQ,gBAAAF,MAACE,OAAA,EAAK,WAAU,WAAU;AAAA,UAClC,OAAO;AAAA;AAAA;AAAA,MAjBH,OAAO;AAAA,IAkBd;AAAA,EAEJ,CAAC,GACH;AAEJ;;;AC1EA,SAA4B,OAAAC,YAAW;AACvC,SAAS,eAAe;AA+BtB,SACE,OAAAC,OADF,QAAAC,cAAA;AA3BK,IAAM,6BAA6BC,KAAI,sCAAsC;AAAA,EAClF,UAAU;AAAA,IACR,MAAM;AAAA,MACJ,IAAI;AAAA,MACJ,SAAS;AAAA,MACT,IAAI;AAAA,IACN;AAAA,EACF;AAAA,EACA,iBAAiB;AAAA,IACf,MAAM;AAAA,EACR;AACF,CAAC;AAUM,IAAM,iBAAiB,CAAC;AAAA,EAC7B;AAAA,EACA;AAAA,EACA;AAAA,EACA,GAAG;AACL,MACE,gBAAAD,OAAC,UAAK,MAAK,UAAS,WAAW,GAAG,kCAAkC,SAAS,GAAI,GAAG,OAClF;AAAA,kBAAAD,MAAC,WAAQ,WAAW,GAAG,2BAA2B,EAAE,KAAK,CAAC,CAAC,GAAG,eAAY,QAAO;AAAA,EAChF,QAAQ,gBAAAA,MAAC,UAAM,iBAAM,IAAU;AAAA,GAClC;AAUK,IAAM,iBAAiB,CAAC;AAAA,EAC7B,OAAO;AAAA,EACP;AAAA,EACA;AAAA,EACA,GAAG;AACL,MACE,gBAAAA;AAAA,EAAC;AAAA;AAAA,IACC,WAAW,GAAG,2DAA2D,SAAS;AAAA,IACjF,GAAG;AAAA,IAEJ,0BAAAA,MAAC,kBAAe,MAAY,OAAc;AAAA;AAC5C;;;ACxDF,SAAS,QAAQ,KAAAG,UAAS;AAuCtB,SAGM,OAAAC,OAHN,QAAAC,cAAA;AAZG,SAAS,UAAU;AAAA,EACxB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,aAAa;AAAA,EACb;AAAA,EACA;AAAA,EACA,GAAG;AACL,GAAiC;AAC/B,QAAM,YAAY,YAAY,SAAS,MAAM,SAAS;AACtD,SACE,gBAAAA,OAAC,SAAI,WAAW,GAAG,YAAY,SAAS,GACtC;AAAA,oBAAAD,MAAC,UAAK,WAAU,sFACb,sBACC,gBAAAA,MAAC,kBAAe,MAAK,MAAK,IAE1B,gBAAAA,MAAC,UAAO,WAAU,WAAU,eAAY,QAAO,GAEnD;AAAA,IACA,gBAAAA;AAAA,MAAC;AAAA;AAAA,QACC,KAAK;AAAA,QACL,MAAK;AAAA,QACL;AAAA,QACA,UAAU,CAAC,UAAU,SAAS,MAAM,OAAO,KAAK;AAAA,QAChD,WAAW;AAAA,UACT;AAAA;AAAA;AAAA;AAAA,UAIA;AAAA,UACA,YAAY,UAAU;AAAA,UACtB;AAAA,QACF;AAAA,QACC,GAAG;AAAA;AAAA,IACN;AAAA,IACC,aACC,gBAAAA;AAAA,MAAC;AAAA;AAAA,QACC,MAAK;AAAA,QACL,SAAS,MAAO,UAAU,QAAQ,IAAI,SAAS,EAAE;AAAA,QACjD,cAAY;AAAA,QACZ,WAAU;AAAA,QAEV,0BAAAA,MAACE,IAAA,EAAE,WAAU,WAAU,eAAY,QAAO;AAAA;AAAA,IAC5C;AAAA,KAEJ;AAEJ;;;AC3EA,SAAS,YAAmD;AAuEtD,SAiNM,YAAAC,WAhNJ,OAAAC,OADF,QAAAC,cAAA;AA/BN,IAAM,eAAe;AAAA,EACnB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAEO,SAAS,WAAW;AAAA,EACzB;AAAA,EACA,OAAO;AAAA,EACP,YAAY;AAAA,EACZ;AAAA,EACA;AACF,GAMwB;AACtB,QAAM,QAAQ,KAAK,OAAO,CAAC,KAAK,MAAM,MAAM,EAAE,OAAO,CAAC;AACtD,MAAI,SAAS,EAAG,QAAO;AAEvB,QAAM,UAAU,OAAO,aAAa;AACpC,QAAM,gBAAgB,IAAI,KAAK,KAAK;AACpC,MAAI,SAAS;AAEb,SACE,gBAAAA,OAAC,SAAI,WAAU,6DAA4D,OAAO,EAAE,OAAO,MAAM,QAAQ,KAAK,GAC5G;AAAA,oBAAAA,OAAC,SAAI,OAAO,MAAM,QAAQ,MAAM,SAAS,OAAO,IAAI,IAAI,IAAI,IAAI,WAAU,cACxE;AAAA,sBAAAD,MAAC,YAAO,IAAI,OAAO,GAAG,IAAI,OAAO,GAAG,GAAG,QAAQ,MAAK,QAAO,QAAO,gBAAe,WAAU,iBAAgB,aAAa,WAAW;AAAA,MAClI,KAAK,IAAI,CAAC,SAAS,MAAM;AACxB,cAAM,WAAW,QAAQ,QAAQ;AACjC,cAAM,OAAO,WAAW;AACxB,cAAM,KACJ,gBAAAA;AAAA,UAAC;AAAA;AAAA,YAEC,IAAI,OAAO;AAAA,YACX,IAAI,OAAO;AAAA,YACX,GAAG;AAAA,YACH,MAAK;AAAA,YACL,QAAQ,QAAQ,SAAS,aAAa,IAAI,aAAa,MAAM;AAAA,YAC7D,aAAa;AAAA,YACb,iBAAiB,GAAG,IAAI,IAAI,gBAAgB,IAAI;AAAA,YAChD,kBAAkB,CAAC;AAAA,YACnB,eAAe,KAAK,SAAS,IAAI,SAAS;AAAA;AAAA,UATrC,QAAQ;AAAA,QAUf;AAEF,kBAAU;AACV,eAAO;AAAA,MACT,CAAC;AAAA,OACH;AAAA,KACE,eAAe,gBACf,gBAAAC,OAAC,SAAI,WAAU,8DACZ;AAAA,qBAAe,gBAAAD,MAAC,UAAK,WAAU,oEAAoE,uBAAY;AAAA,MAC/G,eAAe,gBAAAA,MAAC,UAAK,WAAU,0DAA0D,uBAAY;AAAA,OACxG;AAAA,KAEJ;AAEJ;AAEO,SAAS,UAAU,EAAE,MAAM,MAAM,GAA2D;AACjG,MAAI,KAAK,SAAS,EAAG,QAAO;AAC5B,QAAM,MAAM,KAAK,IAAI,GAAG,IAAI;AAC5B,QAAM,MAAM,KAAK,IAAI,GAAG,IAAI;AAC5B,QAAM,QAAQ,MAAM,OAAO;AAC3B,QAAM,IAAI;AACV,QAAM,IAAI;AACV,QAAM,MAAM,KACT,IAAI,CAAC,GAAG,MAAM,GAAI,KAAK,KAAK,SAAS,KAAM,CAAC,IAAI,KAAM,IAAI,OAAO,SAAU,IAAI,KAAK,CAAC,EAAE,EACvF,KAAK,GAAG;AACX,SACE,gBAAAA,MAAC,SAAI,OAAO,GAAG,QAAQ,GAAG,SAAS,OAAO,CAAC,IAAI,CAAC,IAAI,WAAU,+BAC5D,0BAAAA,MAAC,cAAS,QAAQ,KAAK,MAAK,QAAO,QAAQ,OAAO,aAAY,OAAM,eAAc,SAAQ,gBAAe,SAAQ,GACnH;AAEJ;AAEA,SAAS,cAAc,EAAE,MAAM,MAAM,GAA2D;AAC9F,MAAI,KAAK,SAAS,EAAG,QAAO;AAC5B,QAAM,MAAM,KAAK,IAAI,GAAG,IAAI;AAC5B,QAAM,MAAM,KAAK,IAAI,GAAG,IAAI;AAC5B,QAAM,QAAQ,MAAM,OAAO;AAC3B,QAAM,IAAI;AACV,QAAM,IAAI;AACV,QAAM,IAAI;AACV,QAAM,KAAK,KAAK,IAAI,CAAC,GAAG,MAAO,KAAK,KAAK,SAAS,KAAM,CAAC;AACzD,QAAM,KAAK,KAAK,IAAI,CAAC,MAAM,KAAM,IAAI,OAAO,SAAU,IAAI,IAAI,KAAK,CAAC;AACpE,QAAM,UAAU,GAAG,IAAI,CAAC,GAAG,MAAM,GAAG,CAAC,IAAI,GAAG,CAAC,CAAC,EAAE,EAAE,KAAK,GAAG;AAC1D,QAAM,WAAW,IAAI,GAAG,CAAC,CAAC,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,GAAG,MAAM,IAAI,CAAC,IAAI,GAAG,CAAC,CAAC,EAAE,EAAE,KAAK,GAAG,IAAI,KAAK,GAAG,GAAG,SAAS,CAAC,CAAC,IAAI,CAAC;AAE/G,SACE,gBAAAC,OAAC,SAAI,OAAO,GAAG,QAAQ,GAAG,SAAS,OAAO,CAAC,IAAI,CAAC,IAAI,WAAU,oBAAmB,qBAAoB,QACnG;AAAA,oBAAAD,MAAC,UACC,0BAAAC,OAAC,oBAAe,IAAG,uBAAsB,IAAG,KAAI,IAAG,KAAI,IAAG,KAAI,IAAG,KAC/D;AAAA,sBAAAD,MAAC,UAAK,QAAO,MAAK,WAAW,OAAO,aAAY,QAAO;AAAA,MACvD,gBAAAA,MAAC,UAAK,QAAO,QAAO,WAAW,OAAO,aAAY,KAAI;AAAA,OACxD,GACF;AAAA,IACA,gBAAAA,MAAC,UAAK,GAAG,UAAU,MAAK,6BAA4B;AAAA,IACpD,gBAAAA,MAAC,cAAS,QAAQ,SAAS,MAAK,QAAO,QAAQ,OAAO,aAAY,QAAO,eAAc,SAAQ,gBAAe,SAAQ;AAAA,IACtH,gBAAAA,MAAC,YAAO,IAAI,GAAG,GAAG,SAAS,CAAC,GAAG,IAAI,GAAG,GAAG,SAAS,CAAC,GAAG,GAAE,OAAM,MAAM,OAAO;AAAA,KAC7E;AAEJ;AAEA,IAAM,aAAa;AASZ,IAAM,UAAU,KAAK,SAASE,SAAQ;AAAA,EAC3C;AAAA,EACA;AAAA,EACA,MAAMC;AAAA,EACN;AAAA,EACA;AAAA,EACA,UAAU;AAAA,EACV,UAAU;AAAA,EACV;AAAA,EACA,UAAU;AAAA,EACV;AAAA,EACA;AAAA,EACA,iBAAiB;AAAA,EACjB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAA+B;AAC7B,MAAI,YAAY,QAAQ;AACtB,WACE,gBAAAF;AAAA,MAAC;AAAA;AAAA,QACC,eAAa;AAAA,QACb,WAAU;AAAA,QACV,OAAO;AAAA,UACL,YAAY;AAAA,UACZ,WAAW;AAAA,QACb;AAAA,QAEA;AAAA,0BAAAA,OAAC,SAAI,WAAU,6CACb;AAAA,4BAAAD,MAAC,OAAE,WAAU,mEAAmE,iBAAM;AAAA,YACrFG,SACC,gBAAAH,MAAC,SAAI,WAAU,wFACb,0BAAAA,MAACG,OAAA,EAAK,WAAU,yBAAwB,eAAY,QAAO,GAC7D;AAAA,aAEJ;AAAA,UAEA,gBAAAH,MAAC,SAAI,WAAU,YACZ,oBACC,gBAAAA,MAAC,SAAI,WAAU,iDAAgD,IAE/D,gBAAAA,MAAC,OAAE,WAAU,0FACV,mBAAS,UACZ,GAEJ;AAAA,WAEE,SAAS,eAAe,CAAC,WACzB,gBAAAC,OAAC,SAAI,WAAU,oCACZ;AAAA,qBACC,gBAAAD;AAAA,cAAC;AAAA;AAAA,gBACC,WAAW;AAAA,kBACT;AAAA,kBACA,MAAM,WAAW,yCAAyC;AAAA,gBAC5D;AAAA,gBAEC,gBAAM;AAAA;AAAA,YACT;AAAA,YAED,cAAc,gBAAAA,MAAC,UAAK,WAAU,6BAA6B,sBAAW;AAAA,aACzE;AAAA,UAGD,OAAO,CAAC,WACP,gBAAAA,MAAC,OAAE,WAAU,qEAAqE,eAAI;AAAA,UAGvF,YAAY,QAAQ,CAAC,WACpB,gBAAAC,OAAC,SAAI,WAAU,sCACb;AAAA,4BAAAD,MAAC,SAAI,WAAU,uDACb,0BAAAA,MAAC,SAAI,WAAU,gCAA+B,OAAO,EAAE,OAAO,GAAG,KAAK,IAAI,KAAK,KAAK,IAAI,GAAG,QAAQ,CAAC,CAAC,IAAI,GAAG,GAC9G;AAAA,YACC,iBAAiB,gBAAAA,MAAC,UAAK,WAAU,iEAAiE,yBAAc;AAAA,aACnH;AAAA,UAMD,aAAa,UAAU,SAAS,KAAK,CAAC,WACrC,gBAAAA,MAAC,SAAI,WAAU,kDACb,0BAAAA,MAAC,iBAAc,MAAM,WAAW,OAAM,WAAU,GAClD;AAAA;AAAA;AAAA,IAEJ;AAAA,EAEJ;AAEA,MAAI,YAAY,QAAQ;AACtB,UAAM,WAAWG,QACf,OACE,gBAAAH;AAAA,MAAC;AAAA;AAAA,QACC;AAAA,QACA,WAAU;AAAA,QAEV,0BAAAA,MAACG,OAAA,EAAK,WAAU,6BAA4B,eAAY,QAAO;AAAA;AAAA,IACjE,IAEA,gBAAAH,MAAC,SAAI,WAAU,yGACb,0BAAAA,MAACG,OAAA,EAAK,WAAU,6BAA4B,eAAY,QAAO,GACjE,IAEA;AAEJ,WACE,gBAAAF;AAAA,MAAC;AAAA;AAAA,QACC,eAAa;AAAA,QACb,WAAW;AAAA,UACT;AAAA,UACA,QAAQ;AAAA,QACV;AAAA,QAEA;AAAA,0BAAAA,OAAC,SAAI,WAAW,YACd;AAAA,4BAAAD,MAAC,OAAE,WAAU,2EAA2E,iBAAM;AAAA,YAC7F;AAAA,aACH;AAAA,UAEA,gBAAAA,MAAC,SAAI,WAAU,0CACZ,oBACC,gBAAAA,MAAC,YAAS,WAAU,YAAW,IAE/B,gBAAAC,OAAAF,WAAA,EACE;AAAA,4BAAAC,MAAC,OAAE,WAAU,gLACV,mBAAS,UACZ;AAAA,YACC,SACC,gBAAAA;AAAA,cAAC;AAAA;AAAA,gBACC,WAAW;AAAA,kBACT;AAAA,kBACA,MAAM,WACF,iFACA;AAAA,gBACN;AAAA,gBAEC,gBAAM;AAAA;AAAA,YACT;AAAA,aAEJ,GAEJ;AAAA,WAEE,OAAO,cAAc,CAAC,WACtB,gBAAAC,OAAC,SAAI,WAAU,wCACZ;AAAA,mBACC,gBAAAD;AAAA,cAAC;AAAA;AAAA,gBACC,WAAW;AAAA,kBACT;AAAA,kBACA,YAAY,WACR,iDACA,YAAY,SACV,qDACA;AAAA,gBACR;AAAA,gBAEC;AAAA;AAAA,YACH;AAAA,YAED,aAAa,gBAAAA,MAAC,aAAU,MAAM,WAAW,OAAO,gBAAgB;AAAA,aACnE;AAAA;AAAA;AAAA,IAEJ;AAAA,EAEJ;AAEA,MAAI,YAAY,SAAS;AACvB,UAAM,QAAQ,UAAU,OAAO,CAAC,KAAK,MAAM,MAAM,EAAE,OAAO,CAAC,KAAK;AAEhE,WACE,gBAAAC,OAAC,SAAI,eAAa,QAAQ,WAAU,+CAClC;AAAA,sBAAAA,OAAC,SAAI,WAAW,YACd;AAAA,wBAAAD,MAAC,OAAE,WAAU,2EAA2E,iBAAM;AAAA,QAC7FG,SACC,gBAAAH,MAAC,SAAI,WAAU,0FACb,0BAAAA,MAACG,OAAA,EAAK,WAAU,eAAc,eAAY,QAAO,GACnD;AAAA,SAEJ;AAAA,MAEC,UACC,gBAAAF,OAAC,SAAI,WAAU,gCACb;AAAA,wBAAAD,MAAC,YAAS,WAAU,mCAAkC;AAAA,QACtD,gBAAAC,OAAC,SAAI,WAAU,8BACb;AAAA,0BAAAD,MAAC,YAAS,WAAU,cAAa;AAAA,UACjC,gBAAAA,MAAC,YAAS,WAAU,aAAY;AAAA,UAChC,gBAAAA,MAAC,YAAS,WAAU,aAAY;AAAA,WAClC;AAAA,SACF,IACE,YAAY,SAAS,SAAS,IAChC,gBAAAC,OAAC,SAAI,WAAU,gCACb;AAAA,wBAAAD,MAAC,cAAW,MAAM,UAAU,aAAa,eAAe,OAAO,KAAK,GAAG;AAAA,QACvE,gBAAAA,MAAC,QAAG,WAAU,wCACX,mBAAS,IAAI,CAAC,SAAS,MACtB,gBAAAC,OAAC,QAAuB,WAAU,uCAChC;AAAA,0BAAAD;AAAA,YAAC;AAAA;AAAA,cACC,WAAU;AAAA,cACV,OAAO,EAAE,iBAAiB,QAAQ,SAAS,aAAa,IAAI,aAAa,MAAM,EAAE;AAAA,cACjF,eAAY;AAAA;AAAA,UACd;AAAA,UACA,gBAAAA,MAAC,UAAK,WAAU,iDAAiD,kBAAQ,OAAM;AAAA,UAC/E,gBAAAA,MAAC,UAAK,WAAU,uDACb,kBAAQ,IAAI,GAAG,KAAK,MAAO,QAAQ,QAAQ,QAAS,GAAG,CAAC,MAAM,QAAQ,OACzE;AAAA,aATO,QAAQ,KAUjB,CACD,GACH;AAAA,SACF,IAEA,gBAAAA,MAAC,UAAK,WAAU,2DAA0D,oBAAC;AAAA,MAG5E,OAAO,CAAC,WAAW,gBAAAA,MAAC,OAAE,WAAU,yDAAyD,eAAI;AAAA,OAChG;AAAA,EAEJ;AAIA,QAAM,WAAW,SAAS,OAAO,OAAO,KAAK,IAAI;AACjD,QAAM,QAAQ,WAAW,SAAS,MAAM,QAAQ,IAAI;AACpD,QAAM,QAAQ,CAAC,SAAS,MAAM,WAAW;AACzC,QAAM,WAAW,CAAC,SAAS,MAAM,KAAK,MAAO,CAAC,CAAE,KAAK,MAAO,CAAC,EAAG,UAAU;AAC1E,QAAM,SAAS,WAAW,OAAO,QAAQ,CAAC;AAC1C,QAAM,SAAS,WAAW,MAAO,CAAC,IAAK,QAAQ,CAAC,KAAK,QAAQ,CAAC;AAC9D,QAAM,SAAS,WAAW,MAAO,CAAC,IAAI;AAEtC,SACE,gBAAAC,OAAC,SAAI,eAAa,QAAQ,WAAU,+CAClC;AAAA,oBAAAA,OAAC,SAAI,WAAW,YACd;AAAA,sBAAAD,MAAC,OAAE,WAAU,2EAA2E,iBAAM;AAAA,MAC7FG,SACC,gBAAAH,MAAC,SAAI,WAAU,0FACb,0BAAAA,MAACG,OAAA,EAAK,WAAU,eAAc,eAAY,QAAO,GACnD;AAAA,OAEJ;AAAA,IAEA,gBAAAF,OAAC,SAAI,WAAU,QACZ;AAAA,gBACC,gBAAAD,MAAC,YAAS,WAAU,YAAW,IAC7B,SAAS,OACX,gBAAAA,MAAC,UAAK,WAAU,gDAA+C,oBAAC,IAC9D,QACF,gBAAAA,MAAC,UAAK,WAAU,gIACb,oBACH,IAEA,gBAAAC,OAAC,UAAK,WAAU,uHACb;AAAA,kBAAU,gBAAAA,OAAC,UAAK,WAAU,iCAAiC;AAAA;AAAA,UAAO;AAAA,WAAC;AAAA,QACpE,gBAAAD,MAAC,UAAK,WAAU,YAAY,kBAAO;AAAA,QAClC,UAAU,gBAAAC,OAAC,UAAK,WAAU,iCAAgC;AAAA;AAAA,UAAE;AAAA,WAAO;AAAA,SACtE;AAAA,MAED,OAAO,CAAC,WAAW,gBAAAD,MAAC,OAAE,WAAU,yDAAyD,eAAI;AAAA,OAChG;AAAA,KAEE,SAAS,cAAc,cAAc,CAAC,WACtC,gBAAAC,OAAC,SAAI,WAAU,+CACb;AAAA,sBAAAA,OAAC,SAAI,WAAU,qCACZ;AAAA,iBACC,gBAAAD;AAAA,UAAC;AAAA;AAAA,YACC,WAAW;AAAA,cACT;AAAA,cACA,MAAM,WACF,iFACA;AAAA,YACN;AAAA,YAEC,gBAAM;AAAA;AAAA,QACT;AAAA,QAED,cAAc,gBAAAA,MAAC,UAAK,WAAU,qCAAqC,sBAAW;AAAA,SACjF;AAAA,MACC,aAAa,gBAAAA,MAAC,aAAU,MAAM,WAAW,OAAO,gBAAgB;AAAA,OACnE;AAAA,KAEJ;AAEJ,CAAC;;;ACpbD,SAAS,UAAAI,eAAc;AA2DjB,SAEI,OAAAC,OAFJ,QAAAC,cAAA;AAtBC,SAAS,YAAY;AAAA,EAC1B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,WAAW;AAAA,EACX;AAAA,EACA;AAAA,EACA,GAAG;AACL,GAAmC;AACjC,SACE,gBAAAA;AAAA,IAAC;AAAA;AAAA,MACC,WAAW;AAAA,QACT;AAAA,QACA,WAAW,uCAAuC;AAAA,QAClD;AAAA,MACF;AAAA,MAEA;AAAA,wBAAAA,OAAC,SAAI,WAAU,qCACZ;AAAA,sBACC,gBAAAD,MAAC,kBAAe,MAAK,MAAK,IAE1B,gBAAAA,MAACE,SAAA,EAAO,WAAU,0CAAyC,eAAY,QAAO;AAAA,UAEhF,gBAAAF;AAAA,YAAC;AAAA;AAAA,cACC,KAAK;AAAA,cACL,MAAK;AAAA,cACL;AAAA,cACA,UAAU,CAAC,UAAU,SAAS,MAAM,OAAO,KAAK;AAAA,cAChD,WAAU;AAAA,cACT,GAAG;AAAA;AAAA,UACN;AAAA,UACC;AAAA,UACA,gBACC,gBAAAA;AAAA,YAAC;AAAA;AAAA,cACC,eAAY;AAAA,cACZ,WAAU;AAAA,cAET;AAAA;AAAA,UACH;AAAA,WAEJ;AAAA,QAEC,SAAS,MAAM,SAAS,KACvB,gBAAAA,MAAC,SAAI,WAAU,qCACZ,gBAAM,IAAI,CAAC,EAAE,KAAK,OAAO,MAAMG,MAAK,MACnC,gBAAAF;AAAA,UAAC;AAAA;AAAA,YAEC,MAAK;AAAA,YACL,SAAS,MAAM,eAAe,GAAG;AAAA,YACjC,WAAW;AAAA,cACT;AAAA,cACA,eAAe,MACX,uCACA;AAAA,YACN;AAAA,YAEC;AAAA,cAAAE,SAAQ,gBAAAH,MAACG,OAAA,EAAK,WAAU,eAAc,eAAY,QAAO;AAAA,cACzD;AAAA;AAAA;AAAA,UAXI;AAAA,QAYP,CACD,GACH;AAAA;AAAA;AAAA,EAEJ;AAEJ;;;AC1GA,SAAS,UAAAC,eAAc;AAiBjB,gBAAAC,aAAA;AAHC,SAAS,cAAc,EAAE,QAAQ,UAAU,GAAG,MAAM,GAAqC;AAC9F,SACE,gBAAAA,MAAC,UAAO,MAAK,UAAS,SAAQ,SAAQ,MAAK,QAAO,cAAY,OAAQ,GAAG,OACvE,0BAAAA,MAACC,SAAA,EAAO,WAAU,qBAAoB,eAAY,QAAO,GAC3D;AAEJ;;;ACpBA,SAAS,eAAe,kBAAkB;AAO1C,IAAM,iBAAiB,cAAmC,EAAE,WAAW,MAAM,CAAC;AAEvE,IAAM,yBAAyB,eAAe;AAQ9C,SAAS,sBAA+B;AAC7C,SAAO,WAAW,cAAc,EAAE;AACpC;;;ACyBI,SAaI,OAAAC,OAbJ,QAAAC,cAAA;AAbG,SAAS,QAAqC;AAAA,EACnD;AAAA,EACA,MAAMC;AAAA,EACN;AAAA,EACA,SAAS;AAAA,EACT;AAAA,EACA;AAAA,EACA,GAAG;AACL,GAAkC;AAChC,QAAM,YAAY,oBAAoB;AACtC,QAAM,OAAQ,MAAM;AAEpB,QAAM,MACJ,gBAAAD;AAAA,IAAC;AAAA;AAAA,MACC,WAAW;AAAA,QACT;AAAA,QACA;AAAA,QACA,YAAY,yBAAyB;AAAA,QACrC,SACI,mDACA;AAAA,QACJ;AAAA,MACF;AAAA,MACC,GAAG;AAAA,MAEH;AAAA,QAAAC,SACC,gBAAAF;AAAA,UAACE;AAAA,UAAA;AAAA,YACC,WAAW,GAAG,8BAA8B,SAAS,qBAAqB,uBAAuB;AAAA,YACjG,aAAa,SAAS,IAAI;AAAA,YAC1B,eAAW;AAAA;AAAA,QACb;AAAA,QAEF,gBAAAF;AAAA,UAAC;AAAA;AAAA,YACC,WAAW;AAAA,cACT;AAAA,cACA,YAAY,sBAAsB;AAAA,YACpC;AAAA,YAEC;AAAA;AAAA,QACH;AAAA,QACC,CAAC,aAAa;AAAA;AAAA;AAAA,EACjB;AAGF,MAAI,CAAC,UAAW,QAAO;AAEvB,SACE,gBAAAC,OAAC,WACC;AAAA,oBAAAD,MAAC,kBAAe,SAAO,MAAE,eAAI;AAAA,IAC7B,gBAAAC,OAAC,kBAAe,MAAK,SAAQ,WAAU,6BACpC;AAAA;AAAA,MACA;AAAA,OACH;AAAA,KACF;AAEJ;;;ACtFA,SAAS,eAAAE,oBAAmB;AAC5B,SAAS,YAAAC,kBAAmD;AA6ClD,gBAAAC,OAEA,QAAAC,cAFA;AArBH,SAAS,SAAS;AAAA,EACvB;AAAA,EACA,mBAAmB;AAAA,EACnB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAAgC;AAC9B,QAAM,CAAC,mBAAmB,oBAAoB,IAAIC,WAAS,gBAAgB;AAC3E,QAAM,iBAAiB,aAAa;AACpC,QAAM,gBAAgB,oBAAoB;AAE1C,QAAM,oBAAoB,CAAC,SAAkB;AAC3C,wBAAoB,IAAI;AACxB,QAAI,cAAc,OAAW,sBAAqB,IAAI;AAAA,EACxD;AAEA,SACE,gBAAAD,OAAC,SAAI,WAAW,GAAG,yBAAyB,SAAS,GAClD;AAAA,cACE,gBACC,gBAAAD,MAAC,SAAI,WAAU,+BAA8B,eAAW,MAAC,IAEzD,gBAAAC;AAAA,MAAC;AAAA;AAAA,QACC,MAAK;AAAA,QACL,SAAS,MAAM,kBAAkB,CAAC,cAAc;AAAA,QAChD,iBAAe,CAAC;AAAA,QAChB,WAAU;AAAA,QAEV;AAAA,0BAAAD,MAAC,UAAM,iBAAM;AAAA,UACb,gBAAAA;AAAA,YAACG;AAAA,YAAA;AAAA,cACC,WAAW;AAAA,gBACT;AAAA,gBACA,kBAAkB;AAAA,cACpB;AAAA,cACA,eAAW;AAAA;AAAA,UACb;AAAA;AAAA;AAAA,IACF;AAAA,IAEH,CAAC,kBAAkB,gBAAAH,MAAC,SAAI,WAAU,yBAAyB,UAAS;AAAA,KACvE;AAEJ;;;ACnEA,SAAS,gBAAgB,qBAAqB;AAC9C;AAAA,EACE;AAAA,EACA,aAAAI;AAAA,EACA,UAAAC;AAAA,EACA,YAAAC;AAAA,OAKK;AA8GS,SAiBA,YAAAC,WAVI,OAAAC,OAPJ,QAAAC,cAAA;AAzGhB,SAAS,QAAW,OAAwC,WAAuB;AACjF,SAAO,OAAO,UAAU,aAAc,MAAoC,SAAS,IAAI;AACzF;AAqCO,SAAS,QAAQ;AAAA,EACtB,YAAY;AAAA,EACZ;AAAA,EACA,YAAY;AAAA,EACZ;AAAA,EACA;AAAA,EACA,eAAe;AAAA,EACf,WAAW;AAAA,EACX,WAAW;AAAA,EACX,YAAY;AAAA,EACZ;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAA+B;AAC7B,QAAM,CAAC,eAAe,gBAAgB,IAAIC,WAAS,YAAY;AAC/D,QAAM,eAAe,SAAS;AAC9B,QAAM,CAAC,YAAY,aAAa,IAAIA,WAAS,KAAK;AAElD,QAAM,WAAW;AAAA,IACf,CAAC,SAAiB;AAChB,YAAM,UAAU,KAAK,IAAI,UAAU,KAAK,IAAI,UAAU,IAAI,CAAC;AAC3D,sBAAgB,OAAO;AACvB,UAAI,UAAU,OAAW,kBAAiB,OAAO;AAAA,IACnD;AAAA,IACA,CAAC,UAAU,UAAU,eAAe,KAAK;AAAA,EAC3C;AAEA,QAAM,eAAeC,QAA4C,IAAI;AAErE,QAAM,oBAAoB,CAAC,UAA6C;AACtE,UAAM,cAAc,kBAAkB,MAAM,SAAS;AACrD,iBAAa,UAAU,EAAE,GAAG,MAAM,SAAS,OAAO,aAAa;AAC/D,kBAAc,IAAI;AAAA,EACpB;AACA,QAAM,oBAAoB,CAAC,UAA6C;AACtE,QAAI,CAAC,aAAa,QAAS;AAC3B,aAAS,aAAa,QAAQ,SAAS,MAAM,UAAU,aAAa,QAAQ,EAAE;AAAA,EAChF;AACA,QAAM,UAAU,CAAC,UAA6C;AAC5D,QAAI,MAAM,cAAc,kBAAkB,MAAM,SAAS,GAAG;AAC1D,YAAM,cAAc,sBAAsB,MAAM,SAAS;AAAA,IAC3D;AACA,iBAAa,UAAU;AACvB,kBAAc,KAAK;AAAA,EACrB;AAEA,SACE,gBAAAH,MAAC,0BAAuB,OAAO,EAAE,UAAU,GACzC,0BAAAA,MAAC,mBAAgB,eAAe,KAC9B,0BAAAC;AAAA,IAAC;AAAA;AAAA,MACC,OAAO,EAAE,OAAO,YAAY,YAAY,aAAa;AAAA,MACrD,WAAW;AAAA,QACT;AAAA,QACA,CAAC,cAAc;AAAA,QACf;AAAA,MACF;AAAA,MAEE;AAAA,mBAAU,sBACV,gBAAAD,MAAC,SAAI,WAAU,4DACZ,uBAAa;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,UAMZ,gBAAAC;AAAA,YAAC;AAAA;AAAA,cACC,MAAK;AAAA,cACL,SAAS,MAAM,kBAAkB,CAAC,SAAS;AAAA,cAC3C,cAAW;AAAA,cACX,WAAU;AAAA,cAET;AAAA,0BACC,gBAAAD,MAAC,UAAK,WAAU,4CACb,kBAAQ,QAAQ,SAAS,GAC5B;AAAA,gBAEF,gBAAAA;AAAA,kBAAC;AAAA;AAAA,oBACC,WAAU;AAAA,oBACV,eAAW;AAAA;AAAA,gBACb;AAAA;AAAA;AAAA,UACF;AAAA,YAEA,gBAAAC,OAAAF,WAAA,EACG;AAAA,oBAAU,gBAAAC,MAAC,SAAI,WAAU,kBAAkB,kBAAQ,QAAQ,SAAS,GAAE;AAAA,UACtE,qBACC,gBAAAA;AAAA,YAAC;AAAA;AAAA,cACC,MAAK;AAAA,cACL,SAAS,MAAM,kBAAkB,CAAC,SAAS;AAAA,cAC3C,cAAW;AAAA,cACX,WAAU;AAAA,cAEV,0BAAAA,MAAC,kBAAe,WAAU,WAAU,eAAW,MAAC;AAAA;AAAA,UAClD;AAAA,WAEJ,GAEJ;AAAA,QAGF,gBAAAA,MAAC,cAAY,UAAS;AAAA,QAErB,UAAU,gBAAAA,MAAC,SAAI,WAAU,uCAAuC,kBAAQ,QAAQ,SAAS,GAAE;AAAA,QAE3F,aAAa,CAAC,aACb,gBAAAA;AAAA,UAAC;AAAA;AAAA,YACC,eAAe;AAAA,YACf,eAAe;AAAA,YACf,aAAa;AAAA,YACb,eAAe,MAAM,SAAS,YAAY;AAAA,YAC1C,WAAU;AAAA;AAAA,QACZ;AAAA;AAAA;AAAA,EAEJ,GACF,GACF;AAEJ;AAeO,SAAS,WAAW,EAAE,UAAU,WAAW,GAAG,KAAK,GAAkC;AAC1F,QAAM,MAAMG,QAAuB,IAAI;AACvC,QAAM,CAAC,UAAU,WAAW,IAAID,WAAS,KAAK;AAE9C,EAAAE,WAAU,MAAM;AACd,UAAM,KAAK,IAAI;AACf,QAAI,CAAC,GAAI;AACT,UAAM,SAAS,MAAM,YAAY,GAAG,eAAe,GAAG,YAAY,GAAG,eAAe,CAAC;AACrF,WAAO;AACP,OAAG,iBAAiB,UAAU,MAAM;AACpC,UAAM,WAAW,IAAI,eAAe,MAAM;AAC1C,aAAS,QAAQ,EAAE;AACnB,WAAO,MAAM;AACX,SAAG,oBAAoB,UAAU,MAAM;AACvC,eAAS,WAAW;AAAA,IACtB;AAAA,EACF,GAAG,CAAC,CAAC;AAEL,SACE,gBAAAH,OAAC,SAAI,WAAU,yCACb;AAAA,oBAAAD;AAAA,MAAC;AAAA;AAAA,QACC;AAAA,QACA,WAAW,GAAG,wDAAwD,SAAS;AAAA,QAC9E,GAAG;AAAA,QAEH;AAAA;AAAA,IACH;AAAA,IACC,YACC,gBAAAA;AAAA,MAAC;AAAA;AAAA,QACC,WAAU;AAAA,QACV,eAAW;AAAA;AAAA,IACb;AAAA,KAEJ;AAEJ;;;AC7NA,SAAS,aAAAK,YAAW,UAAAC,eAAc;AAClC,SAAS,SAAAC,QAAO,YAAY;AAqFV,SAwBY,OAAAC,OAxBZ,QAAAC,cAAA;AApCX,SAAS,QAAQ;AAAA,EACtB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,WAAW;AAAA,EACX,WAAW;AAAA,EACX,eAAe;AAAA,EACf;AACF,GAAiB;AACf,QAAM,WAAWC,QAAO,oBAAI,IAA+B,CAAC;AAE5D,EAAAC,WAAU,MAAM;AACd,UAAM,aAAa,SAAS,QAAQ,IAAI,IAAI;AAC5C,gBAAY,eAAe,EAAE,OAAO,WAAW,QAAQ,SAAS,CAAC;AAAA,EACnE,GAAG,CAAC,IAAI,CAAC;AAET;AAAA;AAAA;AAAA;AAAA,IAIE,gBAAAF,OAAC,SAAI,WAAU,2CACb;AAAA,sBAAAD,MAAC,SAAI,cAAY,UAAU,WAAU,kBACnC,0BAAAA;AAAA,QAAC;AAAA;AAAA,UACC,eAAa;AAAA,UACb,WAAU;AAAA,UAEV,0BAAAA,MAAC,QAAG,WAAU,yCACX,gBAAM,IAAI,CAAC,EAAE,GAAG,OAAO,MAAM,GAAG,MAAM;AACrC,kBAAM,OAAO,OAAO;AACpB,kBAAM,SAAS,SAAS;AACxB,kBAAM,YAAY,KAAK,WAAW,MAAM;AACxC,kBAAM,OAAO,MAAM,MAAM,SAAS;AAClC,mBACE,gBAAAC,OAAC,QAAW,WAAW,GAAG,oBAAoB,CAAC,QAAQ,QAAQ,GAC7D;AAAA,8BAAAA;AAAA,gBAAC;AAAA;AAAA,kBACC,KAAK,CAAC,YAAY;AAChB,wBAAI,QAAS,UAAS,QAAQ,IAAI,GAAG,OAAO;AAAA,wBACvC,UAAS,QAAQ,OAAO,CAAC;AAAA,kBAChC;AAAA,kBACA,eAAa,QAAQ,CAAC;AAAA,kBACtB,iBAAe,CAAC;AAAA,kBAChB,gBAAc,SAAS,SAAS;AAAA,kBAChC,SAAS,MAAM,aAAa,WAAW,CAAC;AAAA,kBACxC,WAAW;AAAA,oBACT;AAAA,oBACA,YAAY,oCAAoC;AAAA,kBAClD;AAAA,kBAEA;AAAA,oCAAAD;AAAA,sBAAC;AAAA;AAAA,wBACC,WAAW;AAAA,0BACT;AAAA,0BACA,OACI,+BACA,SACE,uCACA;AAAA,wBACR;AAAA,wBAEC,iBAAO,gBAAAA,MAACI,QAAA,EAAM,WAAU,WAAU,IAAK;AAAA;AAAA,oBAC1C;AAAA,oBACA,gBAAAJ;AAAA,sBAAC;AAAA;AAAA,wBACC,WAAW;AAAA,0BACT;AAAA,0BACA,SACI,8CACA,OACE,yCACA;AAAA,wBACR;AAAA,wBAEC;AAAA;AAAA,oBACH;AAAA,oBACA,gBAAAA,MAAC,UAAK,WAAU,kEACb,iBACH;AAAA;AAAA;AAAA,cACF;AAAA,cACC,CAAC,QACA,gBAAAA;AAAA,gBAAC;AAAA;AAAA,kBACC,WAAW;AAAA,oBACT;AAAA,oBACA,OAAO,eAAe;AAAA,kBACxB;AAAA;AAAA,cACF;AAAA,iBAjDK,CAmDT;AAAA,UAEJ,CAAC,GACH;AAAA;AAAA,MACF,GACF;AAAA,MACC,SACC,gBAAAC;AAAA,QAAC;AAAA;AAAA,UACC,eAAa;AAAA,UACb,SAAS;AAAA,UACT,OAAO;AAAA,UACP,WAAU;AAAA,UAEV;AAAA,4BAAAD,MAAC,QAAK,WAAU,eAAc;AAAA,YAC7B;AAAA;AAAA;AAAA,MACH;AAAA,OAEJ;AAAA;AAEJ;","names":["forwardRef","jsx","forwardRef","forwardRef","jsx","forwardRef","forwardRef","jsx","forwardRef","jsx","cva","jsx","cva","forwardRef","jsx","forwardRef","forwardRef","jsx","forwardRef","forwardRef","jsx","jsxs","forwardRef","jsx","Check","forwardRef","jsx","forwardRef","Check","forwardRef","jsx","forwardRef","forwardRef","jsx","forwardRef","forwardRef","jsx","forwardRef","forwardRef","jsx","jsxs","forwardRef","forwardRef","jsx","forwardRef","Check","forwardRef","jsx","jsxs","forwardRef","Check","cva","DialogPrimitive","X","forwardRef","jsx","jsxs","forwardRef","cva","X","forwardRef","jsx","forwardRef","jsx","jsxs","useState","useState","Fragment","jsx","jsxs","useState","jsx","useState","useState","jsx","jsxs","useState","useRef","useState","useEffect","useState","jsx","jsxs","useState","useRef","next","useState","jsx","useState","jsx","jsxs","Check","X","useEffect","useRef","useState","jsx","jsxs","jsx","jsxs","useState","useRef","useEffect","Check","X","X","useEffect","useMemo","useRef","useState","jsx","jsxs","useState","useRef","useMemo","useEffect","X","jsx","jsxs","jsx","jsx","jsxs","Icon","cva","jsx","jsxs","cva","X","jsx","jsxs","X","Fragment","jsx","jsxs","KpiCard","Icon","Search","jsx","jsxs","Search","Icon","Search","jsx","Search","jsx","jsxs","Icon","ChevronDown","useState","jsx","jsxs","useState","ChevronDown","useEffect","useRef","useState","Fragment","jsx","jsxs","useState","useRef","useEffect","useEffect","useRef","Check","jsx","jsxs","useRef","useEffect","Check"]}
1
+ {"version":3,"sources":["../src/primitives/button.tsx","../src/lib/utils.ts","../src/primitives/input.tsx","../src/primitives/label.tsx","../src/primitives/textarea.tsx","../src/primitives/card.tsx","../src/primitives/badge.tsx","../src/primitives/dialog.tsx","../src/primitives/popover.tsx","../src/primitives/select.tsx","../src/primitives/skeleton.tsx","../src/primitives/checkbox.tsx","../src/primitives/switch.tsx","../src/primitives/tabs.tsx","../src/primitives/separator.tsx","../src/primitives/scroll-area.tsx","../src/primitives/table.tsx","../src/primitives/dropdown-menu.tsx","../src/primitives/sheet.tsx","../src/primitives/tooltip.tsx","../src/patterns/modal/Modal.tsx","../src/patterns/modal/ConfirmDialog.tsx","../src/patterns/modal/DialogActions.tsx","../src/lib/platform.ts","../src/patterns/modal/FormModal.tsx","../src/patterns/modal/ResponsivePanel.tsx","../src/lib/useMediaQuery.ts","../src/patterns/modal/QuestionDialog.tsx","../src/patterns/form-field/FormField.tsx","../src/patterns/combobox/Combobox.tsx","../src/lib/optionGrouping.ts","../src/lib/optionGrid.tsx","../src/patterns/tag-combobox/TagCombobox.tsx","../src/patterns/alert-box/AlertBox.tsx","../src/patterns/status-badge/StatusBadge.tsx","../src/patterns/button-group/ButtonGroup.tsx","../src/patterns/loading-spinner/LoadingSpinner.tsx","../src/patterns/search-bar/SearchBar.tsx","../src/patterns/kpi-card/KpiCard.tsx","../src/patterns/search-panel/SearchPanel.tsx","../src/patterns/search-panel/SearchTrigger.tsx","../src/patterns/sidebar/context.ts","../src/patterns/sidebar/NavItem.tsx","../src/patterns/sidebar/NavGroup.tsx","../src/patterns/sidebar/Sidebar.tsx","../src/patterns/ai/AiButton.tsx","../src/patterns/ai/AiExplainButton.tsx","../src/patterns/ai/VoiceInputButton.tsx","../src/patterns/ai/useSpeechRecognition.ts","../src/patterns/ai/VoiceTranscript.tsx","../src/patterns/stepper/Stepper.tsx"],"sourcesContent":["import { Slot } from \"@radix-ui/react-slot\";\nimport { type VariantProps, cva } from \"class-variance-authority\";\nimport type { ButtonHTMLAttributes } from \"react\";\nimport { forwardRef } from \"react\";\nimport { cn } from \"../lib/utils\";\n\nexport const buttonVariants = cva(\n \"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0\",\n {\n variants: {\n variant: {\n default: \"bg-primary text-primary-foreground hover:bg-primary/90\",\n outline: \"border border-input bg-background hover:bg-accent hover:text-accent-foreground\",\n ghost: \"hover:bg-accent hover:text-accent-foreground\",\n destructive: \"bg-destructive text-destructive-foreground hover:bg-destructive/90\",\n secondary: \"bg-muted text-muted-foreground hover:bg-muted/80\",\n link: \"text-primary underline-offset-4 hover:underline\",\n // \"Swiss design\" red CTA, ported from akeneo_editor's old .btn-primary-swiss\n // naive-ui override. Relies on --color-swiss-primary/-hover and\n // --color-swiss-primary-foreground tokens defined by the consuming app's own\n // Tailwind theme (this package doesn't define them) — same pattern as AlertBox's\n // warning/info/success colors, which assume tokens the shared theme doesn't have.\n \"swiss-primary\":\n \"bg-swiss-primary text-swiss-primary-foreground font-semibold shadow-sm hover:bg-swiss-primary-hover hover:-translate-y-px active:translate-y-px\",\n \"swiss-secondary\":\n \"border border-input bg-background font-semibold text-foreground shadow-sm hover:bg-accent hover:-translate-y-px active:translate-y-px\",\n // Violet \"AI action\" accent, in the same three weights as default/outline/ghost.\n // Fixed Tailwind palette rather than a token — same choice as Badge's `warning`\n // and AlertBox/StatusBadge's warning/info/success tones: the shared theme has no\n // `ai` color, and unlike `swiss-primary` these should work in a consuming app with\n // zero setup. Tints go through `violet-500/N` (not per-mode `violet-50`/`-950`\n // shades) so one class list reads correctly on both light and dark surfaces.\n ai: \"bg-violet-600 text-white shadow-sm hover:bg-violet-600/90\",\n \"ai-subtle\":\n \"border border-violet-500/30 bg-violet-500/10 text-violet-700 hover:bg-violet-500/20 dark:text-violet-300\",\n \"ai-ghost\": \"text-violet-700 hover:bg-violet-500/10 dark:text-violet-300\",\n },\n size: {\n default: \"h-9 px-3\",\n xs: \"h-7 px-2 text-xs\",\n sm: \"h-8 px-2 text-xs\",\n lg: \"h-10 px-4\",\n icon: \"h-9 w-9\",\n \"icon-xs\": \"h-7 w-7\",\n \"icon-sm\": \"h-8 w-8\",\n \"icon-lg\": \"h-10 w-10\",\n },\n },\n defaultVariants: {\n variant: \"default\",\n size: \"default\",\n },\n },\n);\n\nexport interface ButtonProps\n extends ButtonHTMLAttributes<HTMLButtonElement>,\n VariantProps<typeof buttonVariants> {\n asChild?: boolean;\n}\n\nexport const Button = forwardRef<HTMLButtonElement, ButtonProps>(\n ({ className, variant, size, asChild = false, ...props }, ref) => {\n const Comp = asChild ? Slot : \"button\";\n return (\n <Comp className={cn(buttonVariants({ variant, size, className }))} ref={ref} {...props} />\n );\n },\n);\nButton.displayName = \"Button\";\n","import { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\n/** Merges conditional class names, then dedupes conflicting Tailwind utility classes. */\nexport function cn(...inputs: ClassValue[]): string {\n return twMerge(clsx(inputs));\n}\n","import type { InputHTMLAttributes } from \"react\";\nimport { forwardRef } from \"react\";\nimport { cn } from \"../lib/utils\";\n\nexport type InputProps = InputHTMLAttributes<HTMLInputElement>;\n\nexport const Input = forwardRef<HTMLInputElement, InputProps>(({ className, type, ...props }, ref) => {\n return (\n <input\n type={type}\n className={cn(\n \"flex h-9 w-full min-w-0 rounded-md border border-input bg-transparent px-3 py-1 text-sm shadow-sm transition-colors selection:bg-primary selection:text-primary-foreground file:inline-flex file:h-7 file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50\",\n className,\n )}\n ref={ref}\n {...props}\n />\n );\n});\nInput.displayName = \"Input\";\n","import type { LabelHTMLAttributes } from \"react\";\nimport { forwardRef } from \"react\";\nimport { cn } from \"../lib/utils\";\n\nexport const Label = forwardRef<HTMLLabelElement, LabelHTMLAttributes<HTMLLabelElement>>(\n ({ className, ...props }, ref) => (\n <label\n ref={ref}\n className={cn(\n \"text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70\",\n className,\n )}\n {...props}\n />\n ),\n);\nLabel.displayName = \"Label\";\n","import type { TextareaHTMLAttributes } from \"react\";\nimport { forwardRef } from \"react\";\nimport { cn } from \"../lib/utils\";\n\nexport type TextareaProps = TextareaHTMLAttributes<HTMLTextAreaElement>;\n\nexport const Textarea = forwardRef<HTMLTextAreaElement, TextareaProps>(\n ({ className, ...props }, ref) => (\n <textarea\n className={cn(\n \"flex min-h-16 w-full rounded-md border border-input bg-transparent px-3 py-2 text-sm shadow-sm transition-colors placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50\",\n className,\n )}\n ref={ref}\n {...props}\n />\n ),\n);\nTextarea.displayName = \"Textarea\";\n","import type { HTMLAttributes, ReactElement } from \"react\";\nimport { cn } from \"../lib/utils\";\n\n// Deliberately uses bg-background/text-foreground rather than shadcn's usual\n// bg-card/text-card-foreground tokens: the reference consumer app's actual\n// token set (which this package's demo/theme mirrors) has no --card token,\n// and adding one just for this component would be a second, redundant\n// \"surface\" token to keep in sync.\nexport const Card = ({ className, ...props }: HTMLAttributes<HTMLDivElement>): ReactElement => (\n <div className={cn(\"rounded-lg border bg-background text-foreground shadow-sm\", className)} {...props} />\n);\n\nexport const CardHeader = ({\n className,\n ...props\n}: HTMLAttributes<HTMLDivElement>): ReactElement => (\n <div className={cn(\"flex flex-col gap-1.5 p-6\", className)} {...props} />\n);\n\nexport const CardTitle = ({ className, ...props }: HTMLAttributes<HTMLDivElement>): ReactElement => (\n <div className={cn(\"text-lg font-semibold leading-none tracking-tight\", className)} {...props} />\n);\n\nexport const CardDescription = ({\n className,\n ...props\n}: HTMLAttributes<HTMLDivElement>): ReactElement => (\n <div className={cn(\"text-sm text-muted-foreground\", className)} {...props} />\n);\n\nexport const CardContent = ({\n className,\n ...props\n}: HTMLAttributes<HTMLDivElement>): ReactElement => <div className={cn(\"p-6 pt-0\", className)} {...props} />;\n\nexport const CardFooter = ({\n className,\n ...props\n}: HTMLAttributes<HTMLDivElement>): ReactElement => (\n <div className={cn(\"flex items-center gap-2 p-6 pt-0\", className)} {...props} />\n);\n","import { type VariantProps, cva } from \"class-variance-authority\";\nimport type { HTMLAttributes, ReactElement } from \"react\";\nimport { cn } from \"../lib/utils\";\n\nexport const badgeVariants = cva(\n \"inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-medium transition-colors focus:outline-none focus:ring-2 focus:ring-ring\",\n {\n variants: {\n variant: {\n default: \"border-transparent bg-primary text-primary-foreground\",\n secondary: \"border-transparent bg-muted text-muted-foreground\",\n destructive: \"border-transparent bg-destructive text-destructive-foreground\",\n outline: \"border-input text-foreground\",\n // Amber warning tone — same fixed-palette choice as AlertBox/StatusBadge's\n // warning tone, since the shared theme has no warning token yet.\n warning: \"border-transparent bg-amber-100 text-amber-900 dark:bg-amber-900/40 dark:text-amber-200\",\n },\n },\n defaultVariants: {\n variant: \"default\",\n },\n },\n);\n\nexport interface BadgeProps extends HTMLAttributes<HTMLDivElement>, VariantProps<typeof badgeVariants> {}\n\nexport const Badge = ({ className, variant, ...props }: BadgeProps): ReactElement => (\n <div className={cn(badgeVariants({ variant }), className)} {...props} />\n);\n","import * as DialogPrimitive from \"@radix-ui/react-dialog\";\nimport { X } from \"lucide-react\";\nimport type { ComponentPropsWithoutRef, ElementRef, HTMLAttributes, ReactElement } from \"react\";\nimport { forwardRef } from \"react\";\nimport { cn } from \"../lib/utils\";\n\nexport const Dialog = DialogPrimitive.Root;\nexport const DialogTrigger = DialogPrimitive.Trigger;\n\nexport const DialogOverlay = forwardRef<\n ElementRef<typeof DialogPrimitive.Overlay>,\n ComponentPropsWithoutRef<typeof DialogPrimitive.Overlay>\n>(({ className, ...props }, ref) => (\n <DialogPrimitive.Overlay\n ref={ref}\n className={cn(\"fixed inset-0 z-50 bg-black/50\", className)}\n {...props}\n />\n));\nDialogOverlay.displayName = \"DialogOverlay\";\n\nexport const DialogContent = forwardRef<\n ElementRef<typeof DialogPrimitive.Content>,\n ComponentPropsWithoutRef<typeof DialogPrimitive.Content> & {\n showCloseButton?: boolean;\n /** data-testid for the built-in header close button, since it renders no DOM a caller controls directly. */\n closeButtonTestId?: string;\n }\n>(({ className, children, showCloseButton = true, closeButtonTestId, ...props }, ref) => (\n <DialogPrimitive.Portal>\n <DialogOverlay />\n <DialogPrimitive.Content\n ref={ref}\n className={cn(\n \"fixed left-1/2 top-1/2 z-50 max-h-[85vh] w-full max-w-md -translate-x-1/2 -translate-y-1/2 overflow-y-auto rounded-lg border bg-background p-6 shadow-lg\",\n className,\n )}\n {...props}\n >\n {children}\n {showCloseButton ? (\n <DialogPrimitive.Close\n data-testid={closeButtonTestId}\n className=\"absolute right-4 top-4 rounded-sm opacity-70 hover:opacity-100\"\n >\n <X className=\"h-4 w-4\" />\n <span className=\"sr-only\">Close</span>\n </DialogPrimitive.Close>\n ) : null}\n </DialogPrimitive.Content>\n </DialogPrimitive.Portal>\n));\nDialogContent.displayName = \"DialogContent\";\n\nexport const DialogHeader = ({\n className,\n ...props\n}: HTMLAttributes<HTMLDivElement>): ReactElement => (\n <div className={cn(\"flex flex-col gap-1.5\", className)} {...props} />\n);\n\nexport const DialogTitle = forwardRef<\n ElementRef<typeof DialogPrimitive.Title>,\n ComponentPropsWithoutRef<typeof DialogPrimitive.Title>\n>(({ className, ...props }, ref) => (\n <DialogPrimitive.Title ref={ref} className={cn(\"text-lg font-semibold\", className)} {...props} />\n));\nDialogTitle.displayName = \"DialogTitle\";\n\nexport const DialogDescription = forwardRef<\n ElementRef<typeof DialogPrimitive.Description>,\n ComponentPropsWithoutRef<typeof DialogPrimitive.Description>\n>(({ className, ...props }, ref) => (\n <DialogPrimitive.Description\n ref={ref}\n className={cn(\"text-sm text-muted-foreground\", className)}\n {...props}\n />\n));\nDialogDescription.displayName = \"DialogDescription\";\n\nexport const DialogFooter = ({\n className,\n ...props\n}: HTMLAttributes<HTMLDivElement>): ReactElement => (\n <div className={cn(\"mt-4 flex justify-end gap-2\", className)} {...props} />\n);\n","import * as PopoverPrimitive from \"@radix-ui/react-popover\";\nimport type { ComponentPropsWithoutRef, ElementRef } from \"react\";\nimport { forwardRef } from \"react\";\nimport { cn } from \"../lib/utils\";\n\nexport const Popover = PopoverPrimitive.Root;\nexport const PopoverTrigger = PopoverPrimitive.Trigger;\nexport const PopoverAnchor = PopoverPrimitive.Anchor;\n\nexport const PopoverContent = forwardRef<\n ElementRef<typeof PopoverPrimitive.Content>,\n ComponentPropsWithoutRef<typeof PopoverPrimitive.Content> & {\n /** Portal target for the popover content. Defaults to `document.body` (Radix's\n * own default) when omitted. Needed when the popover is opened from inside a\n * modal Dialog/Sheet: Radix's Dialog `FocusScope` traps focus within its own\n * content subtree, and a popover portaled to `document.body` sits outside that\n * subtree — so pass the Dialog/Sheet content element here to portal into it\n * instead. */\n container?: ComponentPropsWithoutRef<typeof PopoverPrimitive.Portal>[\"container\"];\n }\n>(({ className, align = \"start\", sideOffset = 4, container, ...props }, ref) => (\n <PopoverPrimitive.Portal container={container}>\n <PopoverPrimitive.Content\n ref={ref}\n align={align}\n sideOffset={sideOffset}\n className={cn(\n \"z-50 w-72 rounded-md border bg-popover p-4 text-popover-foreground shadow-md outline-none\",\n className,\n )}\n {...props}\n />\n </PopoverPrimitive.Portal>\n));\nPopoverContent.displayName = \"PopoverContent\";\n","import * as SelectPrimitive from \"@radix-ui/react-select\";\nimport { Check, ChevronDown } from \"lucide-react\";\nimport type { ComponentPropsWithoutRef, ElementRef } from \"react\";\nimport { forwardRef } from \"react\";\nimport { cn } from \"../lib/utils\";\n\nexport const Select = SelectPrimitive.Root;\nexport const SelectGroup = SelectPrimitive.Group;\nexport const SelectValue = SelectPrimitive.Value;\n\nexport interface SelectTriggerProps extends ComponentPropsWithoutRef<typeof SelectPrimitive.Trigger> {\n size?: \"sm\" | \"default\";\n}\n\nexport const SelectTrigger = forwardRef<ElementRef<typeof SelectPrimitive.Trigger>, SelectTriggerProps>(\n ({ className, children, size = \"default\", ...props }, ref) => (\n <SelectPrimitive.Trigger\n ref={ref}\n className={cn(\n \"flex w-full items-center justify-between whitespace-nowrap rounded-md border border-input bg-transparent px-3 py-1 text-sm shadow-sm focus:outline-none focus:ring-1 focus:ring-ring disabled:cursor-not-allowed disabled:opacity-50\",\n size === \"sm\" ? \"h-8\" : \"h-9\",\n className,\n )}\n {...props}\n >\n {children}\n <SelectPrimitive.Icon asChild>\n <ChevronDown className=\"h-4 w-4 opacity-50\" />\n </SelectPrimitive.Icon>\n </SelectPrimitive.Trigger>\n ),\n);\nSelectTrigger.displayName = \"SelectTrigger\";\n\nexport const SelectContent = forwardRef<\n ElementRef<typeof SelectPrimitive.Content>,\n ComponentPropsWithoutRef<typeof SelectPrimitive.Content>\n>(({ className, children, position = \"popper\", ...props }, ref) => (\n <SelectPrimitive.Portal>\n <SelectPrimitive.Content\n ref={ref}\n position={position}\n className={cn(\n \"relative z-50 max-h-96 min-w-[8rem] overflow-hidden rounded-md border bg-popover text-popover-foreground shadow-md\",\n position === \"popper\" && \"translate-y-1\",\n className,\n )}\n {...props}\n >\n <SelectPrimitive.Viewport className=\"p-1\">{children}</SelectPrimitive.Viewport>\n </SelectPrimitive.Content>\n </SelectPrimitive.Portal>\n));\nSelectContent.displayName = \"SelectContent\";\n\nexport const SelectItem = forwardRef<\n ElementRef<typeof SelectPrimitive.Item>,\n ComponentPropsWithoutRef<typeof SelectPrimitive.Item>\n>(({ className, children, ...props }, ref) => (\n <SelectPrimitive.Item\n ref={ref}\n className={cn(\n \"relative flex w-full cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50\",\n className,\n )}\n {...props}\n >\n <span className=\"absolute left-2 flex h-3.5 w-3.5 items-center justify-center\">\n <SelectPrimitive.ItemIndicator>\n <Check className=\"h-4 w-4\" />\n </SelectPrimitive.ItemIndicator>\n </span>\n <SelectPrimitive.ItemText>{children}</SelectPrimitive.ItemText>\n </SelectPrimitive.Item>\n));\nSelectItem.displayName = \"SelectItem\";\n","import type { HTMLAttributes, ReactElement } from \"react\";\nimport { cn } from \"../lib/utils\";\n\nexport const Skeleton = ({ className, ...props }: HTMLAttributes<HTMLDivElement>): ReactElement => (\n <div className={cn(\"animate-pulse rounded-md bg-muted\", className)} {...props} />\n);\n","import * as CheckboxPrimitive from \"@radix-ui/react-checkbox\";\nimport { Check } from \"lucide-react\";\nimport type { ComponentPropsWithoutRef, ElementRef } from \"react\";\nimport { forwardRef } from \"react\";\nimport { cn } from \"../lib/utils\";\n\nexport const Checkbox = forwardRef<\n ElementRef<typeof CheckboxPrimitive.Root>,\n ComponentPropsWithoutRef<typeof CheckboxPrimitive.Root>\n>(({ className, ...props }, ref) => (\n <CheckboxPrimitive.Root\n ref={ref}\n className={cn(\n \"peer h-4 w-4 shrink-0 rounded-sm border border-input shadow focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground data-[state=checked]:border-primary\",\n className,\n )}\n {...props}\n >\n <CheckboxPrimitive.Indicator className=\"flex items-center justify-center text-current\">\n <Check className=\"h-3.5 w-3.5\" />\n </CheckboxPrimitive.Indicator>\n </CheckboxPrimitive.Root>\n));\nCheckbox.displayName = \"Checkbox\";\n","import * as SwitchPrimitive from \"@radix-ui/react-switch\";\nimport type { ComponentPropsWithoutRef, ElementRef } from \"react\";\nimport { forwardRef } from \"react\";\nimport { cn } from \"../lib/utils\";\n\nexport interface SwitchProps extends ComponentPropsWithoutRef<typeof SwitchPrimitive.Root> {\n size?: \"sm\" | \"default\";\n}\n\nexport const Switch = forwardRef<ElementRef<typeof SwitchPrimitive.Root>, SwitchProps>(\n ({ className, size = \"default\", ...props }, ref) => (\n <SwitchPrimitive.Root\n ref={ref}\n className={cn(\n \"peer inline-flex shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=unchecked]:bg-input\",\n size === \"sm\" ? \"h-3.5 w-6\" : \"h-5 w-9\",\n className,\n )}\n {...props}\n >\n <SwitchPrimitive.Thumb\n className={cn(\n \"pointer-events-none block rounded-full bg-background shadow-lg ring-0 transition-transform data-[state=unchecked]:translate-x-0\",\n size === \"sm\"\n ? \"h-3 w-3 data-[state=checked]:translate-x-2.5\"\n : \"h-4 w-4 data-[state=checked]:translate-x-4\",\n )}\n />\n </SwitchPrimitive.Root>\n ),\n);\nSwitch.displayName = \"Switch\";\n","import * as TabsPrimitive from \"@radix-ui/react-tabs\";\nimport type { ComponentPropsWithoutRef, ElementRef } from \"react\";\nimport { forwardRef } from \"react\";\nimport { cn } from \"../lib/utils\";\n\nexport const Tabs = TabsPrimitive.Root;\n\nexport const TabsList = forwardRef<\n ElementRef<typeof TabsPrimitive.List>,\n ComponentPropsWithoutRef<typeof TabsPrimitive.List>\n>(({ className, ...props }, ref) => (\n <TabsPrimitive.List\n ref={ref}\n className={cn(\n \"inline-flex h-9 w-fit items-center justify-center rounded-lg bg-muted p-[3px] text-muted-foreground\",\n className,\n )}\n {...props}\n />\n));\nTabsList.displayName = \"TabsList\";\n\nexport const TabsTrigger = forwardRef<\n ElementRef<typeof TabsPrimitive.Trigger>,\n ComponentPropsWithoutRef<typeof TabsPrimitive.Trigger>\n>(({ className, ...props }, ref) => (\n <TabsPrimitive.Trigger\n ref={ref}\n className={cn(\n \"inline-flex h-[calc(100%-1px)] flex-1 items-center justify-center gap-1.5 whitespace-nowrap rounded-md border border-transparent px-2 py-1 text-sm font-medium text-foreground/60 transition-all hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 data-[state=active]:bg-background data-[state=active]:text-foreground data-[state=active]:shadow-sm\",\n className,\n )}\n {...props}\n />\n));\nTabsTrigger.displayName = \"TabsTrigger\";\n\nexport const TabsContent = forwardRef<\n ElementRef<typeof TabsPrimitive.Content>,\n ComponentPropsWithoutRef<typeof TabsPrimitive.Content>\n>(({ className, ...props }, ref) => (\n <TabsPrimitive.Content ref={ref} className={cn(\"flex-1 outline-none\", className)} {...props} />\n));\nTabsContent.displayName = \"TabsContent\";\n","import * as SeparatorPrimitive from \"@radix-ui/react-separator\";\nimport type { ComponentPropsWithoutRef, ElementRef } from \"react\";\nimport { forwardRef } from \"react\";\nimport { cn } from \"../lib/utils\";\n\nexport const Separator = forwardRef<\n ElementRef<typeof SeparatorPrimitive.Root>,\n ComponentPropsWithoutRef<typeof SeparatorPrimitive.Root>\n>(({ className, orientation = \"horizontal\", decorative = true, ...props }, ref) => (\n <SeparatorPrimitive.Root\n ref={ref}\n decorative={decorative}\n orientation={orientation}\n className={cn(\n \"shrink-0 bg-border\",\n orientation === \"horizontal\" ? \"h-px w-full\" : \"h-full w-px\",\n className,\n )}\n {...props}\n />\n));\nSeparator.displayName = \"Separator\";\n","import * as ScrollAreaPrimitive from \"@radix-ui/react-scroll-area\";\nimport type { ComponentPropsWithoutRef, ElementRef } from \"react\";\nimport { forwardRef } from \"react\";\nimport { cn } from \"../lib/utils\";\n\nexport const ScrollBar = forwardRef<\n ElementRef<typeof ScrollAreaPrimitive.ScrollAreaScrollbar>,\n ComponentPropsWithoutRef<typeof ScrollAreaPrimitive.ScrollAreaScrollbar>\n>(({ className, orientation = \"vertical\", ...props }, ref) => (\n <ScrollAreaPrimitive.ScrollAreaScrollbar\n ref={ref}\n orientation={orientation}\n className={cn(\n \"flex touch-none select-none transition-colors\",\n orientation === \"vertical\" && \"h-full w-2.5 border-l border-l-transparent p-[1px]\",\n orientation === \"horizontal\" && \"h-2.5 flex-col border-t border-t-transparent p-[1px]\",\n className,\n )}\n {...props}\n >\n <ScrollAreaPrimitive.ScrollAreaThumb className=\"relative flex-1 rounded-full bg-border\" />\n </ScrollAreaPrimitive.ScrollAreaScrollbar>\n));\nScrollBar.displayName = \"ScrollBar\";\n\nexport const ScrollArea = forwardRef<\n ElementRef<typeof ScrollAreaPrimitive.Root>,\n ComponentPropsWithoutRef<typeof ScrollAreaPrimitive.Root>\n>(({ className, children, ...props }, ref) => (\n <ScrollAreaPrimitive.Root ref={ref} className={cn(\"relative overflow-hidden\", className)} {...props}>\n <ScrollAreaPrimitive.Viewport className=\"h-full w-full rounded-[inherit]\">\n {children}\n </ScrollAreaPrimitive.Viewport>\n <ScrollBar />\n <ScrollAreaPrimitive.Corner />\n </ScrollAreaPrimitive.Root>\n));\nScrollArea.displayName = \"ScrollArea\";\n","import type { HTMLAttributes, TdHTMLAttributes, ThHTMLAttributes } from \"react\";\nimport { forwardRef } from \"react\";\nimport { cn } from \"../lib/utils\";\n\nexport const Table = forwardRef<HTMLTableElement, HTMLAttributes<HTMLTableElement>>(\n ({ className, ...props }, ref) => (\n <div className=\"relative w-full overflow-x-auto\">\n <table ref={ref} className={cn(\"w-full caption-bottom text-sm\", className)} {...props} />\n </div>\n ),\n);\nTable.displayName = \"Table\";\n\nexport const TableHeader = forwardRef<HTMLTableSectionElement, HTMLAttributes<HTMLTableSectionElement>>(\n ({ className, ...props }, ref) => (\n <thead ref={ref} className={cn(\"[&_tr]:border-b\", className)} {...props} />\n ),\n);\nTableHeader.displayName = \"TableHeader\";\n\nexport const TableBody = forwardRef<HTMLTableSectionElement, HTMLAttributes<HTMLTableSectionElement>>(\n ({ className, ...props }, ref) => (\n <tbody ref={ref} className={cn(\"[&_tr:last-child]:border-0\", className)} {...props} />\n ),\n);\nTableBody.displayName = \"TableBody\";\n\nexport const TableFooter = forwardRef<HTMLTableSectionElement, HTMLAttributes<HTMLTableSectionElement>>(\n ({ className, ...props }, ref) => (\n <tfoot\n ref={ref}\n className={cn(\"border-t bg-muted/50 font-medium [&>tr]:last:border-b-0\", className)}\n {...props}\n />\n ),\n);\nTableFooter.displayName = \"TableFooter\";\n\nexport const TableRow = forwardRef<HTMLTableRowElement, HTMLAttributes<HTMLTableRowElement>>(\n ({ className, ...props }, ref) => (\n <tr\n ref={ref}\n className={cn(\"border-b transition-colors hover:bg-muted/50 data-[state=selected]:bg-muted\", className)}\n {...props}\n />\n ),\n);\nTableRow.displayName = \"TableRow\";\n\nexport const TableHead = forwardRef<HTMLTableCellElement, ThHTMLAttributes<HTMLTableCellElement>>(\n ({ className, ...props }, ref) => (\n <th\n ref={ref}\n className={cn(\n \"h-10 whitespace-nowrap px-2 text-left align-middle font-medium text-foreground [&:has([role=checkbox])]:pr-0\",\n className,\n )}\n {...props}\n />\n ),\n);\nTableHead.displayName = \"TableHead\";\n\nexport const TableCell = forwardRef<HTMLTableCellElement, TdHTMLAttributes<HTMLTableCellElement>>(\n ({ className, ...props }, ref) => (\n <td\n ref={ref}\n className={cn(\"whitespace-nowrap p-2 align-middle [&:has([role=checkbox])]:pr-0\", className)}\n {...props}\n />\n ),\n);\nTableCell.displayName = \"TableCell\";\n\nexport const TableCaption = forwardRef<HTMLTableCaptionElement, HTMLAttributes<HTMLTableCaptionElement>>(\n ({ className, ...props }, ref) => (\n <caption ref={ref} className={cn(\"mt-4 text-sm text-muted-foreground\", className)} {...props} />\n ),\n);\nTableCaption.displayName = \"TableCaption\";\n","import * as DropdownMenuPrimitive from \"@radix-ui/react-dropdown-menu\";\nimport { Check, ChevronRight, Circle } from \"lucide-react\";\nimport type { ComponentPropsWithoutRef, ElementRef, HTMLAttributes } from \"react\";\nimport { forwardRef } from \"react\";\nimport { cn } from \"../lib/utils\";\n\nexport const DropdownMenu = DropdownMenuPrimitive.Root;\nexport const DropdownMenuTrigger = DropdownMenuPrimitive.Trigger;\nexport const DropdownMenuGroup = DropdownMenuPrimitive.Group;\nexport const DropdownMenuPortal = DropdownMenuPrimitive.Portal;\nexport const DropdownMenuSub = DropdownMenuPrimitive.Sub;\nexport const DropdownMenuRadioGroup = DropdownMenuPrimitive.RadioGroup;\n\nexport const DropdownMenuContent = forwardRef<\n ElementRef<typeof DropdownMenuPrimitive.Content>,\n ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Content>\n>(({ className, sideOffset = 4, ...props }, ref) => (\n <DropdownMenuPrimitive.Portal>\n <DropdownMenuPrimitive.Content\n ref={ref}\n sideOffset={sideOffset}\n className={cn(\n \"z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-md\",\n className,\n )}\n {...props}\n />\n </DropdownMenuPrimitive.Portal>\n));\nDropdownMenuContent.displayName = \"DropdownMenuContent\";\n\nexport const DropdownMenuItem = forwardRef<\n ElementRef<typeof DropdownMenuPrimitive.Item>,\n ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Item> & { danger?: boolean }\n>(({ className, danger, ...props }, ref) => (\n <DropdownMenuPrimitive.Item\n ref={ref}\n className={cn(\n \"relative flex cursor-default select-none items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50\",\n danger && \"text-destructive focus:bg-destructive/10 focus:text-destructive\",\n className,\n )}\n {...props}\n />\n));\nDropdownMenuItem.displayName = \"DropdownMenuItem\";\n\nexport const DropdownMenuCheckboxItem = forwardRef<\n ElementRef<typeof DropdownMenuPrimitive.CheckboxItem>,\n ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.CheckboxItem>\n>(({ className, children, checked, ...props }, ref) => (\n <DropdownMenuPrimitive.CheckboxItem\n ref={ref}\n checked={checked}\n className={cn(\n \"relative flex cursor-default select-none items-center gap-2 rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50\",\n className,\n )}\n {...props}\n >\n <span className=\"absolute left-2 flex h-3.5 w-3.5 items-center justify-center\">\n <DropdownMenuPrimitive.ItemIndicator>\n <Check className=\"h-4 w-4\" />\n </DropdownMenuPrimitive.ItemIndicator>\n </span>\n {children}\n </DropdownMenuPrimitive.CheckboxItem>\n));\nDropdownMenuCheckboxItem.displayName = \"DropdownMenuCheckboxItem\";\n\nexport const DropdownMenuRadioItem = forwardRef<\n ElementRef<typeof DropdownMenuPrimitive.RadioItem>,\n ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.RadioItem>\n>(({ className, children, ...props }, ref) => (\n <DropdownMenuPrimitive.RadioItem\n ref={ref}\n className={cn(\n \"relative flex cursor-default select-none items-center gap-2 rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50\",\n className,\n )}\n {...props}\n >\n <span className=\"absolute left-2 flex h-3.5 w-3.5 items-center justify-center\">\n <DropdownMenuPrimitive.ItemIndicator>\n <Circle className=\"h-2 w-2 fill-current\" />\n </DropdownMenuPrimitive.ItemIndicator>\n </span>\n {children}\n </DropdownMenuPrimitive.RadioItem>\n));\nDropdownMenuRadioItem.displayName = \"DropdownMenuRadioItem\";\n\nexport const DropdownMenuSeparator = forwardRef<\n ElementRef<typeof DropdownMenuPrimitive.Separator>,\n ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Separator>\n>(({ className, ...props }, ref) => (\n <DropdownMenuPrimitive.Separator\n ref={ref}\n className={cn(\"-mx-1 my-1 h-px bg-muted\", className)}\n {...props}\n />\n));\nDropdownMenuSeparator.displayName = \"DropdownMenuSeparator\";\n\nexport const DropdownMenuLabel = forwardRef<\n ElementRef<typeof DropdownMenuPrimitive.Label>,\n ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Label>\n>(({ className, ...props }, ref) => (\n <DropdownMenuPrimitive.Label\n ref={ref}\n className={cn(\"px-2 py-1.5 text-xs font-medium text-muted-foreground\", className)}\n {...props}\n />\n));\nDropdownMenuLabel.displayName = \"DropdownMenuLabel\";\n\nexport const DropdownMenuShortcut = ({\n className,\n ...props\n}: HTMLAttributes<HTMLSpanElement>) => (\n <span className={cn(\"ml-auto text-xs tracking-widest text-muted-foreground\", className)} {...props} />\n);\n\nexport const DropdownMenuSubTrigger = forwardRef<\n ElementRef<typeof DropdownMenuPrimitive.SubTrigger>,\n ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.SubTrigger>\n>(({ className, children, ...props }, ref) => (\n <DropdownMenuPrimitive.SubTrigger\n ref={ref}\n className={cn(\n \"flex cursor-default select-none items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[state=open]:bg-accent data-[state=open]:text-accent-foreground\",\n className,\n )}\n {...props}\n >\n {children}\n <ChevronRight className=\"ml-auto h-4 w-4\" />\n </DropdownMenuPrimitive.SubTrigger>\n));\nDropdownMenuSubTrigger.displayName = \"DropdownMenuSubTrigger\";\n\nexport const DropdownMenuSubContent = forwardRef<\n ElementRef<typeof DropdownMenuPrimitive.SubContent>,\n ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.SubContent>\n>(({ className, ...props }, ref) => (\n <DropdownMenuPrimitive.SubContent\n ref={ref}\n className={cn(\n \"z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-md\",\n className,\n )}\n {...props}\n />\n));\nDropdownMenuSubContent.displayName = \"DropdownMenuSubContent\";\n","import { type VariantProps, cva } from \"class-variance-authority\";\nimport * as DialogPrimitive from \"@radix-ui/react-dialog\";\nimport { X } from \"lucide-react\";\nimport type {\n ComponentPropsWithoutRef,\n CSSProperties,\n ElementRef,\n HTMLAttributes,\n PointerEvent as ReactPointerEvent,\n ReactElement,\n} from \"react\";\nimport { forwardRef, useEffect, useRef, useState } from \"react\";\nimport { cn } from \"../lib/utils\";\n\nexport const Sheet = DialogPrimitive.Root;\nexport const SheetTrigger = DialogPrimitive.Trigger;\nexport const SheetClose = DialogPrimitive.Close;\nexport const SheetPortal = DialogPrimitive.Portal;\n\nexport const SheetOverlay = forwardRef<\n ElementRef<typeof DialogPrimitive.Overlay>,\n ComponentPropsWithoutRef<typeof DialogPrimitive.Overlay>\n>(({ className, ...props }, ref) => (\n <DialogPrimitive.Overlay\n ref={ref}\n className={cn(\"fixed inset-0 z-50 bg-black/50\", className)}\n {...props}\n />\n));\nSheetOverlay.displayName = \"SheetOverlay\";\n\n// Neither this package nor any other package in the monorepo depends on the\n// `tailwindcss-animate` plugin (grepped for \"animate-in\"/\"tailwindcss-animate\"\n// across the repo — the only pre-existing `data-[state=...]` usages are plain\n// color/background toggles, not that plugin's enter/exit keyframe utilities).\n// Rather than have @bmsuisse/ui silently assume a consumer has that plugin\n// installed, the slide transition here is done with Tailwind's built-in\n// `transition-transform` plus a `translate-x`/`translate-y` toggle driven off\n// Radix's own `data-[state=open]`/`data-[state=closed]` attributes.\nexport const sheetVariants = cva(\n \"fixed z-50 gap-4 bg-background p-6 shadow-lg transition-[transform,box-shadow] duration-300 ease-in-out\",\n {\n variants: {\n side: {\n // Every edge border below is paired with `border-border` explicitly —\n // Tailwind v4's bare `border-*` utilities default to `currentColor`,\n // not the theme's border token, which otherwise renders this seam in\n // the foreground text color (a harsh, high-contrast line in both\n // themes) instead of the intended subtle divider.\n top: \"inset-x-0 top-0 border-b border-border data-[state=closed]:-translate-y-full data-[state=open]:translate-y-0\",\n bottom:\n \"inset-x-0 bottom-0 border-t border-border data-[state=closed]:translate-y-full data-[state=open]:translate-y-0\",\n left: \"inset-y-0 left-0 h-full w-3/4 border-r border-border data-[state=closed]:-translate-x-full data-[state=open]:translate-x-0 sm:max-w-sm\",\n right:\n \"inset-y-0 right-0 h-full w-3/4 border-l border-border data-[state=closed]:translate-x-full data-[state=open]:translate-x-0 sm:max-w-sm\",\n },\n },\n defaultVariants: {\n side: \"right\",\n },\n },\n);\n\nexport interface SheetContentProps\n extends ComponentPropsWithoutRef<typeof DialogPrimitive.Content>,\n VariantProps<typeof sheetVariants> {\n /**\n * Bottom sheets only: adds a drag handle so the user can pull the sheet\n * taller (up to 95% of the viewport) or shorter (down to 30%) with the\n * mouse/touch instead of being stuck with the height set by className.\n * Ignored for other sides.\n */\n resizable?: boolean;\n}\n\n// Off-screen starting transform for the entrance animation below — same\n// direction as each side's own `data-[state=closed]` translate class.\nconst enterFromTransform: Record<\"top\" | \"bottom\" | \"left\" | \"right\", string> = {\n top: \"translateY(-100%)\",\n bottom: \"translateY(100%)\",\n left: \"translateX(-100%)\",\n right: \"translateX(100%)\",\n};\n\nexport const SheetContent = forwardRef<ElementRef<typeof DialogPrimitive.Content>, SheetContentProps>(\n ({ side = \"right\", className, children, resizable = false, style: styleProp, ...props }, ref) => {\n // Radix mounts Content with `data-state=\"open\"` already on first paint,\n // so the `data-[state=...]` translate classes above never see a \"before\"\n // position to transition from — it just appears instead of sliding in.\n // Render one frame off-screen via an inline transform (which overrides\n // the class-based one), then clear it so the transition plays. Exit\n // already animates correctly: Radix flips to `data-state=\"closed\"` while\n // still mounted and defers unmounting until the transition ends.\n const [entered, setEntered] = useState(false);\n useEffect(() => {\n const id = requestAnimationFrame(() => setEntered(true));\n return () => cancelAnimationFrame(id);\n }, []);\n\n // Drag-to-resize: track the sheet's height in local state once the user\n // starts dragging the handle, clamped between 30% and 95% of the\n // viewport height (same bounds as the sheet consumers ported this from).\n const [dragHeight, setDragHeight] = useState<number | null>(null);\n const [isDragging, setIsDragging] = useState(false);\n const dragStart = useRef<{ y: number; height: number } | null>(null);\n const canResize = resizable && side === \"bottom\";\n\n const onHandlePointerDown = (e: ReactPointerEvent<HTMLDivElement>): void => {\n const popup = e.currentTarget.closest('[data-slot=\"sheet-content\"]');\n if (!(popup instanceof HTMLElement)) return;\n e.currentTarget.setPointerCapture(e.pointerId);\n dragStart.current = { y: e.clientY, height: popup.getBoundingClientRect().height };\n setIsDragging(true);\n };\n const onHandlePointerMove = (e: ReactPointerEvent<HTMLDivElement>): void => {\n if (!dragStart.current) return;\n const delta = dragStart.current.y - e.clientY;\n const next = dragStart.current.height + delta;\n const min = window.innerHeight * 0.3;\n const max = window.innerHeight * 0.95;\n setDragHeight(Math.min(max, Math.max(min, next)));\n };\n const onHandlePointerUp = (): void => {\n dragStart.current = null;\n setIsDragging(false);\n };\n\n const style: CSSProperties | undefined = entered\n ? { ...styleProp, ...(canResize && dragHeight != null ? { height: dragHeight, maxHeight: dragHeight } : null) }\n : { ...styleProp, transform: enterFromTransform[side ?? \"right\"] };\n\n return (\n <SheetPortal>\n <SheetOverlay />\n <DialogPrimitive.Content\n ref={ref}\n data-slot=\"sheet-content\"\n style={style}\n className={cn(sheetVariants({ side }), isDragging && \"shadow-2xl\", className)}\n {...props}\n >\n {canResize && (\n <div\n data-testid=\"sheet-drag-handle\"\n className=\"group -mb-2 flex shrink-0 cursor-grab touch-none justify-center py-2 active:cursor-grabbing\"\n onPointerDown={onHandlePointerDown}\n onPointerMove={onHandlePointerMove}\n onPointerUp={onHandlePointerUp}\n onPointerCancel={onHandlePointerUp}\n >\n <div\n className={cn(\n \"h-1 w-10 rounded-full bg-muted-foreground/30 transition-all duration-150 group-hover:w-14 group-hover:bg-muted-foreground/50\",\n isDragging && \"w-14 bg-primary/60\",\n )}\n />\n </div>\n )}\n {children}\n <DialogPrimitive.Close className=\"absolute right-4 top-4 rounded-sm opacity-70 hover:opacity-100\">\n <X className=\"h-4 w-4\" />\n <span className=\"sr-only\">Close</span>\n </DialogPrimitive.Close>\n </DialogPrimitive.Content>\n </SheetPortal>\n );\n },\n);\nSheetContent.displayName = \"SheetContent\";\n\nexport const SheetHeader = ({\n className,\n ...props\n}: HTMLAttributes<HTMLDivElement>): ReactElement => (\n <div className={cn(\"flex flex-col gap-1.5\", className)} {...props} />\n);\n\nexport const SheetFooter = ({\n className,\n ...props\n}: HTMLAttributes<HTMLDivElement>): ReactElement => (\n <div className={cn(\"flex justify-end gap-2\", className)} {...props} />\n);\n\nexport const SheetTitle = forwardRef<\n ElementRef<typeof DialogPrimitive.Title>,\n ComponentPropsWithoutRef<typeof DialogPrimitive.Title>\n>(({ className, ...props }, ref) => (\n <DialogPrimitive.Title ref={ref} className={cn(\"text-lg font-semibold\", className)} {...props} />\n));\nSheetTitle.displayName = \"SheetTitle\";\n\nexport const SheetDescription = forwardRef<\n ElementRef<typeof DialogPrimitive.Description>,\n ComponentPropsWithoutRef<typeof DialogPrimitive.Description>\n>(({ className, ...props }, ref) => (\n <DialogPrimitive.Description\n ref={ref}\n className={cn(\"text-sm text-muted-foreground\", className)}\n {...props}\n />\n));\nSheetDescription.displayName = \"SheetDescription\";\n","import * as TooltipPrimitive from \"@radix-ui/react-tooltip\";\nimport type { ComponentPropsWithoutRef, ElementRef } from \"react\";\nimport { forwardRef } from \"react\";\nimport { cn } from \"../lib/utils\";\n\nexport const TooltipProvider = TooltipPrimitive.Provider;\nexport const Tooltip = TooltipPrimitive.Root;\nexport const TooltipTrigger = TooltipPrimitive.Trigger;\n\nexport const TooltipContent = forwardRef<\n ElementRef<typeof TooltipPrimitive.Content>,\n ComponentPropsWithoutRef<typeof TooltipPrimitive.Content>\n>(({ className, sideOffset = 4, ...props }, ref) => (\n <TooltipPrimitive.Portal>\n <TooltipPrimitive.Content\n ref={ref}\n sideOffset={sideOffset}\n className={cn(\n \"z-50 overflow-hidden rounded-md border bg-popover px-3 py-1.5 text-xs text-popover-foreground shadow-md\",\n className,\n )}\n {...props}\n />\n </TooltipPrimitive.Portal>\n));\nTooltipContent.displayName = \"TooltipContent\";\n","import type { ReactElement, ReactNode } from \"react\";\nimport {\n Dialog,\n DialogContent,\n DialogDescription,\n DialogFooter,\n DialogHeader,\n DialogTitle,\n} from \"../../primitives/dialog\";\n\nexport interface ModalProps {\n /** Whether the modal is open. Modal is fully controlled — no internal open state. */\n open: boolean;\n /** Called when Radix wants to change the open state (backdrop click, Esc, close button). */\n onOpenChange: (open: boolean) => void;\n /** Dialog title, rendered in `DialogTitle`. */\n title: string;\n /** Optional supporting copy, rendered in `DialogDescription` under the title. */\n description?: string;\n /** Body content of the modal. */\n children: ReactNode;\n /** Optional footer content (typically action buttons), rendered in `DialogFooter`. */\n footer?: ReactNode;\n /** Extra classes applied to `DialogContent`, e.g. to override the default width. */\n className?: string;\n}\n\n/**\n * Base structural wrapper around the `@bmsuisse/ui` Dialog primitives: title,\n * optional description, body, and an optional footer. Use this directly for\n * modals that don't fit `ConfirmDialog` or `FormModal`; those two are built\n * on top of the same shape.\n */\nexport const Modal = ({\n open,\n onOpenChange,\n title,\n description,\n children,\n footer,\n className,\n}: ModalProps): ReactElement => (\n <Dialog open={open} onOpenChange={onOpenChange}>\n <DialogContent className={className}>\n <DialogHeader>\n <DialogTitle>{title}</DialogTitle>\n {description ? <DialogDescription>{description}</DialogDescription> : null}\n </DialogHeader>\n {children}\n {footer ? <DialogFooter>{footer}</DialogFooter> : null}\n </DialogContent>\n </Dialog>\n);\n","import type { ReactElement } from \"react\";\nimport { useState } from \"react\";\nimport { Button } from \"../../primitives/button\";\nimport { DialogActions } from \"./DialogActions\";\nimport { Modal } from \"./Modal\";\n\nexport interface ConfirmDialogProps {\n /** Whether the dialog is open. Fully controlled — no internal open state. */\n open: boolean;\n /** Called when Radix wants to change the open state (backdrop click, Esc, close button). */\n onOpenChange: (open: boolean) => void;\n /** Dialog title. */\n title: string;\n /** Optional supporting copy shown under the title. */\n description?: string;\n /** Label for the confirm button. Defaults to `\"Confirm\"`. */\n confirmLabel?: string;\n /** Label for the cancel button. Defaults to `\"Cancel\"`. */\n cancelLabel?: string;\n /** Called when the user clicks confirm. May return a promise; the dialog waits for it. */\n onConfirm: () => void | Promise<void>;\n /** Visual style of the confirm button. Defaults to `\"default\"`. */\n variant?: \"default\" | \"destructive\";\n /** Forwarded to the confirm button, for test targeting (e.g. Playwright/Testing Library). */\n confirmTestId?: string;\n /** Forwarded to the cancel button, for test targeting. */\n cancelTestId?: string;\n}\n\n/**\n * \"Are you sure?\" confirmation dialog. Unlike `FormModal`, this DOES close\n * itself automatically after a successful `onConfirm` — confirmations are a\n * single yes/no action with no follow-up state to inspect, so there's nothing\n * for the caller to decide. If `onConfirm` throws/rejects, the dialog stays\n * open and the error is not swallowed, so a caller can surface its own error\n * UI without the dialog disappearing out from under it.\n */\nexport const ConfirmDialog = ({\n open,\n onOpenChange,\n title,\n description,\n confirmLabel = \"Confirm\",\n cancelLabel = \"Cancel\",\n onConfirm,\n variant = \"default\",\n confirmTestId,\n cancelTestId,\n}: ConfirmDialogProps): ReactElement => {\n const [pending, setPending] = useState(false);\n\n const handleCancel = (): void => {\n onOpenChange(false);\n };\n\n const handleConfirm = async (): Promise<void> => {\n setPending(true);\n try {\n await onConfirm();\n onOpenChange(false);\n } catch (error) {\n // Do not swallow the failure into a silent no-op: surface it (the\n // caller's own error UI is the right place to react to it in detail)\n // and, critically, leave the dialog open instead of closing it as if\n // nothing happened.\n console.error(error);\n } finally {\n setPending(false);\n }\n };\n\n const cancelButton = (\n <Button variant=\"outline\" onClick={handleCancel} disabled={pending} data-testid={cancelTestId}>\n {cancelLabel}\n </Button>\n );\n const confirmButton = (\n <Button\n variant={variant === \"destructive\" ? \"destructive\" : \"default\"}\n onClick={handleConfirm}\n disabled={pending}\n data-testid={confirmTestId}\n >\n {pending ? `${confirmLabel}…` : confirmLabel}\n </Button>\n );\n\n return (\n <Modal\n open={open}\n onOpenChange={onOpenChange}\n title={title}\n description={description}\n footer={<DialogActions actions={[confirmButton]} cancel={cancelButton} />}\n >\n {null}\n </Modal>\n );\n};\n","import type { Key, ReactElement, ReactNode } from \"react\";\nimport { Fragment, useState } from \"react\";\nimport { getConfirmButtonPlacement } from \"../../lib/platform\";\n\nexport interface DialogActionsProps {\n /**\n * The dialog's non-cancel actions, ordered from *nearest to Cancel* to\n * *most primary* — e.g. `[secondaryAction, primaryAction]`. For a plain\n * two-button confirm dialog, pass a single primary action here.\n */\n actions: ReactNode[];\n /** The dismissive/cancel action. */\n cancel: ReactNode;\n}\n\n/**\n * Renders `actions` and `cancel` in the order the current platform's own\n * dialogs use — Windows puts Cancel on the right (trailing), every other\n * platform we target (iOS/iPadOS, macOS, Android, Linux) puts it on the\n * left (leading) — instead of a fixed order every caller has to get right\n * itself. `ConfirmDialog` and `QuestionDialog` use this internally; use it\n * directly for any other dialog/panel footer with the same\n * actions-plus-cancel shape.\n *\n * Matches native multi-button \"Save changes?\"-style dialogs: the most\n * primary action sits at the edge *opposite* Cancel (Windows:\n * `Save · Don't Save · Cancel`; iOS/macOS: `Cancel · Don't Save · Save`),\n * not next to it. `actions` is reversed when Cancel sits on the right\n * (Windows), so the last element of `actions` — the primary action — is\n * always the one furthest from Cancel, and the first element is always the\n * one nearest Cancel, regardless of platform — a caller picks the order\n * once, by meaning, and doesn't have to reason about which edge Cancel\n * lands on.\n *\n * Renders no wrapping element of its own — nest it inside the caller's own\n * footer container (e.g. `DialogFooter`, or `Modal`'s `footer` prop) for\n * layout/spacing.\n */\nexport function DialogActions({ actions, cancel }: DialogActionsProps): ReactElement {\n // Platform doesn't change mid-session, so this is computed once rather\n // than re-read from `navigator` on every render.\n const [placement] = useState(getConfirmButtonPlacement);\n const cancelLeading = placement === \"trailing\";\n const ordered = cancelLeading ? actions : [...actions].reverse();\n\n const renderedActions = ordered.map((action, index) => (\n <Fragment key={actionKey(action, index)}>{action}</Fragment>\n ));\n\n return cancelLeading ? (\n <>\n {cancel}\n {renderedActions}\n </>\n ) : (\n <>\n {renderedActions}\n {cancel}\n </>\n );\n}\n\nfunction actionKey(action: ReactNode, index: number): Key {\n if (action && typeof action === \"object\" && \"key\" in action && action.key !== null) return action.key as Key;\n return index;\n}\n","/**\n * Whether the current runtime is Windows, based on the UA string. Returns\n * `false` outside a browser (SSR, tests) so platform-dependent UI falls back\n * to the non-Windows default rather than guessing.\n */\nexport function isWindowsPlatform(): boolean {\n if (typeof navigator === \"undefined\") return false;\n return /Windows/i.test(navigator.userAgent);\n}\n\nexport type ConfirmButtonPlacement = \"leading\" | \"trailing\";\n\n/**\n * Where a dialog's affirmative/confirm button should sit, matching each\n * platform's own system convention: Windows dialogs place OK/Save on the\n * left (Cancel on the right); every other platform we target — iOS/iPadOS,\n * macOS, Android, Linux — places the affirmative action on the right (the\n * iOS/macOS Human Interface Guidelines require this, and it's the de facto\n * default everywhere else too). Windows is the one exception, so this is\n * driven entirely by `isWindowsPlatform`.\n */\nexport function getConfirmButtonPlacement(): ConfirmButtonPlacement {\n return isWindowsPlatform() ? \"leading\" : \"trailing\";\n}\n","import type { FormEvent, ReactElement, ReactNode } from \"react\";\nimport { useState } from \"react\";\nimport { Button } from \"../../primitives/button\";\nimport {\n Dialog,\n DialogContent,\n DialogDescription,\n DialogFooter,\n DialogHeader,\n DialogTitle,\n} from \"../../primitives/dialog\";\n\nexport interface FormModalProps {\n /** Whether the modal is open. Fully controlled — no internal open state. */\n open: boolean;\n /** Called when Radix wants to change the open state (backdrop click, Esc, close button). */\n onOpenChange: (open: boolean) => void;\n /** Dialog title. */\n title: string;\n /** Optional supporting copy shown under the title. */\n description?: string;\n /** Form field content, rendered inside the `<form>`. */\n children: ReactNode;\n /** Called on submit (button click or Enter in a field). May return a promise. */\n onSubmit: () => void | Promise<void>;\n /** Label for the submit button. Defaults to `\"Save\"`. */\n submitLabel?: string;\n /** Label for the cancel button. Defaults to `\"Cancel\"`. */\n cancelLabel?: string;\n /**\n * Disables the submit button (e.g. required fields still empty), on top of\n * the automatic disable while `onSubmit`'s promise is pending. Cancel\n * stays enabled either way. Defaults to `false`.\n */\n submitDisabled?: boolean;\n /** Extra classes applied to `DialogContent`, e.g. to override the default width. */\n className?: string;\n /** Forwarded to the submit button, for test targeting (e.g. Playwright/Testing Library). */\n submitTestId?: string;\n /** Forwarded to the cancel button, for test targeting. */\n cancelTestId?: string;\n}\n\n/**\n * Modal wrapping a form. Unlike `ConfirmDialog`, this does NOT close itself\n * after a successful `onSubmit` — forms commonly have server-side validation\n * and shouldn't vanish on failure, so closing after success is left entirely\n * to the caller (typically by calling `onOpenChange(false)` once its own\n * submit handler resolves without error).\n */\nexport const FormModal = ({\n open,\n onOpenChange,\n title,\n description,\n children,\n onSubmit,\n submitLabel = \"Save\",\n cancelLabel = \"Cancel\",\n submitDisabled = false,\n className,\n submitTestId,\n cancelTestId,\n}: FormModalProps): ReactElement => {\n const [pending, setPending] = useState(false);\n\n const handleSubmit = async (event: FormEvent<HTMLFormElement>): Promise<void> => {\n event.preventDefault();\n setPending(true);\n try {\n await onSubmit();\n } finally {\n setPending(false);\n }\n };\n\n const handleCancel = (): void => {\n onOpenChange(false);\n };\n\n return (\n <Dialog open={open} onOpenChange={onOpenChange}>\n <DialogContent className={className}>\n <form onSubmit={handleSubmit}>\n <DialogHeader>\n <DialogTitle>{title}</DialogTitle>\n {description ? <DialogDescription>{description}</DialogDescription> : null}\n </DialogHeader>\n {children}\n <DialogFooter>\n <Button\n type=\"button\"\n variant=\"outline\"\n onClick={handleCancel}\n disabled={pending}\n data-testid={cancelTestId}\n >\n {cancelLabel}\n </Button>\n <Button type=\"submit\" disabled={pending || submitDisabled} data-testid={submitTestId}>\n {pending ? `${submitLabel}…` : submitLabel}\n </Button>\n </DialogFooter>\n </form>\n </DialogContent>\n </Dialog>\n );\n};\n","import type { CSSProperties, PointerEvent as ReactPointerEvent, ReactElement, ReactNode } from \"react\";\nimport { useRef, useState } from \"react\";\nimport { useMediaQuery } from \"../../lib/useMediaQuery\";\nimport { cn } from \"../../lib/utils\";\nimport {\n Dialog,\n DialogContent,\n DialogDescription,\n DialogFooter,\n DialogHeader,\n DialogTitle,\n} from \"../../primitives/dialog\";\nimport {\n Sheet,\n SheetContent,\n SheetDescription,\n SheetFooter,\n SheetHeader,\n SheetTitle,\n} from \"../../primitives/sheet\";\n\nconst desktopSizeClasses = {\n sm: \"max-w-md\",\n md: \"max-w-xl\",\n lg: \"max-w-2xl\",\n xl: \"max-w-7xl\",\n} as const;\n\nconst drawerSizeClasses = {\n sm: \"max-h-[50vh]\",\n md: \"max-h-[70vh]\",\n lg: \"max-h-[90vh]\",\n xl: \"max-h-[96vh]\",\n} as const;\n\nexport type ResponsivePanelSize = keyof typeof desktopSizeClasses;\n\nconst MIN_PANEL_WIDTH = 320;\nconst MIN_PANEL_HEIGHT = 240;\nconst VIEWPORT_MARGIN = 16;\n\ntype Corner = \"top-left\" | \"top-right\" | \"bottom-left\" | \"bottom-right\";\n\nconst cornerCursor: Record<Corner, string> = {\n \"top-left\": \"cursor-nwse-resize\",\n \"bottom-right\": \"cursor-nwse-resize\",\n \"top-right\": \"cursor-nesw-resize\",\n \"bottom-left\": \"cursor-nesw-resize\",\n};\n\nconst cornerPosition: Record<Corner, string> = {\n \"top-left\": \"left-0 top-0\",\n \"top-right\": \"right-0 top-0\",\n \"bottom-left\": \"left-0 bottom-0\",\n \"bottom-right\": \"right-0 bottom-0\",\n};\n\nconst cornerGripPosition: Record<Corner, string> = {\n \"top-left\": \"left-1 top-1 border-l-2 border-t-2\",\n \"top-right\": \"right-1 top-1 border-r-2 border-t-2\",\n \"bottom-left\": \"left-1 bottom-1 border-l-2 border-b-2\",\n \"bottom-right\": \"right-1 bottom-1 border-r-2 border-b-2\",\n};\n\ninterface Rect {\n left: number;\n top: number;\n width: number;\n height: number;\n}\n\ninterface DragState {\n mode: \"move\" | \"resize\";\n corner?: Corner;\n x: number;\n y: number;\n rect: Rect;\n}\n\n// Drag the dialog's header to move it, or a corner handle to resize it from\n// that corner (the opposite corner stays anchored). Radix centers the dialog\n// with a translate-based className, so once the user starts dragging we\n// switch to explicit fixed left/top/width/height (inline styles beat the\n// class-based transform/size utilities) and never go back to the centered\n// layout for that open panel. Both left/top and width/height are always\n// clamped to a viewport margin so the panel can never end up positioned\n// (partly) off-screen with no way to drag it back.\n//\n// The anchor rect for a new drag comes from `lastRect` (the geometry we set\n// ourselves on the previous drag) rather than a fresh `getBoundingClientRect()`\n// call whenever one is available — re-measuring the DOM right as a new\n// pointerdown fires occasionally raced with layout and returned a stale box,\n// which made a resize immediately after a move jump the panel off-screen.\nfunction useDesktopPanelGeometry(): {\n style: CSSProperties | undefined;\n isDragging: boolean;\n startMove: (e: ReactPointerEvent<HTMLDivElement>) => void;\n startResize: (corner: Corner) => (e: ReactPointerEvent<HTMLDivElement>) => void;\n onPointerMove: (e: ReactPointerEvent<HTMLDivElement>) => void;\n onPointerUp: () => void;\n} {\n const [style, setStyle] = useState<CSSProperties | undefined>(undefined);\n const [isDragging, setIsDragging] = useState(false);\n const drag = useRef<DragState | null>(null);\n const lastRect = useRef<Rect | null>(null);\n\n const beginDrag =\n (mode: \"move\" | \"resize\", corner?: Corner) =>\n (e: ReactPointerEvent<HTMLDivElement>): void => {\n const content = e.currentTarget.closest('[data-slot=\"dialog-content\"]');\n if (!(content instanceof HTMLElement)) return;\n e.currentTarget.setPointerCapture(e.pointerId);\n const domRect = content.getBoundingClientRect();\n const rect = lastRect.current ?? {\n left: domRect.left,\n top: domRect.top,\n width: domRect.width,\n height: domRect.height,\n };\n drag.current = { mode, corner, x: e.clientX, y: e.clientY, rect };\n setIsDragging(true);\n };\n\n const onPointerMove = (e: ReactPointerEvent<HTMLDivElement>): void => {\n const state = drag.current;\n if (!state) return;\n const deltaX = e.clientX - state.x;\n const deltaY = e.clientY - state.y;\n\n if (state.mode === \"move\") {\n const maxLeft = window.innerWidth - VIEWPORT_MARGIN - state.rect.width;\n const maxTop = window.innerHeight - VIEWPORT_MARGIN - state.rect.height;\n const next: Rect = {\n left: Math.min(maxLeft, Math.max(VIEWPORT_MARGIN, state.rect.left + deltaX)),\n top: Math.min(maxTop, Math.max(VIEWPORT_MARGIN, state.rect.top + deltaY)),\n width: state.rect.width,\n height: state.rect.height,\n };\n lastRect.current = next;\n setStyle({ position: \"fixed\", transform: \"none\", translate: \"none\", maxWidth: \"none\", maxHeight: \"none\", ...next });\n return;\n }\n\n const corner = state.corner ?? \"top-left\";\n const growsLeft = corner === \"top-left\" || corner === \"bottom-left\";\n const growsUp = corner === \"top-left\" || corner === \"top-right\";\n const right = state.rect.left + state.rect.width;\n const bottom = state.rect.top + state.rect.height;\n const maxWidth = window.innerWidth - VIEWPORT_MARGIN * 2;\n const maxHeight = window.innerHeight - VIEWPORT_MARGIN * 2;\n\n let width = Math.max(\n MIN_PANEL_WIDTH,\n Math.min(maxWidth, growsLeft ? state.rect.width - deltaX : state.rect.width + deltaX),\n );\n let height = Math.max(\n MIN_PANEL_HEIGHT,\n Math.min(maxHeight, growsUp ? state.rect.height - deltaY : state.rect.height + deltaY),\n );\n\n // Clamp the moving edge to the viewport margin too, so growing toward\n // an edge never pushes the opposite (anchored) edge off-screen.\n const left = growsLeft ? right - Math.min(width, right - VIEWPORT_MARGIN) : state.rect.left;\n width = growsLeft ? right - left : Math.min(width, window.innerWidth - VIEWPORT_MARGIN - state.rect.left);\n\n const top = growsUp ? bottom - Math.min(height, bottom - VIEWPORT_MARGIN) : state.rect.top;\n height = growsUp ? bottom - top : Math.min(height, window.innerHeight - VIEWPORT_MARGIN - state.rect.top);\n\n const next: Rect = { left, top, width, height };\n lastRect.current = next;\n setStyle({ position: \"fixed\", transform: \"none\", translate: \"none\", maxWidth: \"none\", maxHeight: \"none\", ...next });\n };\n\n const onPointerUp = (): void => {\n drag.current = null;\n setIsDragging(false);\n };\n\n return {\n style,\n isDragging,\n startMove: beginDrag(\"move\"),\n startResize: (corner) => beginDrag(\"resize\", corner),\n onPointerMove,\n onPointerUp,\n };\n}\n\nexport interface ResponsivePanelProps {\n /** Whether the panel is open. Fully controlled — no internal open state. */\n open: boolean;\n /** Called when Radix wants to change the open state (backdrop click, Esc, close button). */\n onOpenChange: (open: boolean) => void;\n /** Panel title. */\n title: string;\n /** Optional supporting copy shown under the title. */\n description?: string;\n /** Body content of the panel. */\n children: ReactNode;\n /** Optional footer content (typically action buttons). */\n footer?: ReactNode;\n /** Extra classes applied to the panel content, e.g. to override the default width/height. */\n className?: string;\n /**\n * `matchMedia` query that decides desktop vs. mobile layout. Defaults to\n * Tailwind's `lg` breakpoint, matching the rest of `@bmsuisse/ui`'s responsive patterns.\n */\n breakpoint?: string;\n /**\n * Panel size, `sm`/`md`/`lg` (default)/`xl`. On desktop this is the dialog\n * width (`max-w-md`/`max-w-xl`/`max-w-2xl`/`max-w-4xl`); on mobile — where\n * width is always full-bleed — it's the drawer's max height instead\n * (`50vh`/`70vh`/`90vh`/`96vh`).\n */\n size?: ResponsivePanelSize;\n /**\n * Adds drag handles so the user can resize the panel with the mouse:\n * on desktop, a grip on all four corners (each anchors the opposite\n * corner, so `size` just becomes the starting size); on the mobile\n * drawer, a handle at the top (drags height between 30vh and 95vh).\n * Default `false`.\n */\n resizable?: boolean;\n /**\n * Desktop only: lets the user drag the panel by its header to reposition\n * it anywhere in the viewport. Default `false`. No effect on the mobile\n * drawer, which is always docked to the bottom.\n */\n draggable?: boolean;\n /**\n * Whether clicking/tapping outside the panel closes it. Default `true`.\n * When `false`, only the header's close button (and Esc) can close it —\n * use this for panels guarding unsaved work the user shouldn't lose to a\n * stray click.\n */\n closeOnOutsideClick?: boolean;\n}\n\n/**\n * Like `Modal`, but uses the extra desktop space instead of a fixed small\n * dialog, and becomes a native bottom-sheet drawer below `breakpoint` — a\n * centered floating box with its own scroll region reads as a leftover\n * desktop shape on a phone. Use this over `Modal` for content that benefits\n * from more room (multi-section forms, longer lists) on both form factors.\n */\nexport const ResponsivePanel = ({\n open,\n onOpenChange,\n title,\n description,\n children,\n footer,\n className,\n breakpoint = \"(min-width: 1024px)\",\n size = \"lg\",\n resizable = false,\n draggable = false,\n closeOnOutsideClick = true,\n}: ResponsivePanelProps): ReactElement => {\n const isDesktop = useMediaQuery(breakpoint);\n const geometry = useDesktopPanelGeometry();\n const onInteractOutside = closeOnOutsideClick ? undefined : (e: Event): void => e.preventDefault();\n\n if (isDesktop) {\n const corners: Corner[] = [\"top-left\", \"top-right\", \"bottom-left\", \"bottom-right\"];\n return (\n <Dialog open={open} onOpenChange={onOpenChange}>\n <DialogContent\n data-slot=\"dialog-content\"\n onInteractOutside={onInteractOutside}\n style={resizable || draggable ? geometry.style : undefined}\n className={cn(\n \"max-h-[85vh] overflow-y-auto transition-shadow duration-150 ease-out\",\n geometry.isDragging && \"shadow-2xl ring-2 ring-primary/30\",\n desktopSizeClasses[size],\n className,\n )}\n >\n {resizable &&\n corners.map((corner) => (\n <div\n key={corner}\n data-testid={`panel-resize-handle-${corner}`}\n className={cn(\n \"group absolute h-4 w-4 touch-none\",\n cornerPosition[corner],\n cornerCursor[corner],\n )}\n onPointerDown={geometry.startResize(corner)}\n onPointerMove={geometry.onPointerMove}\n onPointerUp={geometry.onPointerUp}\n onPointerCancel={geometry.onPointerUp}\n >\n <div\n className={cn(\n \"absolute h-2 w-2 scale-100 border-muted-foreground/40 transition-transform duration-150 group-hover:scale-125 group-hover:border-primary/60\",\n cornerGripPosition[corner],\n )}\n />\n </div>\n ))}\n <DialogHeader\n className={cn(draggable && \"touch-none cursor-move select-none\")}\n onPointerDown={draggable ? geometry.startMove : undefined}\n onPointerMove={draggable ? geometry.onPointerMove : undefined}\n onPointerUp={draggable ? geometry.onPointerUp : undefined}\n onPointerCancel={draggable ? geometry.onPointerUp : undefined}\n >\n <DialogTitle>{title}</DialogTitle>\n {description ? <DialogDescription>{description}</DialogDescription> : null}\n </DialogHeader>\n {children}\n {footer ? <DialogFooter>{footer}</DialogFooter> : null}\n </DialogContent>\n </Dialog>\n );\n }\n\n return (\n <Sheet open={open} onOpenChange={onOpenChange}>\n <SheetContent\n side=\"bottom\"\n resizable={resizable}\n onInteractOutside={onInteractOutside}\n className={cn(\n \"flex flex-col overflow-y-auto rounded-t-2xl\",\n drawerSizeClasses[size],\n className,\n )}\n >\n <SheetHeader>\n <SheetTitle>{title}</SheetTitle>\n {description ? <SheetDescription>{description}</SheetDescription> : null}\n </SheetHeader>\n {children}\n {footer ? <SheetFooter>{footer}</SheetFooter> : null}\n </SheetContent>\n </Sheet>\n );\n};\n","import { useEffect, useState } from \"react\";\n\n/**\n * Tracks whether a `matchMedia` query currently matches, updating on change.\n * Used to switch between desktop/mobile layouts (see `ResponsivePanel`).\n */\nexport function useMediaQuery(query: string): boolean {\n const [matches, setMatches] = useState(() =>\n typeof window !== \"undefined\" ? window.matchMedia(query).matches : false,\n );\n\n useEffect(() => {\n const mq = window.matchMedia(query);\n setMatches(mq.matches);\n const handler = (e: MediaQueryListEvent): void => setMatches(e.matches);\n mq.addEventListener(\"change\", handler);\n return () => mq.removeEventListener(\"change\", handler);\n }, [query]);\n\n return matches;\n}\n","import type { ReactElement } from \"react\";\nimport { useState } from \"react\";\nimport { Button, type ButtonProps } from \"../../primitives/button\";\nimport { DialogActions } from \"./DialogActions\";\nimport { Modal } from \"./Modal\";\n\nexport interface QuestionDialogAction {\n /** Button label. */\n label: string;\n /** Called when this action is clicked. May return a promise; the dialog waits for it before closing. */\n onClick: () => void | Promise<void>;\n /** Visual style of this action's button. Defaults to `\"default\"`. */\n variant?: ButtonProps[\"variant\"];\n /** Forwarded to this action's `Button`, for test targeting. */\n testId?: string;\n}\n\nexport interface QuestionDialogProps {\n /** Whether the dialog is open. Fully controlled — no internal open state. */\n open: boolean;\n /** Called when Radix wants to change the open state (backdrop click, Esc, close button, Cancel). */\n onOpenChange: (open: boolean) => void;\n /** Dialog title. */\n title: string;\n /** Optional supporting copy shown under the title. */\n description?: string;\n /**\n * The dialog's non-cancel actions, ordered from *nearest Cancel* to *most\n * primary* (see `DialogActions`) — e.g.\n * `[{ label: \"Don't Save\", ... }, { label: \"Save\", ... }]` puts \"Save\",\n * the primary action, at the edge opposite Cancel on every platform,\n * matching native \"Save changes?\"-style dialogs.\n */\n actions: QuestionDialogAction[];\n /** Label for the cancel button. Defaults to `\"Cancel\"`. */\n cancelLabel?: string;\n /** Forwarded to the cancel button, for test targeting. */\n cancelTestId?: string;\n}\n\n/**\n * A dialog asking a question with any number of actions plus a Cancel —\n * `ConfirmDialog` generalized past the fixed confirm/cancel pair, for\n * prompts like \"Save changes before closing?\" (Don't Save / Cancel / Save).\n * Like `ConfirmDialog`, it closes itself automatically after a successful\n * action click — if the clicked action's `onClick` throws/rejects, the\n * dialog stays open (and the error isn't swallowed) so a caller can surface\n * its own error UI. Cancel always closes immediately.\n *\n * Button order follows the current platform's own convention via\n * `DialogActions` — pick `actions`' order by *meaning* (least to most\n * primary), not by which edge Cancel happens to land on.\n */\nexport const QuestionDialog = ({\n open,\n onOpenChange,\n title,\n description,\n actions,\n cancelLabel = \"Cancel\",\n cancelTestId,\n}: QuestionDialogProps): ReactElement => {\n const [pendingIndex, setPendingIndex] = useState<number | null>(null);\n const pending = pendingIndex !== null;\n\n const handleCancel = (): void => {\n onOpenChange(false);\n };\n\n const handleActionClick = async (action: QuestionDialogAction, index: number): Promise<void> => {\n setPendingIndex(index);\n try {\n await action.onClick();\n onOpenChange(false);\n } catch (error) {\n // Do not swallow the failure into a silent no-op: surface it (the\n // caller's own error UI is the right place to react to it in detail)\n // and, critically, leave the dialog open instead of closing it as if\n // nothing happened.\n console.error(error);\n } finally {\n setPendingIndex(null);\n }\n };\n\n return (\n <Modal\n open={open}\n onOpenChange={onOpenChange}\n title={title}\n description={description}\n footer={\n <DialogActions\n actions={actions.map((action, index) => (\n <Button\n key={action.label}\n variant={action.variant ?? \"default\"}\n onClick={() => handleActionClick(action, index)}\n disabled={pending}\n data-testid={action.testId}\n >\n {pendingIndex === index ? `${action.label}…` : action.label}\n </Button>\n ))}\n cancel={\n <Button variant=\"outline\" onClick={handleCancel} disabled={pending} data-testid={cancelTestId}>\n {cancelLabel}\n </Button>\n }\n />\n }\n >\n {null}\n </Modal>\n );\n};\n","import type { ReactElement } from \"react\";\nimport { cloneElement, isValidElement, useId } from \"react\";\nimport { cn } from \"../../lib/utils\";\nimport { Label } from \"../../primitives/label\";\n\nexport interface FormFieldProps {\n /** Visible label text for the field. */\n label: string;\n /** Explicit id to associate the label with the child control. Auto-generated when omitted. */\n htmlFor?: string;\n /** Validation error text. When set, takes precedence over `description` and marks the child as invalid. */\n error?: string;\n /** Helper text shown below the child control when there's no `error`. */\n description?: string;\n /** Renders a visual \"required\" indicator next to the label. */\n required?: boolean;\n /** The single form control (e.g. `Input`, `Textarea`, `Select`) this field wraps. */\n children: ReactElement;\n /** Additional class names for the outer wrapper. */\n className?: string;\n}\n\n/**\n * Wraps a single form control with a `Label`, optional required indicator, and\n * either an `error` or `description` message — the \"label + input + error\"\n * pattern used throughout the consuming apps' forms.\n *\n * Handles id plumbing automatically: generates a stable id (via `useId`) for\n * the label/control pair unless `htmlFor` or the child's own `id` is set, and\n * wires up `aria-invalid` / `aria-describedby` so the error or description\n * text is announced by assistive tech.\n */\nexport function FormField({\n label,\n htmlFor,\n error,\n description,\n required,\n children,\n className,\n}: FormFieldProps): ReactElement {\n const generatedId = useId();\n const resolvedId = htmlFor ?? generatedId;\n const isSingleElement = isValidElement(children);\n const existingChildId = isSingleElement\n ? (children.props as { id?: string }).id\n : undefined;\n const effectiveId = existingChildId ?? resolvedId;\n\n const message = error ?? description;\n const messageId = message ? `${effectiveId}-message` : undefined;\n\n const child = isSingleElement\n ? cloneElement(\n children as ReactElement<{\n id?: string;\n \"aria-invalid\"?: boolean;\n \"aria-describedby\"?: string;\n }>,\n {\n id: effectiveId,\n ...(error ? { \"aria-invalid\": true } : {}),\n ...(messageId ? { \"aria-describedby\": messageId } : {}),\n },\n )\n : children;\n\n return (\n <div className={cn(\"flex flex-col gap-1.5\", className)}>\n <Label htmlFor={effectiveId}>\n {label}\n {required ? (\n <span className=\"text-destructive\" aria-hidden=\"true\">\n {\" \"}\n *\n </span>\n ) : null}\n </Label>\n {child}\n {error ? (\n <p id={messageId} className=\"text-sm text-destructive\">\n {error}\n </p>\n ) : description ? (\n <p id={messageId} className=\"text-sm text-muted-foreground\">\n {description}\n </p>\n ) : null}\n </div>\n );\n}\n","import { Check, ChevronsUpDown, X } from \"lucide-react\";\nimport type { ComponentProps, KeyboardEvent, ReactElement, ReactNode } from \"react\";\nimport { useEffect, useMemo, useRef, useState } from \"react\";\nimport { cn } from \"../../lib/utils\";\nimport {\n buildRenderChunks,\n groupCheckState,\n groupMembers,\n type OptionRow as ImportedOptionRow,\n} from \"../../lib/optionGrouping\";\nimport { renderGridOptions, type GridColumn } from \"../../lib/optionGrid\";\nimport { Button } from \"../../primitives/button\";\nimport { Input } from \"../../primitives/input\";\nimport { Popover, PopoverContent, PopoverTrigger } from \"../../primitives/popover\";\n\nexport interface ComboboxOption {\n value: string;\n label: string;\n disabled?: boolean;\n /** Groups this option under a header with the given key, rendered as a bold label\n * (plus a tri-state \"select all\" checkbox in multi-select mode — see `groupLabels`\n * on the base props). Options sharing a `group` must be contiguous in `options` —\n * the component renders a header the first time a group key is seen and does not\n * re-sort the list, so interleaved groups would render more than one header for the\n * same key. Ungrouped options (no `group`) render individually, with no header.\n * Ignored when `columns` is set (see that prop's own doc). */\n group?: string;\n /** Extra fields for this option, surfaced as additional columns when the\n * base props' `columns` is set — e.g. `{ email: \"a@b.com\", role: \"Admin\" }`.\n * Ignored otherwise. */\n data?: Record<string, ReactNode>;\n}\n\ninterface ComboboxBaseProps {\n /** The full option list. Filtering happens client-side against `label`. */\n options: ComboboxOption[];\n /** Trigger text shown when nothing is selected. Defaults to `\"Select…\"`. */\n placeholder?: string;\n /** Placeholder for the search input inside the popover. Defaults to `\"Search…\"`. */\n searchPlaceholder?: string;\n /** Shown when the search term matches nothing. Defaults to `\"No matches.\"`. */\n emptyMessage?: string;\n disabled?: boolean;\n /** Shows `loadingMessage` on the trigger instead of the placeholder/selection, and\n * disables the trigger and clear affordance alongside `disabled`. For a combobox whose\n * `options` are still being fetched. Defaults to `false`. */\n loading?: boolean;\n /** Trigger text shown while `loading` is true. Defaults to `\"Loading…\"`. */\n loadingMessage?: string;\n /** Shows a clear (\"x\") affordance on the trigger when a value is selected. Defaults to `true`. */\n clearable?: boolean;\n className?: string;\n id?: string;\n /** Forwarded to the trigger button, for test targeting (e.g. Playwright/Testing Library). */\n \"data-testid\"?: string;\n /** Display label for a group key (`ComboboxOption.group`). Falls back to the raw key\n * when an entry is missing. Only relevant when at least one option sets `group`. */\n groupLabels?: Record<string, string>;\n /** Portal target for the popover, forwarded to the underlying `PopoverContent`.\n * Needed when the combobox is opened from inside a modal Dialog/Sheet — pass the\n * Dialog/Sheet content element so the popover portals inside it instead of\n * `document.body`, which would otherwise fight with the Dialog's focus trap. */\n container?: ComponentProps<typeof PopoverContent>[\"container\"];\n /** Switches the search input to server-driven mode: called with the raw search\n * text on every keystroke (and with `\"\"` when the popover opens), and `options`\n * is rendered as-is instead of being filtered locally against `label`. Omit for\n * the default client-side filtering behavior. */\n onSearchChange?: (search: string) => void;\n /** Fallback trigger label used when the current selection's `value`(s) aren't\n * present in `options` — the case in server-driven search mode where the\n * selected option was found by an earlier query and isn't part of the current\n * result page. Ignored once a matching option is found in `options`. */\n selectedLabel?: string;\n /** Renders the popup's option list as a multi-column grid instead of a flat\n * label list — one column per entry here, each reading either the option's\n * own `label` (`key: \"label\"`) or `option.data[key]`. Useful when users need\n * more context than a label to tell options apart (e.g. an id/email/role\n * table instead of a bare name). Mutually exclusive with `group` — a grid\n * row has no natural place for a group header spanning several unrelated\n * columns, so `group` is ignored on every option while this is set. The\n * popup grows to fit the columns (at least as wide as the trigger). */\n columns?: GridColumn[];\n}\n\nexport interface ComboboxSingleProps extends ComboboxBaseProps {\n /** Omitted or `false` for the (default) single-select shape below. */\n multiple?: false;\n /** Selected option's `value`, or `null`/`undefined` for no selection. */\n value?: string | null;\n /** Called with the newly selected option's `value`, or `null` when cleared. */\n onChange: (value: string | null) => void;\n}\n\nexport interface ComboboxMultiProps extends ComboboxBaseProps {\n /** `true` selects the multi-select shape below. */\n multiple: true;\n /** Selected options' `value`s. */\n value: string[];\n /** Called with the full updated selection after a toggle, or `[]` when cleared. */\n onChange: (value: string[]) => void;\n}\n\n/**\n * Discriminated on `multiple`: the default (omitted/`false`) shape is the\n * original single-select API, unchanged (`value: string | null`); passing\n * `multiple: true` switches to the array-valued shape (`value: string[]`).\n */\nexport type ComboboxProps = ComboboxSingleProps | ComboboxMultiProps;\n\n/** If the current multi-select selection is exactly one or more *fully* selected\n * groups and nothing else, returns those groups' labels joined by \", \" (e.g. \"Team A\"\n * or \"Team A, Team B\") — so picking a manager's whole team via its header checkbox\n * shows the team's name on the trigger instead of a bare \"6 selected\". A group\n * selected alongside anything it doesn't fully cover (a partial group, or a full\n * group plus an extra individual pick) returns `null`, falling back to the count. */\nfunction resolveGroupTriggerLabel(\n options: ComboboxOption[],\n selectedValues: string[],\n groupLabel: (group: string) => string,\n): string | null {\n const selectedSet = new Set(selectedValues);\n const groupsPresent = Array.from(\n new Set(options.filter((o) => selectedSet.has(o.value) && o.group).map((o) => o.group as string)),\n );\n if (groupsPresent.length === 0) return null;\n\n const coveredValues = new Set<string>();\n const fullyCoveredGroups: string[] = [];\n for (const group of groupsPresent) {\n const members = groupMembers(options, group);\n if (members.length > 0 && members.every((v) => selectedSet.has(v))) {\n fullyCoveredGroups.push(group);\n for (const v of members) coveredValues.add(v);\n }\n }\n const hasLeftover = selectedValues.some((v) => !coveredValues.has(v));\n if (fullyCoveredGroups.length === 0 || hasLeftover) return null;\n return fullyCoveredGroups.map(groupLabel).join(\", \");\n}\n\ntype OptionRow = ImportedOptionRow<ComboboxOption>;\n\n/**\n * A searchable dropdown (\"autocomplete box\"), single- or multi-select\n * depending on the `multiple` prop: a button trigger showing the current\n * selection, opening a popover with a text filter above a scrollable option\n * list. Deliberately built on the existing `Popover` + `Input` primitives\n * rather than a `cmdk`-based `Command` component — this mirrors\n * `@bmsuisse/datagrid`'s `EnumFilter` (plain substring filter over a manually\n * rendered list), keeping the dependency footprint the same as the rest of\n * this package instead of introducing a new list/command library.\n */\nexport function Combobox(props: ComboboxProps): ReactElement {\n const {\n options,\n placeholder = \"Select…\",\n searchPlaceholder = \"Search…\",\n emptyMessage = \"No matches.\",\n disabled,\n loading = false,\n loadingMessage = \"Loading…\",\n clearable = true,\n className,\n id,\n groupLabels,\n container,\n onSearchChange,\n selectedLabel,\n columns,\n } = props;\n const testId = props[\"data-testid\"];\n const [open, setOpen] = useState(false);\n const [search, setSearch] = useState(\"\");\n const [activeIndex, setActiveIndex] = useState(0);\n const inputRef = useRef<HTMLInputElement>(null);\n\n // Normalize both modes to an array so the rest of the component (rendering,\n // active-index bookkeeping) doesn't need to branch on `multiple` at all —\n // only `selectOption` and the clear affordance need mode-specific behavior.\n const selectedValues = useMemo<string[]>(\n () => (props.multiple ? props.value : props.value ? [props.value] : []),\n [props.multiple, props.value],\n );\n\n const selectedOptions = useMemo(\n () => options.filter((option) => selectedValues.includes(option.value)),\n [options, selectedValues],\n );\n\n // In server-driven search mode (`onSearchChange` given), `options` is assumed\n // to already be the caller's current result set — filtering it again locally\n // against a possibly-stale `search` term would double-filter and could hide\n // options the server already matched on fields other than `label`.\n const visibleOptions = useMemo(() => {\n if (onSearchChange) return options;\n const term = search.trim().toLowerCase();\n if (!term) return options;\n return options.filter((option) => option.label.toLowerCase().includes(term));\n }, [options, search, onSearchChange]);\n\n // Reset the search box and re-point `activeIndex` at the current selection\n // each time the popover opens — intentionally NOT reactive to `options`/\n // `value` changes while it stays open, only to the open transition itself.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n useEffect(() => {\n if (!open) return;\n setSearch(\"\");\n onSearchChange?.(\"\");\n const firstSelected = selectedValues[0];\n const selectedIdx = firstSelected ? options.findIndex((option) => option.value === firstSelected) : -1;\n setActiveIndex(selectedIdx >= 0 ? selectedIdx : 0);\n inputRef.current?.focus();\n }, [open]);\n\n // Keep the active index in range as the visible list shrinks/grows while typing.\n useEffect(() => {\n setActiveIndex((i) => Math.min(i, Math.max(visibleOptions.length - 1, 0)));\n }, [visibleOptions.length]);\n\n function selectOption(option: ComboboxOption): void {\n if (option.disabled) return;\n if (props.multiple) {\n const next = props.value.includes(option.value)\n ? props.value.filter((v) => v !== option.value)\n : [...props.value, option.value];\n props.onChange(next);\n return; // multi-select stays open so the user can pick several\n }\n props.onChange(option.value);\n setOpen(false);\n }\n\n function handleKeyDown(event: KeyboardEvent<HTMLInputElement>): void {\n if (event.key === \"ArrowDown\") {\n event.preventDefault();\n setActiveIndex((i) => Math.min(i + 1, visibleOptions.length - 1));\n } else if (event.key === \"ArrowUp\") {\n event.preventDefault();\n setActiveIndex((i) => Math.max(i - 1, 0));\n } else if (event.key === \"Enter\") {\n event.preventDefault();\n const option = visibleOptions[activeIndex];\n if (option) selectOption(option);\n }\n }\n\n const groupLabel = (group: string): string => groupLabels?.[group] ?? group;\n\n function toggleGroup(group: string): void {\n if (!props.multiple) return;\n const members = groupMembers(options, group);\n const next =\n groupCheckState(options, selectedValues, group) === \"checked\"\n ? props.value.filter((v) => !members.includes(v))\n : Array.from(new Set([...props.value, ...members]));\n props.onChange(next);\n }\n\n // \"N selected\" once 2+ are picked (multi-select only — single-select never exceeds\n // 1); the single label at exactly 1; the placeholder at 0; a fully-selected group's\n // own label(s) in place of the count when that applies (see resolveGroupTriggerLabel).\n const triggerLabel = loading\n ? loadingMessage\n : selectedOptions.length === 0\n ? (selectedValues.length > 0 ? (selectedLabel ?? placeholder) : placeholder)\n : selectedOptions.length === 1\n ? (selectedOptions[0]?.label ?? placeholder)\n : (props.multiple ? resolveGroupTriggerLabel(options, selectedValues, groupLabel) : null) ??\n `${selectedOptions.length} selected`;\n\n // Skipped entirely in grid mode (`columns` set) — its result is only ever\n // read from the flat/grouped rendering branch below, so building it there\n // would just re-walk `visibleOptions` on every keystroke for a value\n // nothing then reads.\n const renderChunks = useMemo(() => (columns ? [] : buildRenderChunks(visibleOptions)), [visibleOptions, columns]);\n\n function renderOption({ option, index }: OptionRow): ReactElement {\n const isSelected = selectedValues.includes(option.value);\n const isActive = index === activeIndex;\n return (\n <button\n key={option.value}\n type=\"button\"\n role=\"option\"\n aria-selected={isSelected}\n disabled={option.disabled}\n data-testid={testId ? `${testId}-option` : undefined}\n data-option-value={option.value}\n onMouseEnter={() => setActiveIndex(index)}\n onClick={() => selectOption(option)}\n className={cn(\n \"flex w-full items-center gap-2 rounded-sm px-2 py-1.5 text-left text-sm outline-none disabled:pointer-events-none disabled:opacity-50\",\n isActive && \"bg-accent text-accent-foreground\",\n )}\n >\n {props.multiple ? (\n <input\n type=\"checkbox\"\n checked={isSelected}\n readOnly\n tabIndex={-1}\n className=\"pointer-events-none h-3.5 w-3.5 shrink-0 accent-primary\"\n />\n ) : (\n <Check className={cn(\"h-4 w-4 shrink-0\", isSelected ? \"opacity-100\" : \"opacity-0\")} />\n )}\n <span className=\"truncate\">{option.label}</span>\n </button>\n );\n }\n\n return (\n <Popover open={open} onOpenChange={setOpen}>\n <PopoverTrigger asChild>\n <Button\n id={id}\n data-testid={testId}\n type=\"button\"\n variant=\"outline\"\n role=\"combobox\"\n aria-expanded={open}\n disabled={disabled || loading}\n className={cn(\n \"w-full justify-between font-normal\",\n (selectedOptions.length === 0 || loading) && \"text-muted-foreground\",\n className,\n )}\n >\n <span className=\"truncate\">{triggerLabel}</span>\n <span className=\"flex items-center gap-1\">\n {clearable && !loading && selectedValues.length > 0 ? (\n <span\n role=\"button\"\n aria-label=\"Clear selection\"\n tabIndex={-1}\n className=\"rounded-sm p-0.5 opacity-60 hover:bg-accent hover:opacity-100\"\n onClick={(event) => {\n event.stopPropagation();\n if (props.multiple) {\n props.onChange([]);\n } else {\n props.onChange(null);\n }\n }}\n >\n <X className=\"h-3.5 w-3.5\" />\n </span>\n ) : null}\n <ChevronsUpDown className=\"h-4 w-4 shrink-0 opacity-50\" aria-hidden=\"true\" />\n </span>\n </Button>\n </PopoverTrigger>\n <PopoverContent\n align=\"start\"\n container={container}\n className={cn(\n \"w-[var(--radix-popover-trigger-width)] min-w-[10rem] p-2\",\n columns && \"w-max min-w-[var(--radix-popover-trigger-width)] max-w-[min(40rem,90vw)]\",\n )}\n onOpenAutoFocus={(event) => event.preventDefault()}\n >\n <div className=\"flex flex-col gap-2\">\n <Input\n ref={inputRef}\n value={search}\n onChange={(event) => {\n setSearch(event.target.value);\n onSearchChange?.(event.target.value);\n }}\n onKeyDown={handleKeyDown}\n placeholder={searchPlaceholder}\n aria-label={searchPlaceholder}\n />\n <div role=\"listbox\" className={cn(\"max-h-60 overflow-y-auto\", !columns && \"flex flex-col gap-0.5\")}>\n {visibleOptions.length === 0 ? (\n <p className=\"py-2 text-center text-sm text-muted-foreground\">{emptyMessage}</p>\n ) : columns ? (\n renderGridOptions({\n columns,\n options: visibleOptions,\n activeIndex,\n multiple: Boolean(props.multiple),\n isSelected: (option) => selectedValues.includes(option.value),\n onSelect: selectOption,\n onHover: setActiveIndex,\n testId,\n })\n ) : (\n renderChunks.map((chunk) => {\n if (chunk.kind === \"single\") return renderOption(chunk.row);\n const headerState = groupCheckState(options, selectedValues, chunk.group);\n return (\n // The header and every one of its group's rows share this wrapper --\n // its bounds are the sticky header's containing block, so `sticky top-0`\n // keeps the header pinned for the group's whole scroll extent instead of\n // just past its first row (see buildRenderChunks). Spacing above a group\n // lives on this wrapper's `pt-1`, not on the header itself -- a margin on\n // the sticky element would travel with it once stuck, leaving a gap at the\n // scrollport's top that the row behind it shows through.\n <div key={`group-${chunk.group}`} className=\"flex flex-col gap-0.5 pt-1 first:pt-0\">\n <div\n data-group-header\n className=\"sticky top-0 z-10 flex items-center gap-2 rounded-sm bg-muted px-2 py-1.5 text-sm font-semibold text-foreground\"\n >\n {props.multiple ? (\n <input\n type=\"checkbox\"\n checked={headerState === \"checked\"}\n ref={(el) => {\n if (el) el.indeterminate = headerState === \"indeterminate\";\n }}\n onChange={() => toggleGroup(chunk.group)}\n onClick={(event) => event.stopPropagation()}\n className=\"h-3.5 w-3.5 shrink-0 accent-primary\"\n aria-label={`Select all of ${groupLabel(chunk.group)}`}\n />\n ) : null}\n <span className=\"truncate\">{groupLabel(chunk.group)}</span>\n </div>\n {chunk.rows.map(renderOption)}\n </div>\n );\n })\n )}\n </div>\n </div>\n </PopoverContent>\n </Popover>\n );\n}\n","/** Minimal shape shared by `ComboboxOption` and `TagComboboxOption` — everything\n * the grouping helpers below actually touch. Both components keep their own,\n * richer option type; this exists purely so the two don't hand-duplicate the\n * same grouping logic (and risk it drifting between them on a future fix). */\nexport interface GroupableOption {\n value: string;\n group?: string;\n disabled?: boolean;\n}\n\nexport function groupMembers<T extends GroupableOption>(options: T[], group: string): string[] {\n return options.filter((o) => o.group === group && !o.disabled).map((o) => o.value);\n}\n\nexport type GroupCheckState = \"checked\" | \"unchecked\" | \"indeterminate\";\n\nexport function groupCheckState<T extends GroupableOption>(\n options: T[],\n selectedValues: string[],\n group: string,\n): GroupCheckState {\n const members = groupMembers(options, group);\n const selectedCount = members.filter((v) => selectedValues.includes(v)).length;\n if (selectedCount === 0) return \"unchecked\";\n return selectedCount === members.length ? \"checked\" : \"indeterminate\";\n}\n\nexport interface OptionRow<T extends GroupableOption> {\n option: T;\n index: number;\n}\nexport interface GroupChunk<T extends GroupableOption> {\n kind: \"group\";\n group: string;\n rows: OptionRow<T>[];\n}\nexport interface SingleChunk<T extends GroupableOption> {\n kind: \"single\";\n row: OptionRow<T>;\n}\nexport type RenderChunk<T extends GroupableOption> = GroupChunk<T> | SingleChunk<T>;\n\n/** Chunks `visibleOptions` into per-group chunks (a header plus all of that group's\n * rows, relying on the \"a group's options are contiguous\" invariant `group` already\n * documents on both option types) versus lone ungrouped rows, in one linear pass --\n * kept separate from JSX so a caller's render is a plain `.map()` with no per-row\n * bookkeeping of its own. A sticky header can only stay pinned within its own\n * containing block -- the nearest ancestor that isn't itself sticky/statically laid\n * out -- so the header and every one of its group's rows must share one wrapper\n * element. Rendering each row in its own top-level sibling div (rather than chunking\n * by group) gave the header a containing block of just itself plus the group's first\n * row, so it unstuck after a single row instead of staying pinned for the group's\n * full scroll extent. */\nexport function buildRenderChunks<T extends GroupableOption>(visibleOptions: T[]): RenderChunk<T>[] {\n const chunks: RenderChunk<T>[] = [];\n visibleOptions.forEach((option, index) => {\n const row: OptionRow<T> = { option, index };\n const last = chunks[chunks.length - 1];\n if (option.group && last?.kind === \"group\" && last.group === option.group) {\n last.rows.push(row);\n } else if (option.group) {\n chunks.push({ kind: \"group\", group: option.group, rows: [row] });\n } else {\n chunks.push({ kind: \"single\", row });\n }\n });\n return chunks;\n}\n","import type { ReactElement, ReactNode } from \"react\";\nimport { cn } from \"./utils\";\nimport type { GroupableOption } from \"./optionGrouping\";\nimport { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from \"../primitives/table\";\n\n/** A column shown in a grid-style option popup (see `renderGridOptions`). `key`\n * selects what each row shows in that column: the literal string `\"label\"` reads\n * the option's own `label`, anything else reads `option.data?.[key]`. */\nexport interface GridColumn {\n key: string;\n header: string;\n className?: string;\n}\n\n/** Minimal shape `renderGridOptions` needs from an option — both `ComboboxOption`\n * and `TagComboboxOption` satisfy this once they carry `data`. */\nexport interface GridableOption extends GroupableOption {\n label: string;\n data?: Record<string, ReactNode>;\n}\n\ninterface RenderGridOptionsProps<T extends GridableOption> {\n columns: GridColumn[];\n options: T[];\n activeIndex: number;\n multiple: boolean;\n isSelected: (option: T) => boolean;\n onSelect: (option: T) => void;\n onHover: (index: number) => void;\n testId?: string;\n}\n\n/**\n * Renders `options` as a table (built on the same `Table`/`TableRow`/`TableCell`\n * primitives every other table in this package uses, so a future styling tweak\n * there — borders, checkbox-column padding, etc. — reaches this too) instead of\n * the default flat label list — the `columns` counterpart to `buildRenderChunks`'s\n * grouped-label rendering. Deliberately ignores each option's `group` (an\n * option-grid header spanning several unrelated columns has no obvious layout,\n * and no caller has asked for it yet) — grid mode and grouping are mutually\n * exclusive, documented on the `columns` prop of both `Combobox` and `TagCombobox`.\n */\nexport function renderGridOptions<T extends GridableOption>({\n columns,\n options,\n activeIndex,\n multiple,\n isSelected,\n onSelect,\n onHover,\n testId,\n}: RenderGridOptionsProps<T>): ReactElement {\n return (\n <Table className=\"text-sm\">\n <TableHeader>\n <TableRow className=\"hover:bg-transparent\">\n {multiple && <TableHead className=\"sticky top-0 z-10 w-6 bg-muted\" />}\n {columns.map((column) => (\n <TableHead\n key={column.key}\n className={cn(\"sticky top-0 z-10 whitespace-nowrap bg-muted text-xs\", column.className)}\n >\n {column.header}\n </TableHead>\n ))}\n </TableRow>\n </TableHeader>\n <TableBody>\n {options.map((option, index) => {\n const selected = isSelected(option);\n const active = index === activeIndex;\n return (\n <TableRow\n key={option.value}\n role=\"option\"\n aria-selected={selected}\n // Otherwise a screen reader reads every column's text as the option's\n // name (e.g. \"Germany Berlin Europe\") instead of just its label,\n // unlike the flat list's <button>, whose accessible name is the\n // label alone.\n aria-label={option.label}\n aria-disabled={option.disabled}\n data-testid={testId ? `${testId}-option` : undefined}\n data-option-value={option.value}\n onMouseEnter={() => onHover(index)}\n onClick={() => {\n if (!option.disabled) onSelect(option);\n }}\n className={cn(\n \"cursor-pointer outline-none\",\n // `hover:bg-accent` repeats the active row's own background under\n // `:hover` -- otherwise TableRow's default `hover:bg-muted/50`\n // would win over the plain `bg-accent` below (later in the\n // stylesheet) and flash the active/keyboard-selected row to the\n // wrong color the instant the mouse sits over it.\n active && \"bg-accent text-accent-foreground hover:bg-accent hover:text-accent-foreground\",\n option.disabled && \"pointer-events-none opacity-50\",\n )}\n >\n {multiple && (\n <TableCell className=\"w-6\">\n <input\n type=\"checkbox\"\n checked={selected}\n readOnly\n tabIndex={-1}\n className=\"pointer-events-none h-3.5 w-3.5 shrink-0 accent-primary\"\n />\n </TableCell>\n )}\n {columns.map((column) => (\n <TableCell key={column.key} className={cn(\"truncate\", column.className)}>\n {column.key === \"label\" ? option.label : option.data?.[column.key]}\n </TableCell>\n ))}\n </TableRow>\n );\n })}\n </TableBody>\n </Table>\n );\n}\n","import { X } from \"lucide-react\";\nimport type { ComponentProps, KeyboardEvent, ReactElement, ReactNode } from \"react\";\nimport { useEffect, useMemo, useRef, useState } from \"react\";\nimport { cn } from \"../../lib/utils\";\nimport {\n buildRenderChunks,\n groupCheckState,\n groupMembers,\n type OptionRow,\n} from \"../../lib/optionGrouping\";\nimport { renderGridOptions, type GridColumn } from \"../../lib/optionGrid\";\nimport { Popover, PopoverAnchor, PopoverContent } from \"../../primitives/popover\";\n\nexport interface TagComboboxOption {\n value: string;\n label: string;\n disabled?: boolean;\n /** Groups this option under a header with the given key, rendered as a bold label\n * plus a tri-state \"select all\" checkbox (unchecked/checked/indeterminate, reflecting\n * how many of the group's members are selected — toggling it selects or clears the\n * whole group). Options sharing a `group` must be contiguous in `options` — see\n * `Combobox`'s own `group` doc for the same constraint and the reasoning behind it.\n * Ignored when `columns` is set (see that prop's own doc). */\n group?: string;\n /** Extra fields for this option, surfaced as additional columns when\n * `columns` is set — e.g. `{ email: \"a@b.com\", role: \"Admin\" }`. Ignored\n * otherwise. */\n data?: Record<string, ReactNode>;\n}\n\nexport interface TagComboboxProps {\n /** The full option list. Filtering happens client-side against `label`,\n * unless `onSearchChange` is given (see below). */\n options: TagComboboxOption[];\n /** Selected options' `value`s. */\n value: string[];\n /** Called with the full updated selection after a toggle or a chip removal. */\n onChange: (value: string[]) => void;\n /** Shown in the field when nothing is selected and nothing is typed. Defaults to `\"Select…\"`. */\n placeholder?: string;\n /** Shown when the search term matches nothing. Defaults to `\"No matches.\"`. */\n emptyMessage?: string;\n disabled?: boolean;\n /** Shows `loadingMessage` in the option list instead of `emptyMessage`, for a\n * combobox whose `options` are still being fetched (e.g. a server search whose\n * request hasn't resolved yet). Defaults to `false`. */\n loading?: boolean;\n /** Message shown in the option list while `loading` is true. Defaults to `\"Loading…\"`. */\n loadingMessage?: string;\n className?: string;\n id?: string;\n /** Forwarded to the field, for test targeting (e.g. Playwright/Testing Library). */\n \"data-testid\"?: string;\n /** Switches the search input to server-driven mode: called with the raw search\n * text on every keystroke, and `options` is rendered as-is instead of being\n * filtered locally against `label`. Omit for the default client-side filtering\n * behavior — see `Combobox`'s own `onSearchChange` for the same contract. */\n onSearchChange?: (search: string) => void;\n /** Portal target for the popover, forwarded to the underlying `PopoverContent`.\n * Needed when the combobox is opened from inside a modal Dialog/Sheet — pass the\n * Dialog/Sheet content element so the popover portals inside it instead of\n * `document.body`, which would otherwise fight with the Dialog's focus trap. */\n container?: ComponentProps<typeof PopoverContent>[\"container\"];\n /** Display label for a group key (`TagComboboxOption.group`). Falls back to the raw\n * key when an entry is missing. Only relevant when at least one option sets `group`. */\n groupLabels?: Record<string, string>;\n /** Renders the popup's option list as a multi-column grid instead of a flat\n * label list — see `Combobox`'s own `columns` doc for the full contract\n * (including its interaction with `group`, and the widened popup). */\n columns?: GridColumn[];\n}\n\n/**\n * A tags-and-search multi-select: selected options render as removable chips\n * inline inside one bordered field, with a search input immediately after\n * the last chip. Typing opens a popover listing matches below the field;\n * picking one adds a chip right where the caret was and clears the search\n * term so the user can keep typing. Complements `Combobox`'s `multiple`\n * mode (a trigger button + a summary count) for the case where every\n * individual selection needs to stay visible and removable at a glance —\n * built on the same `Popover`/keyboard-nav shape rather than forking it,\n * so both patterns share one mental model.\n */\nexport function TagCombobox({\n options,\n value,\n onChange,\n placeholder = \"Select…\",\n emptyMessage = \"No matches.\",\n disabled,\n loading = false,\n loadingMessage = \"Loading…\",\n className,\n id,\n onSearchChange,\n container,\n groupLabels,\n columns,\n ...rest\n}: TagComboboxProps): ReactElement {\n const testId = rest[\"data-testid\"];\n const [open, setOpen] = useState(false);\n const [search, setSearch] = useState(\"\");\n const [activeIndex, setActiveIndex] = useState(0);\n const inputRef = useRef<HTMLInputElement>(null);\n const fieldRef = useRef<HTMLDivElement>(null);\n\n const selectedOptions = useMemo(\n () => value.map((v) => options.find((o) => o.value === v) ?? { value: v, label: v }),\n [options, value],\n );\n\n // In server-driven search mode (`onSearchChange` given), `options` is assumed\n // to already be the caller's current result set — filtering it again locally\n // against a possibly-stale `search` term would double-filter and could hide\n // options the server already matched on fields other than `label`.\n const visibleOptions = useMemo(() => {\n if (onSearchChange) return options;\n const term = search.trim().toLowerCase();\n if (!term) return options;\n return options.filter((option) => option.label.toLowerCase().includes(term));\n }, [options, search, onSearchChange]);\n\n useEffect(() => {\n setActiveIndex((i) => Math.min(Math.max(i, 0), Math.max(visibleOptions.length - 1, 0)));\n }, [visibleOptions.length]);\n\n // Skipped entirely in grid mode (`columns` set) — see `Combobox`'s own\n // identical `renderChunks` doc for why.\n const renderChunks = useMemo(() => (columns ? [] : buildRenderChunks(visibleOptions)), [visibleOptions, columns]);\n\n // Reset the search term and re-point `activeIndex` each time the popover\n // opens -- intentionally NOT reactive to `options`/`value` changes while it\n // stays open, only to the open transition itself, mirroring `Combobox`'s\n // own identical effect. Harmless (and idempotent) when `open` becomes true\n // via focus right before the user starts typing: search is already \"\" at\n // that point, since typing is what would change it.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n useEffect(() => {\n if (!open) return;\n setSearch(\"\");\n onSearchChange?.(\"\");\n const firstSelected = value[0];\n const selectedIdx = firstSelected ? options.findIndex((o) => o.value === firstSelected) : -1;\n setActiveIndex(selectedIdx >= 0 ? selectedIdx : 0);\n }, [open]);\n\n function updateSearch(next: string): void {\n setSearch(next);\n onSearchChange?.(next);\n if (!open) setOpen(true);\n }\n\n function toggleOption(option: TagComboboxOption): void {\n if (option.disabled) return;\n const next = value.includes(option.value) ? value.filter((v) => v !== option.value) : [...value, option.value];\n onChange(next);\n updateSearch(\"\");\n inputRef.current?.focus();\n }\n\n function removeValue(v: string): void {\n // Mirrors toggleOption's own guard: an option disabled in the caller's\n // `options` list can't be deselected via its dropdown row, so its chip's\n // own remove button (and the Backspace shortcut, which calls this too)\n // must refuse it the same way instead of silently bypassing that.\n if (options.find((o) => o.value === v)?.disabled) return;\n onChange(value.filter((existing) => existing !== v));\n }\n\n const groupLabel = (group: string): string => groupLabels?.[group] ?? group;\n\n // Deliberately uses the full `options` list, not `visibleOptions` -- a\n // group's checkbox/toggle must reflect and act on every member, including\n // ones the current search term is hiding, matching `Combobox`'s own\n // `toggleGroup`/header-state contract for the same reason.\n function toggleGroup(group: string): void {\n const members = groupMembers(options, group);\n const next =\n groupCheckState(options, value, group) === \"checked\"\n ? value.filter((v) => !members.includes(v))\n : Array.from(new Set([...value, ...members]));\n onChange(next);\n inputRef.current?.focus();\n }\n\n function handleKeyDown(event: KeyboardEvent<HTMLInputElement>): void {\n if (event.key === \"ArrowDown\") {\n event.preventDefault();\n setOpen(true);\n setActiveIndex((i) => Math.min(i + 1, Math.max(visibleOptions.length - 1, 0)));\n } else if (event.key === \"ArrowUp\") {\n event.preventDefault();\n setActiveIndex((i) => Math.max(i - 1, 0));\n } else if (event.key === \"Enter\") {\n event.preventDefault();\n const option = visibleOptions[activeIndex];\n if (option) toggleOption(option);\n } else if (event.key === \"Escape\") {\n setOpen(false);\n } else if (event.key === \"Backspace\" && search === \"\") {\n // Standard tag-input convention: Backspace on an empty search field\n // removes the most recently added chip instead of doing nothing.\n const last = value[value.length - 1];\n if (last !== undefined) removeValue(last);\n }\n }\n\n function renderOption({ option, index }: OptionRow<TagComboboxOption>): ReactElement {\n const isSelected = value.includes(option.value);\n const isActive = index === activeIndex;\n return (\n <button\n key={option.value}\n type=\"button\"\n role=\"option\"\n aria-selected={isSelected}\n disabled={option.disabled}\n data-testid={testId ? `${testId}-option` : undefined}\n data-option-value={option.value}\n onMouseEnter={() => setActiveIndex(index)}\n onClick={() => toggleOption(option)}\n className={cn(\n \"flex w-full items-center gap-2 rounded-sm px-2 py-1.5 text-left text-sm outline-none disabled:pointer-events-none disabled:opacity-50\",\n isActive && \"bg-accent text-accent-foreground\",\n )}\n >\n <input\n type=\"checkbox\"\n checked={isSelected}\n readOnly\n tabIndex={-1}\n className=\"pointer-events-none h-3.5 w-3.5 shrink-0 accent-primary\"\n />\n <span className=\"truncate\">{option.label}</span>\n </button>\n );\n }\n\n return (\n <Popover open={open} onOpenChange={setOpen}>\n <PopoverAnchor asChild>\n <div\n ref={fieldRef}\n data-testid={testId}\n role=\"combobox\"\n aria-expanded={open}\n aria-disabled={disabled}\n className={cn(\n \"flex min-h-9 w-full flex-wrap items-center gap-1.5 rounded-md border border-input bg-transparent px-2 py-1.5 text-sm\",\n \"focus-within:outline-none focus-within:ring-2 focus-within:ring-ring\",\n disabled && \"cursor-not-allowed opacity-50\",\n className,\n )}\n onClick={() => {\n if (!disabled) inputRef.current?.focus();\n }}\n >\n {selectedOptions.map((option) => (\n <span\n key={option.value}\n className=\"inline-flex items-center gap-1 rounded-full bg-muted py-0.5 pr-1 pl-2.5 text-xs font-medium text-muted-foreground\"\n >\n <span className=\"max-w-48 truncate\">{option.label}</span>\n {!disabled && (\n <button\n type=\"button\"\n aria-label={`Remove ${option.label}`}\n className=\"rounded-full p-0.5 hover:bg-accent hover:text-accent-foreground\"\n onClick={(event) => {\n event.stopPropagation();\n removeValue(option.value);\n }}\n >\n <X className=\"h-3 w-3\" />\n </button>\n )}\n </span>\n ))}\n <input\n ref={inputRef}\n id={id}\n value={search}\n disabled={disabled}\n placeholder={selectedOptions.length === 0 ? placeholder : undefined}\n aria-label={placeholder}\n className=\"min-w-24 flex-1 bg-transparent outline-none placeholder:text-muted-foreground disabled:cursor-not-allowed\"\n onFocus={() => setOpen(true)}\n onChange={(event) => updateSearch(event.target.value)}\n onKeyDown={handleKeyDown}\n />\n </div>\n </PopoverAnchor>\n <PopoverContent\n align=\"start\"\n container={container}\n className={cn(\n \"w-[var(--radix-popover-trigger-width)] min-w-[10rem] p-2\",\n columns && \"w-max min-w-[var(--radix-popover-trigger-width)] max-w-[min(40rem,90vw)]\",\n )}\n onOpenAutoFocus={(event) => event.preventDefault()}\n onCloseAutoFocus={(event) => event.preventDefault()}\n // Radix's non-modal Popover content treats a focus/pointer event as\n // \"outside\" (and dismisses) unless the target is inside the content\n // itself or is the registered `PopoverTrigger` -- but this field uses\n // `PopoverAnchor`, which never registers a trigger ref, and\n // `toggleOption`/`removeValue` deliberately refocus `inputRef` (which\n // lives in the anchor, not inside this portaled content) after every\n // pick so the user can keep typing. Without this guard, that refocus\n // itself reads as \"focus left to somewhere outside\" and closes the\n // popover right after each selection.\n onInteractOutside={(event) => {\n if (fieldRef.current?.contains(event.target as Node)) event.preventDefault();\n }}\n >\n <div role=\"listbox\" className={cn(\"max-h-60 overflow-y-auto\", !columns && \"flex flex-col gap-0.5\")}>\n {loading ? (\n <p className=\"py-2 text-center text-sm text-muted-foreground\">{loadingMessage}</p>\n ) : visibleOptions.length === 0 ? (\n <p className=\"py-2 text-center text-sm text-muted-foreground\">{emptyMessage}</p>\n ) : columns ? (\n renderGridOptions({\n columns,\n options: visibleOptions,\n activeIndex,\n multiple: true,\n isSelected: (option) => value.includes(option.value),\n onSelect: toggleOption,\n onHover: setActiveIndex,\n testId,\n })\n ) : (\n renderChunks.map((chunk) => {\n if (chunk.kind === \"single\") return renderOption(chunk.row);\n const headerState = groupCheckState(options, value, chunk.group);\n return (\n // The header and every one of its group's rows share this wrapper -- its\n // bounds are the sticky header's containing block, so `sticky top-0` keeps\n // the header pinned for the group's whole scroll extent instead of just\n // past its first row. Spacing above a group lives on this wrapper's\n // `pt-1`/`first:pt-0`, not on the header itself -- see `Combobox`'s own\n // identical structure for why both of these matter.\n <div key={`group-${chunk.group}`} className=\"flex flex-col gap-0.5 pt-1 first:pt-0\">\n <div\n data-group-header\n className=\"sticky top-0 z-10 flex items-center gap-2 rounded-sm bg-muted px-2 py-1.5 text-sm font-semibold text-foreground\"\n >\n <input\n type=\"checkbox\"\n checked={headerState === \"checked\"}\n ref={(el) => {\n if (el) el.indeterminate = headerState === \"indeterminate\";\n }}\n onChange={() => toggleGroup(chunk.group)}\n onClick={(event) => event.stopPropagation()}\n className=\"h-3.5 w-3.5 shrink-0 accent-primary\"\n aria-label={`Select all of ${groupLabel(chunk.group)}`}\n />\n <span className=\"truncate\">{groupLabel(chunk.group)}</span>\n </div>\n {chunk.rows.map(renderOption)}\n </div>\n );\n })\n )}\n </div>\n </PopoverContent>\n </Popover>\n );\n}\n","import { AlertCircle, AlertTriangle, CheckCircle2, Info } from \"lucide-react\";\nimport type { ReactElement, ReactNode } from \"react\";\nimport { cn } from \"../../lib/utils\";\n\nexport type AlertBoxVariant = \"error\" | \"warning\" | \"info\" | \"success\";\n\nexport interface AlertBoxProps {\n /** Determines the color scheme and the default icon. */\n variant: AlertBoxVariant;\n /** Optional bold heading line shown above the body content. */\n title?: string;\n /** Body text/content. Always rendered. */\n children: ReactNode;\n className?: string;\n /**\n * Overrides the default variant icon entirely. Pass `null` to hide the\n * icon. Defaults to a variant-specific lucide-react icon.\n */\n icon?: ReactNode;\n}\n\n// `error` borders/background reuse the shared `destructive` theme token, but the text\n// color is a fixed red rather than `text-destructive` because that token is tuned for\n// solid button fills, not small text on a tinted background, and fails WCAG AA contrast\n// there. `warning`/`info`/`success` have no equivalent tokens in @bmsuisse/ui's theme (it\n// only defines background/foreground/primary/muted/popover/accent/destructive/border/\n// input/ring), so these three variants use fixed Tailwind palette colors instead of theme\n// tokens. A consumer app with different brand colors will need to override these via\n// `className`.\nconst variantStyles: Record<AlertBoxVariant, string> = {\n error: \"border-destructive bg-destructive/10 text-red-800 dark:text-red-300\",\n warning: \"border-amber-500 bg-amber-500/10 text-amber-900 dark:text-amber-200\",\n info: \"border-sky-500 bg-sky-500/10 text-sky-700 dark:text-sky-300\",\n success: \"border-emerald-500 bg-emerald-500/10 text-emerald-700 dark:text-emerald-300\",\n};\n\nconst defaultIcons: Record<AlertBoxVariant, ReactElement> = {\n error: <AlertCircle className=\"h-4 w-4 shrink-0\" aria-hidden=\"true\" />,\n warning: <AlertTriangle className=\"h-4 w-4 shrink-0\" aria-hidden=\"true\" />,\n info: <Info className=\"h-4 w-4 shrink-0\" aria-hidden=\"true\" />,\n success: <CheckCircle2 className=\"h-4 w-4 shrink-0\" aria-hidden=\"true\" />,\n};\n\nexport const AlertBox = ({ variant, title, children, className, icon }: AlertBoxProps): ReactElement => {\n const resolvedIcon = icon === undefined ? defaultIcons[variant] : icon;\n\n return (\n <div className={cn(\"rounded-md border p-3 text-sm\", variantStyles[variant], className)}>\n <div className=\"flex flex-row items-start gap-2\">\n {resolvedIcon != null && <span className=\"mt-0.5 shrink-0\">{resolvedIcon}</span>}\n <div className=\"flex flex-col gap-1\">\n {title && <p className=\"font-bold\">{title}</p>}\n <div>{children}</div>\n </div>\n </div>\n </div>\n );\n};\n","import type { HTMLAttributes, ReactElement } from \"react\";\nimport { cn } from \"../../lib/utils\";\nimport { Badge } from \"../../primitives/badge\";\n\n/** Semantic color intent for a {@link StatusBadge}. */\nexport type StatusTone = \"success\" | \"warning\" | \"error\" | \"info\" | \"neutral\";\n\n/**\n * Class names per tone. `success` / `warning` / `info` fall back to fixed\n * Tailwind palette shades (with `dark:` variants, since this package's dark\n * mode is a `.dark` ancestor class) because the shared theme currently only\n * defines background/foreground/primary/muted/popover/accent/destructive/\n * border/input/ring tokens — no warning/info/success tokens exist yet, same\n * reasoning AlertBox uses for those tones. `neutral` reuses the `muted` token\n * directly; `error` reuses `destructive` for the tint but, like AlertBox, uses a\n * fixed red for the text because `text-destructive` is tuned for solid button\n * fills and only reaches ~3.9:1 (light) / ~3.5:1 (dark) on its own 15% tint.\n */\nconst TONE_CLASSES: Record<StatusTone, string> = {\n success: \"border-transparent bg-emerald-500/15 text-emerald-700 dark:bg-emerald-500/20 dark:text-emerald-300\",\n warning: \"border-transparent bg-amber-500/15 text-amber-800 dark:bg-amber-500/20 dark:text-amber-300\",\n info: \"border-transparent bg-sky-500/15 text-sky-700 dark:bg-sky-500/20 dark:text-sky-300\",\n error: \"border-transparent bg-destructive/15 text-red-800 dark:text-red-300\",\n neutral: \"border-transparent bg-muted text-muted-foreground\",\n};\n\n/** Built-in status vocabulary, matched case-insensitively against `status.toLowerCase()`. */\nconst DEFAULT_TONE_MAP: Record<string, StatusTone> = {\n active: \"success\",\n approved: \"success\",\n completed: \"success\",\n paid: \"success\",\n done: \"success\",\n pending: \"warning\",\n draft: \"warning\",\n in_review: \"warning\",\n inreview: \"warning\",\n rejected: \"error\",\n failed: \"error\",\n cancelled: \"error\",\n canceled: \"error\",\n overdue: \"error\",\n inactive: \"neutral\",\n archived: \"neutral\",\n new: \"info\",\n};\n\n/** Title-cases a raw status value and replaces underscores/hyphens with spaces, e.g. `\"in_review\"` -> `\"In Review\"`. */\nfunction deriveLabel(status: string): string {\n return status\n .replace(/[_-]+/g, \" \")\n .trim()\n .split(/\\s+/)\n .filter(Boolean)\n .map((word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase())\n .join(\" \");\n}\n\n/**\n * Resolves a status to a {@link StatusTone}.\n *\n * Resolution order: explicit `tone` prop > caller's `toneMap` (case-insensitive\n * key match) > built-in default map (case-insensitive) > `neutral` fallback.\n */\nfunction resolveTone(status: string, tone?: StatusTone, toneMap?: Record<string, StatusTone>): StatusTone {\n if (tone) {\n return tone;\n }\n\n const key = status.toLowerCase();\n\n if (toneMap) {\n for (const [candidate, candidateTone] of Object.entries(toneMap)) {\n if (candidate.toLowerCase() === key) {\n return candidateTone;\n }\n }\n }\n\n return DEFAULT_TONE_MAP[key] ?? \"neutral\";\n}\n\nexport interface StatusBadgeProps extends Omit<HTMLAttributes<HTMLDivElement>, \"children\"> {\n /** Raw status value from the caller's domain, e.g. `\"pending\"`, `\"APPROVED\"`, `\"in_review\"`. */\n status: string;\n /** Overrides the displayed text. Defaults to a title-cased, space-separated derivation of `status`. */\n label?: string;\n /** Explicit tone override. When provided, `toneMap` and the built-in default map are skipped entirely. */\n tone?: StatusTone;\n /** Caller-supplied status-to-tone mapping (case-insensitive keys), checked before the built-in default map. */\n toneMap?: Record<string, StatusTone>;\n}\n\n/**\n * A status-to-color badge, built on the shared `Badge` primitive.\n *\n * Centralizes the status->color mapping that's otherwise reimplemented ad hoc\n * per app: callers can rely on the built-in English status vocabulary, supply\n * their own `toneMap` for domain-specific statuses, or force a `tone`\n * outright.\n */\nexport const StatusBadge = ({ status, label, tone, toneMap, className, ...props }: StatusBadgeProps): ReactElement => {\n const resolvedTone = resolveTone(status, tone, toneMap);\n const displayLabel = label ?? deriveLabel(status);\n\n return (\n <Badge variant=\"outline\" className={cn(TONE_CLASSES[resolvedTone], className)} {...props}>\n {displayLabel}\n </Badge>\n );\n};\n","import type { ComponentType, ReactElement } from \"react\";\nimport { cn } from \"../../lib/utils\";\nimport { Button, type ButtonProps } from \"../../primitives/button\";\n\n/** One segment of a {@link ButtonGroup}. */\nexport interface ButtonGroupOption<T extends string = string> {\n value: T;\n label: string;\n icon?: ComponentType<{ className?: string }>;\n}\n\nexport interface ButtonGroupProps<T extends string = string> {\n options: ButtonGroupOption<T>[];\n value: T;\n onValueChange: (value: T) => void;\n /** Forwarded to every segment's `Button`. @default \"default\" */\n size?: ButtonProps[\"size\"];\n disabled?: boolean;\n /** Accessible name for the group's `role=\"group\"` wrapper. */\n \"aria-label\"?: string;\n className?: string;\n \"data-testid\"?: string;\n}\n\n/**\n * A row of mutually exclusive, connected buttons (single-select segmented\n * control) — e.g. an ignore/create/update choice per row. Built on the\n * `Button` primitive rather than a bespoke element so segments inherit its\n * variant styling, sizes, and disabled/focus-visible behavior for free.\n *\n * Segments share borders (each button after the first overlaps its left\n * border by 1px via `-ml-px`) with `hover:z-10`/`focus-visible:z-10` so the\n * active/hovered segment's own border still draws on top of its neighbor\n * instead of being clipped underneath it.\n */\nexport function ButtonGroup<T extends string = string>({\n options,\n value,\n onValueChange,\n size = \"default\",\n disabled,\n className,\n ...props\n}: ButtonGroupProps<T>): ReactElement {\n return (\n <div role=\"group\" aria-label={props[\"aria-label\"]} className={cn(\"inline-flex\", className)} data-testid={props[\"data-testid\"]}>\n {options.map((option, index) => {\n const selected = option.value === value;\n const Icon = option.icon;\n return (\n <Button\n key={option.value}\n type=\"button\"\n variant={selected ? \"default\" : \"outline\"}\n size={size}\n disabled={disabled}\n aria-pressed={selected}\n data-testid={props[\"data-testid\"] ? `${props[\"data-testid\"]}-option-${option.value}` : undefined}\n onClick={() => onValueChange(option.value)}\n className={cn(\n \"relative rounded-none focus-visible:z-10\",\n !selected && \"hover:z-10\",\n index === 0 && \"rounded-l-md\",\n index === options.length - 1 && \"rounded-r-md\",\n index > 0 && \"-ml-px\",\n )}\n >\n {Icon && <Icon className=\"h-4 w-4\" />}\n {option.label}\n </Button>\n );\n })}\n </div>\n );\n}\n","import { type VariantProps, cva } from \"class-variance-authority\";\nimport { Loader2 } from \"lucide-react\";\nimport type { HTMLAttributes, ReactElement } from \"react\";\nimport { cn } from \"../../lib/utils\";\n\nexport const loadingSpinnerIconVariants = cva(\"animate-spin text-muted-foreground\", {\n variants: {\n size: {\n sm: \"h-3.5 w-3.5\",\n default: \"h-4 w-4\",\n lg: \"h-6 w-6\",\n },\n },\n defaultVariants: {\n size: \"default\",\n },\n});\n\nexport interface LoadingSpinnerProps\n extends HTMLAttributes<HTMLSpanElement>,\n VariantProps<typeof loadingSpinnerIconVariants> {\n /** Optional text rendered next to the spinner. Omitted entirely renders an icon-only spinner. */\n label?: string;\n}\n\n/** Inline loading indicator: a spinning icon with an optional label, e.g. `<LoadingSpinner label=\"Saving…\" />`. */\nexport const LoadingSpinner = ({\n size,\n label,\n className,\n ...props\n}: LoadingSpinnerProps): ReactElement => (\n <span role=\"status\" className={cn(\"inline-flex items-center gap-2\", className)} {...props}>\n <Loader2 className={cn(loadingSpinnerIconVariants({ size }))} aria-hidden=\"true\" />\n {label ? <span>{label}</span> : null}\n </span>\n);\n\nexport interface LoadingOverlayProps\n extends HTMLAttributes<HTMLDivElement>,\n Pick<LoadingSpinnerProps, \"label\"> {\n size?: LoadingSpinnerProps[\"size\"];\n}\n\n/** Centers a larger `LoadingSpinner` inside a full container/page — use as a route or panel loading state. */\nexport const LoadingOverlay = ({\n size = \"lg\",\n label,\n className,\n ...props\n}: LoadingOverlayProps): ReactElement => (\n <div\n className={cn(\"flex h-full min-h-32 w-full items-center justify-center\", className)}\n {...props}\n >\n <LoadingSpinner size={size} label={label} />\n </div>\n);\n","import { Search, X } from \"lucide-react\";\nimport type { InputHTMLAttributes, ReactElement, Ref } from \"react\";\nimport { cn } from \"../../lib/utils\";\nimport { LoadingSpinner } from \"../loading-spinner/LoadingSpinner\";\n\nexport interface SearchBarProps\n extends Omit<InputHTMLAttributes<HTMLInputElement>, \"type\" | \"value\" | \"onChange\" | \"size\"> {\n value: string;\n onChange: (value: string) => void;\n /** Swaps the leading search icon for a spinner while a search request is in flight. */\n isLoading?: boolean;\n /** Called when the clear (×) button is pressed. Defaults to `onChange(\"\")`. Pass `false` to hide the button entirely, even with a non-empty value. */\n onClear?: (() => void) | false;\n /** Accessible label for the clear button. @default \"Clear search\" */\n clearLabel?: string;\n /** Forwarded ref so a caller can focus the input programmatically. */\n inputRef?: Ref<HTMLInputElement>;\n className?: string;\n}\n\n/**\n * Pill-shaped search input: leading icon (swaps to a spinner while\n * `isLoading`), trailing clear button once there's a value. The shape\n * duplicated across several consuming apps' own hand-rolled search boxes —\n * unlike `Combobox`, this has no dropdown/result list of its own, just the\n * input chrome; the caller owns whatever renders the results.\n */\nexport function SearchBar({\n value,\n onChange,\n isLoading,\n onClear,\n clearLabel = \"Clear search\",\n inputRef,\n className,\n ...props\n}: SearchBarProps): ReactElement {\n const showClear = onClear !== false && value.length > 0;\n return (\n <div className={cn(\"relative\", className)}>\n <span className=\"pointer-events-none absolute top-1/2 left-4 -translate-y-1/2 text-muted-foreground\">\n {isLoading ? (\n <LoadingSpinner size=\"sm\" />\n ) : (\n <Search className=\"h-4 w-4\" aria-hidden=\"true\" />\n )}\n </span>\n <input\n ref={inputRef}\n type=\"search\"\n value={value}\n onChange={(event) => onChange(event.target.value)}\n className={cn(\n \"h-11 w-full rounded-full border border-input bg-background text-[15px] text-foreground placeholder:text-muted-foreground focus-visible:ring-1 focus-visible:ring-ring focus-visible:outline-none\",\n // Chromium/Safari render their own native clear (×) control on\n // type=\"search\" inputs -- left alone, it stacks on top of our own\n // custom clear button below instead of replacing it.\n \"[&::-webkit-search-cancel-button]:appearance-none [&::-webkit-search-decoration]:appearance-none\",\n showClear ? \"pr-11\" : \"pr-4\",\n \"pl-11\",\n )}\n {...props}\n />\n {showClear && (\n <button\n type=\"button\"\n onClick={() => (onClear ? onClear() : onChange(\"\"))}\n aria-label={clearLabel}\n className=\"absolute top-1/2 right-2 flex h-7 w-7 -translate-y-1/2 items-center justify-center rounded-full text-muted-foreground hover:bg-accent hover:text-foreground\"\n >\n <X className=\"h-4 w-4\" aria-hidden=\"true\" />\n </button>\n )}\n </div>\n );\n}\n","import { memo, type ComponentType, type ReactElement } from \"react\";\nimport { cn } from \"../../lib/utils\";\nimport { Skeleton } from \"../../primitives/skeleton\";\n\nexport interface KpiCardProps {\n label: string;\n value?: string | number | null;\n icon?: ComponentType<{ className?: string }>;\n badge?: { text: string; positive?: boolean };\n badgeLabel?: string;\n /** @default \"default\" */\n variant?: \"hero\" | \"mini\" | \"default\" | \"donut\";\n loading?: boolean;\n sub?: string;\n /** Colors `sub` on the mini variant — \"warn\"/\"danger\" flag something worth acting on (overdue, at-risk), \"default\" stays muted. */\n subTone?: \"default\" | \"warn\" | \"danger\";\n /** Makes the icon (mini variant) or the whole card clickable. */\n href?: string;\n sparkline?: number[];\n /** @default \"var(--color-primary, #3b82f6)\" */\n sparklineColor?: string;\n /** Hero variant only: 0-100 achievement-vs-target bar rendered under `sub`. */\n progress?: number;\n progressLabel?: string;\n /** Donut variant only: the proportions to render as a ring chart, with a legend listing each segment's share. */\n segments?: DonutSegment[];\n /** Donut variant only: big label centered in the ring. Defaults to the sum of `segments`' values. */\n centerValue?: string;\n /** Any CSS color/gradient, overriding the variant's default surface (`--color-primary` for `hero`, `bg-card` for the rest). */\n background?: string;\n /** For E2E tests to target a specific tile unambiguously when `label` also appears elsewhere on the page (e.g. a chart legend). */\n testId?: string;\n}\n\nexport interface DonutSegment {\n label: string;\n value: number;\n /** @default a color from the built-in palette, cycling by index */\n color?: string;\n}\n\n/** Falls back to a fixed palette when the consuming app hasn't registered `--chart-1`..`--chart-6` — see the \"Chart tokens\" docs. */\nconst DONUT_COLORS = [\n \"var(--chart-1, #3b82f6)\",\n \"var(--chart-2, #22c55e)\",\n \"var(--chart-3, #f59e0b)\",\n \"var(--chart-4, #8b5cf6)\",\n \"var(--chart-5, #ef4444)\",\n \"var(--chart-6, #06b6d4)\",\n];\n\nexport function DonutChart({\n data,\n size = 96,\n thickness = 14,\n centerValue,\n centerLabel,\n}: {\n data: DonutSegment[];\n size?: number;\n thickness?: number;\n centerValue?: string;\n centerLabel?: string;\n}): ReactElement | null {\n const total = data.reduce((sum, d) => sum + d.value, 0);\n if (total <= 0) return null;\n\n const radius = (size - thickness) / 2;\n const circumference = 2 * Math.PI * radius;\n let offset = 0;\n\n return (\n <div className=\"relative inline-flex shrink-0 items-center justify-center\" style={{ width: size, height: size }}>\n <svg width={size} height={size} viewBox={`0 0 ${size} ${size}`} className=\"-rotate-90\">\n <circle cx={size / 2} cy={size / 2} r={radius} fill=\"none\" stroke=\"currentColor\" className=\"text-muted/40\" strokeWidth={thickness} />\n {data.map((segment, i) => {\n const fraction = segment.value / total;\n const dash = fraction * circumference;\n const el = (\n <circle\n key={segment.label}\n cx={size / 2}\n cy={size / 2}\n r={radius}\n fill=\"none\"\n stroke={segment.color ?? DONUT_COLORS[i % DONUT_COLORS.length]}\n strokeWidth={thickness}\n strokeDasharray={`${dash} ${circumference - dash}`}\n strokeDashoffset={-offset}\n strokeLinecap={data.length > 1 ? \"butt\" : \"round\"}\n />\n );\n offset += dash;\n return el;\n })}\n </svg>\n {(centerValue || centerLabel) && (\n <div className=\"absolute inset-0 flex flex-col items-center justify-center\">\n {centerValue && <span className=\"text-base font-black tracking-tight text-foreground tabular-nums\">{centerValue}</span>}\n {centerLabel && <span className=\"text-[9px] font-medium text-muted-foreground uppercase\">{centerLabel}</span>}\n </div>\n )}\n </div>\n );\n}\n\nexport function Sparkline({ data, color }: { data: number[]; color: string }): ReactElement | null {\n if (data.length < 2) return null;\n const min = Math.min(...data);\n const max = Math.max(...data);\n const range = max - min || 1;\n const W = 72;\n const H = 28;\n const pts = data\n .map((v, i) => `${(i / (data.length - 1)) * W},${H - ((v - min) / range) * (H - 2) - 1}`)\n .join(\" \");\n return (\n <svg width={W} height={H} viewBox={`0 0 ${W} ${H}`} className=\"overflow-visible opacity-70\">\n <polyline points={pts} fill=\"none\" stroke={color} strokeWidth=\"1.5\" strokeLinecap=\"round\" strokeLinejoin=\"round\" />\n </svg>\n );\n}\n\nfunction AreaSparkline({ data, color }: { data: number[]; color: string }): ReactElement | null {\n if (data.length < 2) return null;\n const min = Math.min(...data);\n const max = Math.max(...data);\n const range = max - min || 1;\n const W = 200;\n const H = 28;\n const P = 2;\n const xs = data.map((_, i) => (i / (data.length - 1)) * W);\n const ys = data.map((v) => H - ((v - min) / range) * (H - 2 * P) - P);\n const linePts = xs.map((x, i) => `${x},${ys[i]}`).join(\" \");\n const areaPath = `M${xs[0]},${H} ` + xs.map((x, i) => `L${x},${ys[i]}`).join(\" \") + ` L${xs[xs.length - 1]},${H} Z`;\n\n return (\n <svg width={W} height={H} viewBox={`0 0 ${W} ${H}`} className=\"overflow-visible\" preserveAspectRatio=\"none\">\n <defs>\n <linearGradient id=\"kpi-card-spark-fill\" x1=\"0\" y1=\"0\" x2=\"0\" y2=\"1\">\n <stop offset=\"0%\" stopColor={color} stopOpacity=\"0.22\" />\n <stop offset=\"100%\" stopColor={color} stopOpacity=\"0\" />\n </linearGradient>\n </defs>\n <path d={areaPath} fill=\"url(#kpi-card-spark-fill)\" />\n <polyline points={linePts} fill=\"none\" stroke={color} strokeWidth=\"1.75\" strokeLinecap=\"round\" strokeLinejoin=\"round\" />\n <circle cx={xs[xs.length - 1]} cy={ys[ys.length - 1]} r=\"2.5\" fill={color} />\n </svg>\n );\n}\n\nconst rowBetween = \"flex items-center justify-between\";\n\n/**\n * Dashboard KPI tile in three variants — `hero` (large, primary-colored,\n * for the single headline metric), `default` (bordered card for a KPI\n * grid), and `mini` (compact, for dense grids of secondary metrics).\n * Optionally shows a badge, a trend sparkline, and (hero only) a\n * progress-vs-target bar.\n */\nexport const KpiCard = memo(function KpiCard({\n label,\n value,\n icon: Icon,\n badge,\n badgeLabel,\n variant = \"default\",\n loading = false,\n sub,\n subTone = \"default\",\n href,\n sparkline,\n sparklineColor = \"var(--color-primary, #3b82f6)\",\n progress,\n progressLabel,\n segments,\n centerValue,\n background,\n testId,\n}: KpiCardProps): ReactElement {\n // Inline style, so it wins over the variants' own `bg-card` class.\n const bgStyle = background ? { background } : undefined;\n if (variant === \"hero\") {\n return (\n <div\n data-testid={testId}\n className=\"relative col-span-2 flex min-w-0 flex-1 flex-col gap-1.5 overflow-hidden rounded-2xl p-4 md:p-3 lg:col-span-1 lg:max-w-[340px] lg:min-w-[260px]\"\n style={{\n background: background ?? \"var(--color-primary)\",\n boxShadow: `0 2px 10px color-mix(in oklch, ${background ?? \"var(--color-primary)\"} 18%, transparent)`,\n }}\n >\n <div className=\"relative flex items-start justify-between\">\n <p className=\"text-[11px] font-bold tracking-[0.14em] text-white/70 uppercase\">{label}</p>\n {Icon && (\n <div className=\"flex h-6 w-6 items-center justify-center rounded-lg bg-white/15 ring-1 ring-white/20\">\n <Icon className=\"h-3 w-3 text-white/90\" aria-hidden=\"true\" />\n </div>\n )}\n </div>\n\n <div className=\"relative\">\n {loading ? (\n <div className=\"h-6 w-28 animate-pulse rounded-lg bg-white/15\" />\n ) : (\n <p className=\"text-2xl leading-none font-black tracking-tight text-white tabular-nums md:text-[22px]\">\n {value ?? \"—\"}\n </p>\n )}\n </div>\n\n {(badge || badgeLabel) && !loading && (\n <div className=\"relative flex items-center gap-2\">\n {badge && (\n <span\n className={cn(\n \"inline-flex items-center gap-1 rounded-full px-2.5 py-0.5 text-[11px] font-bold tabular-nums ring-1\",\n badge.positive ? \"bg-white/15 text-white ring-white/25\" : \"bg-black/25 text-white ring-white/15\",\n )}\n >\n {badge.text}\n </span>\n )}\n {badgeLabel && <span className=\"text-[11px] text-white/70\">{badgeLabel}</span>}\n </div>\n )}\n\n {sub && !loading && (\n <p className=\"relative -mt-1 text-[11px] font-medium text-white/75 tabular-nums\">{sub}</p>\n )}\n\n {progress != null && !loading && (\n <div className=\"relative flex items-center gap-1.5\">\n <div className=\"h-1 flex-1 overflow-hidden rounded-full bg-white/20\">\n <div className=\"h-1 rounded-full bg-white/85\" style={{ width: `${Math.min(100, Math.max(0, progress))}%` }} />\n </div>\n {progressLabel && <span className=\"shrink-0 text-[11px] font-semibold text-white/80 tabular-nums\">{progressLabel}</span>}\n </div>\n )}\n\n {/* Area sparkline pinned to bottom, always white: the hero card's own\n background is the `var(--color-primary)` gradient above, so a\n primary-colored line (the default) disappears against it. */}\n {sparkline && sparkline.length > 1 && !loading && (\n <div className=\"relative -mx-4 mt-auto -mb-4 md:-mx-3 md:-mb-3\">\n <AreaSparkline data={sparkline} color=\"#ffffff\" />\n </div>\n )}\n </div>\n );\n }\n\n if (variant === \"mini\") {\n const iconSlot = Icon ? (\n href ? (\n <a\n href={href}\n className=\"tap-target flex h-7 w-7 shrink-0 items-center justify-center rounded-xl bg-primary/10 text-primary transition-[background-color,scale] hover:bg-primary/20 active:scale-90 motion-reduce:transition-none md:h-6 md:w-6\"\n >\n <Icon className=\"h-4 w-4 md:h-3.5 md:w-3.5\" aria-hidden=\"true\" />\n </a>\n ) : (\n <div className=\"flex h-7 w-7 shrink-0 items-center justify-center rounded-xl bg-primary/10 text-primary md:h-6 md:w-6\">\n <Icon className=\"h-4 w-4 md:h-3.5 md:w-3.5\" aria-hidden=\"true\" />\n </div>\n )\n ) : null;\n\n return (\n <div\n data-testid={testId}\n style={bgStyle}\n className={cn(\n \"flex h-full min-w-0 flex-1 flex-col gap-1.5 overflow-hidden rounded-2xl border border-border bg-card p-3 transition-shadow md:p-2.5\",\n href && \"hover:border-primary/20 hover:shadow-md\",\n )}\n >\n <div className={rowBetween}>\n <p className=\"text-[11px] font-bold tracking-[0.12em] text-muted-foreground uppercase\">{label}</p>\n {iconSlot}\n </div>\n\n <div className=\"flex min-w-0 flex-1 items-center gap-2\">\n {loading ? (\n <Skeleton className=\"h-6 w-16\" />\n ) : (\n <>\n <p className=\"min-w-0 animate-in truncate text-[20px] leading-none font-black tracking-tight text-foreground duration-200 fade-in-0 tabular-nums motion-reduce:animate-none md:text-[16px]\">\n {value ?? \"—\"}\n </p>\n {badge && (\n <span\n className={cn(\n \"shrink-0 animate-in rounded-md px-1.5 py-0.5 text-[11px] font-bold duration-200 fade-in-0 tabular-nums motion-reduce:animate-none\",\n badge.positive\n ? \"bg-emerald-100 text-emerald-700 dark:bg-emerald-900/30 dark:text-emerald-400\"\n : \"bg-muted text-muted-foreground\",\n )}\n >\n {badge.text}\n </span>\n )}\n </>\n )}\n </div>\n\n {(sub || sparkline) && !loading && (\n <div className=\"flex items-end justify-between gap-2\">\n {sub && (\n <p\n className={cn(\n \"text-[11px]\",\n subTone === \"danger\"\n ? \"font-semibold text-red-600 dark:text-red-400\"\n : subTone === \"warn\"\n ? \"font-semibold text-amber-700 dark:text-amber-300\"\n : \"text-muted-foreground\",\n )}\n >\n {sub}\n </p>\n )}\n {sparkline && <Sparkline data={sparkline} color={sparklineColor} />}\n </div>\n )}\n </div>\n );\n }\n\n if (variant === \"donut\") {\n const total = segments?.reduce((sum, s) => sum + s.value, 0) ?? 0;\n\n return (\n <div data-testid={testId} style={bgStyle} className=\"rounded-xl border border-border bg-card p-5\">\n <div className={rowBetween}>\n <p className=\"text-[11px] font-bold tracking-[0.12em] text-muted-foreground uppercase\">{label}</p>\n {Icon && (\n <div className=\"flex h-7 w-7 shrink-0 items-center justify-center rounded-xl bg-primary/8 text-primary\">\n <Icon className=\"h-3.5 w-3.5\" aria-hidden=\"true\" />\n </div>\n )}\n </div>\n\n {loading ? (\n <div className=\"mt-3 flex items-center gap-4\">\n <Skeleton className=\"h-24 w-24 shrink-0 rounded-full\" />\n <div className=\"flex flex-1 flex-col gap-2\">\n <Skeleton className=\"h-3 w-full\" />\n <Skeleton className=\"h-3 w-3/4\" />\n <Skeleton className=\"h-3 w-1/2\" />\n </div>\n </div>\n ) : segments && segments.length > 0 ? (\n <div className=\"mt-3 flex items-center gap-4\">\n <DonutChart data={segments} centerValue={centerValue ?? String(total)} />\n <ul className=\"flex min-w-0 flex-1 flex-col gap-1.5\">\n {segments.map((segment, i) => (\n <li key={segment.label} className=\"flex items-center gap-2 text-[12px]\">\n <span\n className=\"h-2 w-2 shrink-0 rounded-full\"\n style={{ backgroundColor: segment.color ?? DONUT_COLORS[i % DONUT_COLORS.length] }}\n aria-hidden=\"true\"\n />\n <span className=\"min-w-0 flex-1 truncate text-muted-foreground\">{segment.label}</span>\n <span className=\"shrink-0 font-semibold text-foreground tabular-nums\">\n {total > 0 ? `${Math.round((segment.value / total) * 100)}%` : segment.value}\n </span>\n </li>\n ))}\n </ul>\n </div>\n ) : (\n <span className=\"mt-3 block text-2xl font-black text-muted-foreground/40\">—</span>\n )}\n\n {sub && !loading && <p className=\"mt-2.5 text-[11px] text-muted-foreground tabular-nums\">{sub}</p>}\n </div>\n );\n }\n\n // Default variant: splits a value like \"12 kunden\" or \"42 %\" into a\n // large number plus a small prefix/suffix unit.\n const strValue = value != null ? String(value) : null;\n const parts = strValue ? strValue.split(/\\s(.+)/) : null;\n const plain = !parts || parts.length === 1;\n const isSuffix = !plain && /^\\d/.test(parts![0]!) && parts![1]!.length <= 3;\n const prefix = isSuffix ? null : parts?.[0];\n const number = isSuffix ? parts![0] : (parts?.[1] ?? parts?.[0]);\n const suffix = isSuffix ? parts![1] : null;\n\n return (\n <div data-testid={testId} style={bgStyle} className=\"rounded-xl border border-border bg-card p-5\">\n <div className={rowBetween}>\n <p className=\"text-[11px] font-bold tracking-[0.12em] text-muted-foreground uppercase\">{label}</p>\n {Icon && (\n <div className=\"flex h-7 w-7 shrink-0 items-center justify-center rounded-xl bg-primary/8 text-primary\">\n <Icon className=\"h-3.5 w-3.5\" aria-hidden=\"true\" />\n </div>\n )}\n </div>\n\n <div className=\"mt-3\">\n {loading ? (\n <Skeleton className=\"h-7 w-20\" />\n ) : value == null ? (\n <span className=\"text-2xl font-black text-muted-foreground/40\">—</span>\n ) : plain ? (\n <span className=\"animate-in text-2xl font-black tracking-tight text-foreground duration-200 fade-in-0 tabular-nums motion-reduce:animate-none\">\n {strValue}\n </span>\n ) : (\n <span className=\"animate-in font-black tracking-tight text-foreground duration-200 fade-in-0 tabular-nums motion-reduce:animate-none\">\n {prefix && <span className=\"text-sm text-muted-foreground\">{prefix} </span>}\n <span className=\"text-2xl\">{number}</span>\n {suffix && <span className=\"text-sm text-muted-foreground\"> {suffix}</span>}\n </span>\n )}\n {sub && !loading && <p className=\"mt-0.5 text-[11px] text-muted-foreground tabular-nums\">{sub}</p>}\n </div>\n\n {(badge || badgeLabel || sparkline) && !loading && (\n <div className=\"mt-2.5 flex items-end justify-between gap-2\">\n <div className=\"flex flex-wrap items-center gap-2\">\n {badge && (\n <span\n className={cn(\n \"rounded-md px-1.5 py-0.5 text-[11px] font-semibold tabular-nums\",\n badge.positive\n ? \"bg-emerald-100 text-emerald-700 dark:bg-emerald-900/30 dark:text-emerald-400\"\n : \"bg-muted text-muted-foreground\",\n )}\n >\n {badge.text}\n </span>\n )}\n {badgeLabel && <span className=\"text-[11px] text-muted-foreground\">{badgeLabel}</span>}\n </div>\n {sparkline && <Sparkline data={sparkline} color={sparklineColor} />}\n </div>\n )}\n </div>\n );\n});\n","import { Search } from \"lucide-react\";\nimport type { ComponentType, InputHTMLAttributes, ReactElement, ReactNode, Ref } from \"react\";\nimport { cn } from \"../../lib/utils\";\nimport { LoadingSpinner } from \"../loading-spinner/LoadingSpinner\";\n\nexport interface SearchPanelMode {\n key: string;\n label: string;\n icon?: ComponentType<{ className?: string }>;\n}\n\nexport interface SearchPanelProps\n extends Omit<InputHTMLAttributes<HTMLInputElement>, \"type\" | \"value\" | \"onChange\" | \"size\"> {\n value: string;\n onChange: (value: string) => void;\n /** Swaps the leading search icon for a spinner while a search request is in flight. */\n isLoading?: boolean;\n /** Extra content after the input, e.g. a mic button. */\n trailingSlot?: ReactNode;\n /** Keyboard-shortcut hint rendered after `trailingSlot`, e.g. `\"⌘K\"`. Omit to hide it. */\n shortcutHint?: string;\n /** Mode-switcher pills rendered below the input row (e.g. \"Search\" / \"Ask AI\"). Omit to hide the row entirely. */\n modes?: SearchPanelMode[];\n activeMode?: string;\n onModeChange?: (key: string) => void;\n /** Squares the panel's bottom corners so a results dropdown anchored directly below it reads as one continuous surface. */\n expanded?: boolean;\n inputRef?: Ref<HTMLInputElement>;\n className?: string;\n}\n\n/**\n * Bordered search card: an input row (leading icon/spinner, input, optional\n * trailing slot and keyboard-shortcut hint) plus an optional row of\n * mode-switcher pills below it. Headless on results — the caller renders\n * whatever dropdown or inline results belong under it.\n */\nexport function SearchPanel({\n value,\n onChange,\n isLoading,\n trailingSlot,\n shortcutHint,\n modes,\n activeMode,\n onModeChange,\n expanded = false,\n inputRef,\n className,\n ...props\n}: SearchPanelProps): ReactElement {\n return (\n <div\n className={cn(\n \"flex flex-col border border-border bg-card shadow-sm\",\n expanded ? \"rounded-t-2xl border-b-transparent\" : \"rounded-2xl\",\n className,\n )}\n >\n <div className=\"flex h-14 items-center gap-3 px-4\">\n {isLoading ? (\n <LoadingSpinner size=\"sm\" />\n ) : (\n <Search className=\"h-5 w-5 shrink-0 text-muted-foreground\" aria-hidden=\"true\" />\n )}\n <input\n ref={inputRef}\n type=\"text\"\n value={value}\n onChange={(event) => onChange(event.target.value)}\n className=\"min-w-0 flex-1 bg-transparent text-[15px] text-foreground outline-none placeholder:text-muted-foreground\"\n {...props}\n />\n {trailingSlot}\n {shortcutHint && (\n <kbd\n aria-hidden=\"true\"\n className=\"hidden shrink-0 items-center rounded border border-border bg-muted/60 px-1.5 py-0.5 text-[10px] font-medium text-muted-foreground select-none sm:inline-flex\"\n >\n {shortcutHint}\n </kbd>\n )}\n </div>\n\n {modes && modes.length > 0 && (\n <div className=\"flex items-center gap-2 px-4 pb-3\">\n {modes.map(({ key, label, icon: Icon }) => (\n <button\n key={key}\n type=\"button\"\n onClick={() => onModeChange?.(key)}\n className={cn(\n \"flex items-center gap-1.5 rounded-full px-3 py-1.5 text-[13px] font-medium transition-colors\",\n activeMode === key\n ? \"bg-primary text-primary-foreground\"\n : \"text-muted-foreground hover:bg-muted\",\n )}\n >\n {Icon && <Icon className=\"h-3.5 w-3.5\" aria-hidden=\"true\" />}\n {label}\n </button>\n ))}\n </div>\n )}\n </div>\n );\n}\n","import { Search } from \"lucide-react\";\nimport type { ButtonHTMLAttributes, ReactElement } from \"react\";\nimport { Button } from \"../../primitives/button\";\n\nexport interface SearchTriggerProps extends Omit<ButtonHTMLAttributes<HTMLButtonElement>, \"children\"> {\n /** Accessible label, also used as the tooltip text by callers that wrap this in one. @default \"Search\" */\n label?: string;\n}\n\n/**\n * Icon-only header button that opens a search overlay (a `SearchPanel`, a\n * dropdown, a `Sheet` — this owns no state or panel of its own). For a\n * full-width always-visible input instead, use `SearchBar`.\n */\nexport function SearchTrigger({ label = \"Search\", ...props }: SearchTriggerProps): ReactElement {\n return (\n <Button type=\"button\" variant=\"ghost\" size=\"icon\" aria-label={label} {...props}>\n <Search className=\"h-[18px] w-[18px]\" aria-hidden=\"true\" />\n </Button>\n );\n}\n","import { createContext, useContext } from \"react\";\n\ninterface SidebarContextValue {\n /** True when the nearest `<Sidebar>` is showing its icon-only rail (labels/group headers hidden). */\n collapsed: boolean;\n}\n\nconst SidebarContext = createContext<SidebarContextValue>({ collapsed: false });\n\nexport const SidebarContextProvider = SidebarContext.Provider;\n\n/**\n * Whether the nearest ancestor `<Sidebar>` is rail-collapsed. Defaults to\n * `false` when there is no ancestor `<Sidebar>` — this is what lets\n * `NavGroup`/`NavItem` be reused standalone inside a mobile drawer (`Sheet`),\n * which is never rail-collapsed.\n */\nexport function useSidebarCollapsed(): boolean {\n return useContext(SidebarContext).collapsed;\n}\n","import type { ComponentPropsWithoutRef, ElementType, ReactElement, ReactNode } from \"react\";\nimport { cn } from \"../../lib/utils\";\nimport { Tooltip, TooltipContent, TooltipTrigger } from \"../../primitives/tooltip\";\nimport { useSidebarCollapsed } from \"./context\";\n\n/** Shape a `lucide-react` icon component satisfies — `NavItem` sizes and colors it itself. */\nexport interface NavIconProps {\n className?: string;\n strokeWidth?: string | number;\n \"aria-hidden\"?: boolean | \"true\" | \"false\";\n}\n\nexport type NavItemProps<T extends ElementType = \"a\"> = {\n /** The element (or router `Link`) this renders as, e.g. `as={Link} to=\"/overview\"`. @default \"a\" */\n as?: T;\n icon?: ElementType<NavIconProps>;\n label: ReactNode;\n /** Highlights this row as the current page. The caller computes this from its own router — `NavItem` has no router opinion. */\n active?: boolean;\n /** Rendered after the label, and again in the collapsed-rail tooltip — e.g. an experimental-status `Badge`. */\n badge?: ReactNode;\n className?: string;\n} & Omit<ComponentPropsWithoutRef<T>, \"as\" | \"className\">;\n\n/**\n * One row inside a `Sidebar`/`NavGroup`. Polymorphic via `as` so it renders a\n * plain `<a>` by default or a router's own `Link` (extra props like `to`/\n * `href` pass straight through). When the nearest `Sidebar` is rail-\n * collapsed, the row shrinks to icon-only and shows `label`/`badge` in a\n * hover tooltip instead.\n */\nexport function NavItem<T extends ElementType = \"a\">({\n as,\n icon: Icon,\n label,\n active = false,\n badge,\n className,\n ...rest\n}: NavItemProps<T>): ReactElement {\n const collapsed = useSidebarCollapsed();\n const Comp = (as ?? \"a\") as ElementType;\n\n const row = (\n <Comp\n className={cn(\n \"group relative flex items-center rounded-lg px-2.5 py-2 text-[13px] font-medium transition-colors\",\n \"focus-visible:ring-2 focus-visible:ring-primary focus-visible:ring-inset focus-visible:outline-none\",\n collapsed ? \"justify-center gap-0\" : \"gap-2.5\",\n active\n ? \"bg-nav-primary/8 font-semibold text-foreground\"\n : \"text-foreground/55 hover:bg-muted/60 hover:text-foreground\",\n className,\n )}\n {...rest}\n >\n {Icon && (\n <Icon\n className={cn(\"h-[18px] w-[18px] shrink-0\", active ? \"text-nav-primary\" : \"text-muted-foreground\")}\n strokeWidth={active ? 2 : 1.75}\n aria-hidden\n />\n )}\n <span\n className={cn(\n \"truncate transition-[opacity,max-width] duration-150\",\n collapsed ? \"max-w-0 opacity-0\" : \"max-w-[10rem] opacity-100\",\n )}\n >\n {label}\n </span>\n {!collapsed && badge}\n </Comp>\n );\n\n if (!collapsed) return row;\n\n return (\n <Tooltip>\n <TooltipTrigger asChild>{row}</TooltipTrigger>\n <TooltipContent side=\"right\" className=\"flex items-center gap-1.5\">\n {label}\n {badge}\n </TooltipContent>\n </Tooltip>\n );\n}\n","import { ChevronDown } from \"lucide-react\";\nimport { useState, type ReactElement, type ReactNode } from \"react\";\nimport { cn } from \"../../lib/utils\";\nimport { useSidebarCollapsed } from \"./context\";\n\nexport interface NavGroupProps {\n /** Section header. Omit for a flat group with no header/collapse affordance. */\n label?: ReactNode;\n /** Uncontrolled starting collapsed state. @default false */\n defaultCollapsed?: boolean;\n /** Controlled collapsed state. */\n collapsed?: boolean;\n onCollapsedChange?: (collapsed: boolean) => void;\n children: ReactNode;\n className?: string;\n}\n\n/**\n * A labeled, independently collapsible section of `NavItem`s inside a\n * `Sidebar`. This group's own collapsed state (items hidden/shown) is\n * separate from the sidebar's rail-collapse: when the sidebar itself is\n * rail-collapsed, this group's header shrinks to a thin divider (its items\n * stay visible as icons) rather than disappearing, since there's no room for\n * a clickable label to toggle.\n */\nexport function NavGroup({\n label,\n defaultCollapsed = false,\n collapsed,\n onCollapsedChange,\n children,\n className,\n}: NavGroupProps): ReactElement {\n const [internalCollapsed, setInternalCollapsed] = useState(defaultCollapsed);\n const groupCollapsed = collapsed ?? internalCollapsed;\n const railCollapsed = useSidebarCollapsed();\n\n const setGroupCollapsed = (next: boolean) => {\n onCollapsedChange?.(next);\n if (collapsed === undefined) setInternalCollapsed(next);\n };\n\n return (\n <div className={cn(\"flex flex-col gap-0.5\", className)}>\n {label &&\n (railCollapsed ? (\n <div className=\"mx-2 my-1 h-px bg-border/50\" aria-hidden />\n ) : (\n <button\n type=\"button\"\n onClick={() => setGroupCollapsed(!groupCollapsed)}\n aria-expanded={!groupCollapsed}\n className=\"group flex w-full items-center justify-between px-2.5 py-0.5 text-[11px] font-medium text-muted-foreground/80 hover:text-foreground\"\n >\n <span>{label}</span>\n <ChevronDown\n className={cn(\n \"h-4 w-4 opacity-40 transition-transform group-hover:opacity-100\",\n groupCollapsed && \"-rotate-90\",\n )}\n aria-hidden\n />\n </button>\n ))}\n {!groupCollapsed && <div className=\"flex flex-col gap-0.5\">{children}</div>}\n </div>\n );\n}\n","import { PanelLeftClose, PanelLeftOpen } from \"lucide-react\";\nimport {\n useCallback,\n useEffect,\n useRef,\n useState,\n type ComponentPropsWithoutRef,\n type PointerEvent as ReactPointerEvent,\n type ReactElement,\n type ReactNode,\n} from \"react\";\nimport { cn } from \"../../lib/utils\";\nimport { TooltipProvider } from \"../../primitives/tooltip\";\nimport { SidebarContextProvider } from \"./context\";\n\nfunction resolve<T>(value: T | ((collapsed: boolean) => T), collapsed: boolean): T {\n return typeof value === \"function\" ? (value as (collapsed: boolean) => T)(collapsed) : value;\n}\n\nexport interface SidebarProps {\n /** Rail-collapse the whole sidebar to an icon-only strip. Controlled. */\n collapsed?: boolean;\n /** Renders a built-in collapse/expand toggle button and fires when it's clicked. Omit to hide the toggle and drive `collapsed` some other way. */\n onCollapsedChange?: (collapsed: boolean) => void;\n /** Lets the user drag the trailing edge to resize. @default false */\n resizable?: boolean;\n /** Controlled width in px (only meaningful while expanded). */\n width?: number;\n onWidthChange?: (width: number) => void;\n /** Uncontrolled starting width in px, and the double-click-to-reset target. @default 240 */\n defaultWidth?: number;\n minWidth?: number;\n maxWidth?: number;\n /** Width of the icon-only rail. @default 56 */\n railWidth?: number;\n /** Logo/wordmark slot. Pass a function to swap in a compact mark once `collapsed` — the shared component only owns the collapse *toggle button*, not your branding. */\n header?: ReactNode | ((collapsed: boolean) => ReactNode);\n /** Pinned below the scrollable nav area (e.g. a user-profile row), outside the scroll-fade. */\n footer?: ReactNode | ((collapsed: boolean) => ReactNode);\n children: ReactNode;\n className?: string;\n}\n\n/**\n * App shell's left navigation panel: fixed-width or drag-resizable, with an\n * optional icon-only rail-collapse mode (tooltips on hover, via `NavItem`).\n * Renders `children` (typically one or more `NavGroup`s of `NavItem`s)\n * inside a scrollable area with a bottom scroll-fade once content overflows.\n *\n * For a mobile drawer, don't reuse `Sidebar` itself (its resize handle and\n * rail-collapse don't apply there) — render the same `NavGroup`/`NavItem`\n * children inside a `Sheet`, wrapped in the separately-exported `SidebarNav`\n * for the scroll-fade behavior.\n */\nexport function Sidebar({\n collapsed = false,\n onCollapsedChange,\n resizable = false,\n width,\n onWidthChange,\n defaultWidth = 240,\n minWidth = 180,\n maxWidth = 420,\n railWidth = 56,\n header,\n footer,\n children,\n className,\n}: SidebarProps): ReactElement {\n const [internalWidth, setInternalWidth] = useState(defaultWidth);\n const currentWidth = width ?? internalWidth;\n const [isDragging, setIsDragging] = useState(false);\n\n const setWidth = useCallback(\n (next: number) => {\n const clamped = Math.min(maxWidth, Math.max(minWidth, next));\n onWidthChange?.(clamped);\n if (width === undefined) setInternalWidth(clamped);\n },\n [maxWidth, minWidth, onWidthChange, width],\n );\n\n const dragStartRef = useRef<{ x: number; width: number } | null>(null);\n\n const handlePointerDown = (event: ReactPointerEvent<HTMLDivElement>) => {\n event.currentTarget.setPointerCapture(event.pointerId);\n dragStartRef.current = { x: event.clientX, width: currentWidth };\n setIsDragging(true);\n };\n const handlePointerMove = (event: ReactPointerEvent<HTMLDivElement>) => {\n if (!dragStartRef.current) return;\n setWidth(dragStartRef.current.width + (event.clientX - dragStartRef.current.x));\n };\n const endDrag = (event: ReactPointerEvent<HTMLDivElement>) => {\n if (event.currentTarget.hasPointerCapture(event.pointerId)) {\n event.currentTarget.releasePointerCapture(event.pointerId);\n }\n dragStartRef.current = null;\n setIsDragging(false);\n };\n\n return (\n <SidebarContextProvider value={{ collapsed }}>\n <TooltipProvider delayDuration={200}>\n <aside\n style={{ width: collapsed ? railWidth : currentWidth }}\n className={cn(\n \"relative flex h-full shrink-0 flex-col border-r border-border bg-sidebar\",\n !isDragging && \"transition-[width] duration-150\",\n className,\n )}\n >\n {(header || onCollapsedChange) && (\n <div className=\"flex h-16 items-center gap-2 border-b border-border px-3\">\n {collapsed && onCollapsedChange ? (\n // Collapsed rail: the header slot (e.g. a compact logo mark) and the\n // expand toggle would otherwise compete for the narrow rail's width\n // and clip each other, so they're stacked instead — the header shows\n // by default and cross-fades to the toggle icon on hover, matching\n // the same affordance OneSales' own sidebar rail uses.\n <button\n type=\"button\"\n onClick={() => onCollapsedChange(!collapsed)}\n aria-label=\"Expand sidebar\"\n className=\"group relative flex h-9 w-9 shrink-0 items-center justify-center\"\n >\n {header && (\n <span className=\"transition-opacity group-hover:opacity-0\">\n {resolve(header, collapsed)}\n </span>\n )}\n <PanelLeftOpen\n className=\"absolute h-4 w-4 text-muted-foreground opacity-0 transition-opacity group-hover:opacity-100\"\n aria-hidden\n />\n </button>\n ) : (\n <>\n {header && <div className=\"min-w-0 flex-1\">{resolve(header, collapsed)}</div>}\n {onCollapsedChange && (\n <button\n type=\"button\"\n onClick={() => onCollapsedChange(!collapsed)}\n aria-label=\"Collapse sidebar\"\n className=\"flex h-7 w-7 shrink-0 items-center justify-center rounded-md text-muted-foreground hover:bg-muted hover:text-foreground\"\n >\n <PanelLeftClose className=\"h-4 w-4\" aria-hidden />\n </button>\n )}\n </>\n )}\n </div>\n )}\n\n <SidebarNav>{children}</SidebarNav>\n\n {footer && <div className=\"border-t border-border/50 px-2 py-2\">{resolve(footer, collapsed)}</div>}\n\n {resizable && !collapsed && (\n <div\n onPointerDown={handlePointerDown}\n onPointerMove={handlePointerMove}\n onPointerUp={endDrag}\n onDoubleClick={() => setWidth(defaultWidth)}\n className=\"absolute top-0 right-0 h-full w-1.5 cursor-col-resize touch-none hover:bg-primary/40\"\n />\n )}\n </aside>\n </TooltipProvider>\n </SidebarContextProvider>\n );\n}\n\nexport type SidebarNavProps = {\n children: ReactNode;\n className?: string;\n} & Omit<ComponentPropsWithoutRef<\"div\">, \"className\" | \"children\" | \"ref\">;\n\n/**\n * The scrollable nav-item area, with a bottom scroll-fade once content\n * overflows. Used internally by `Sidebar`; exported separately so a mobile\n * drawer can wrap the same `NavGroup`/`NavItem` children in it without the\n * rest of the `Sidebar` shell. Extra props (`onClick`, `data-testid`, …)\n * forward to the scrollable element itself — e.g. `onClick` to close a\n * mobile drawer when any nav link inside is tapped.\n */\nexport function SidebarNav({ children, className, ...rest }: SidebarNavProps): ReactElement {\n const ref = useRef<HTMLDivElement>(null);\n const [showFade, setShowFade] = useState(false);\n\n useEffect(() => {\n const el = ref.current;\n if (!el) return;\n const update = () => setShowFade(el.scrollHeight - el.scrollTop - el.clientHeight > 1);\n update();\n el.addEventListener(\"scroll\", update);\n const observer = new ResizeObserver(update);\n observer.observe(el);\n return () => {\n el.removeEventListener(\"scroll\", update);\n observer.disconnect();\n };\n }, []);\n\n return (\n <div className=\"relative flex min-h-0 flex-1 flex-col\">\n <div\n ref={ref}\n className={cn(\"flex flex-1 flex-col gap-3 overflow-y-auto px-2 py-2\", className)}\n {...rest}\n >\n {children}\n </div>\n {showFade && (\n <div\n className=\"pointer-events-none absolute right-0 bottom-0 left-0 h-6 bg-gradient-to-t from-sidebar to-transparent\"\n aria-hidden\n />\n )}\n </div>\n );\n}\n","import { Sparkles } from \"lucide-react\";\nimport type { ElementType } from \"react\";\nimport { forwardRef } from \"react\";\nimport { Button, type ButtonProps } from \"../../primitives/button\";\nimport { LoadingSpinner } from \"../loading-spinner/LoadingSpinner\";\nimport type { NavIconProps } from \"../sidebar/NavItem\";\n\n/** The three `buttonVariants` entries that carry the violet AI accent. */\nexport type AiButtonVariant = \"ai\" | \"ai-subtle\" | \"ai-ghost\";\n\nexport interface AiButtonProps extends Omit<ButtonProps, \"variant\"> {\n /** `ai` = solid CTA, `ai-subtle` = tinted chip, `ai-ghost` = inline text action. @default \"ai-subtle\" */\n variant?: AiButtonVariant;\n /** Swaps the leading icon for a spinner and disables the button while an AI call is in flight. */\n loading?: boolean;\n /** Leading icon. @default Sparkles */\n icon?: ElementType<NavIconProps>;\n}\n\n/**\n * The \"do something with AI\" button: sparkle icon plus a built-in in-flight\n * state on top of `Button`'s `ai*` variants. Forwards its ref like `Button`\n * so it works as a Radix `asChild` trigger — `AiExplainButton` mounts one\n * inside `PopoverTrigger`, which needs the DOM node to anchor the popover.\n */\nexport const AiButton = forwardRef<HTMLButtonElement, AiButtonProps>(\n ({ variant = \"ai-subtle\", loading = false, icon: Icon = Sparkles, disabled, children, ...props }, ref) => (\n <Button\n ref={ref}\n variant={variant}\n disabled={disabled || loading}\n aria-busy={loading || undefined}\n {...props}\n >\n {loading ? (\n <LoadingSpinner size=\"sm\" className=\"[&_svg]:text-current\" />\n ) : (\n <Icon className=\"h-4 w-4\" aria-hidden=\"true\" />\n )}\n {children}\n </Button>\n ),\n);\nAiButton.displayName = \"AiButton\";\n","import { RefreshCw, Sparkles } from \"lucide-react\";\nimport type { ReactElement, ReactNode } from \"react\";\nimport { useState } from \"react\";\nimport { Popover, PopoverContent, PopoverTrigger } from \"../../primitives/popover\";\nimport { Button } from \"../../primitives/button\";\nimport { AlertBox } from \"../alert-box/AlertBox\";\nimport { LoadingSpinner } from \"../loading-spinner/LoadingSpinner\";\nimport { AiButton, type AiButtonProps } from \"./AiButton\";\n\nexport interface AiExplainButtonProps\n extends Omit<AiButtonProps, \"children\" | \"onClick\" | \"loading\" | \"title\" | \"aria-busy\"> {\n /**\n * Produces the explanation, called the first time the popover opens (and on\n * \"Try again\" after a failure) — not on mount, so nothing is spent on a\n * button nobody clicks.\n */\n onExplain: () => Promise<ReactNode> | ReactNode;\n /** Button text. @default \"Explain\" */\n label?: string;\n /** Heading inside the popover. @default the label */\n title?: string;\n /** Popover alignment relative to the button. @default \"start\" */\n align?: \"start\" | \"center\" | \"end\";\n /** Class names for the popover panel, e.g. to widen it. @default \"w-80\" */\n contentClassName?: string;\n}\n\n/**\n * \"What am I looking at?\" button: a sparkle affordance next to a chart, a KPI\n * or a form field that opens a popover and lazily asks the caller's model to\n * explain it. The caller returns any node, so an explanation can be prose,\n * a list, or a small rendered breakdown. Every other prop (`variant`, `size`,\n * `icon`, `data-testid`, ...) goes to the underlying `AiButton`.\n */\nexport function AiExplainButton({\n onExplain,\n label = \"Explain\",\n title,\n align = \"start\",\n contentClassName = \"w-80\",\n size = \"sm\",\n ...props\n}: AiExplainButtonProps): ReactElement {\n const [open, setOpen] = useState(false);\n const [loading, setLoading] = useState(false);\n const [content, setContent] = useState<ReactNode | null>(null);\n const [error, setError] = useState<string | null>(null);\n\n const load = async (): Promise<void> => {\n setLoading(true);\n setError(null);\n try {\n setContent(await onExplain());\n } catch (err) {\n setError(err instanceof Error ? err.message : String(err));\n } finally {\n setLoading(false);\n }\n };\n\n const handleOpenChange = (next: boolean): void => {\n setOpen(next);\n // ponytail: cached for the life of the component -- a \"Regenerate\" action\n // can go on top of `load()` if a consumer ever needs a fresh answer.\n if (next && content === null && error === null && !loading) void load();\n };\n\n return (\n <Popover open={open} onOpenChange={handleOpenChange}>\n <PopoverTrigger asChild>\n <AiButton size={size} {...props}>\n {label}\n </AiButton>\n </PopoverTrigger>\n <PopoverContent align={align} className={contentClassName}>\n <p className=\"mb-2 flex items-center gap-1.5 text-sm font-semibold\">\n <Sparkles className=\"h-4 w-4 shrink-0 text-muted-foreground\" aria-hidden=\"true\" />\n {title ?? label}\n </p>\n {loading ? (\n <LoadingSpinner size=\"sm\" label=\"Thinking…\" className=\"text-sm text-muted-foreground\" />\n ) : error ? (\n <div className=\"flex flex-col items-start gap-2\">\n <div role=\"alert\" className=\"w-full\">\n <AlertBox variant=\"error\">{error}</AlertBox>\n </div>\n <Button type=\"button\" variant=\"outline\" size=\"sm\" onClick={() => void load()}>\n <RefreshCw className=\"h-4 w-4\" aria-hidden=\"true\" />\n Try again\n </Button>\n </div>\n ) : (\n <div className=\"max-h-80 overflow-y-auto text-sm leading-relaxed\">{content}</div>\n )}\n </PopoverContent>\n </Popover>\n );\n}\n","import { Mic, MicOff } from \"lucide-react\";\nimport { forwardRef } from \"react\";\nimport { Button, type ButtonProps } from \"../../primitives/button\";\nimport { cn } from \"../../lib/utils\";\nimport { type SpeechRecognitionEngineFactory, useSpeechRecognition } from \"./useSpeechRecognition\";\n\nexport interface VoiceInputButtonProps\n extends Omit<ButtonProps, \"onError\" | \"variant\" | \"children\"> {\n /** Called with each finalized chunk of speech, ready to append to whatever the caller is filling in. */\n onTranscript: (text: string) => void;\n /** Called with the recognizer's raw error code (`\"not-allowed\"`, `\"no-speech\"`, ...) — see `describeSpeechError` for user-facing text. */\n onError?: (error: string) => void;\n /** BCP-47 tag, e.g. `\"de-CH\"`. Defaults to the document language. */\n lang?: string;\n /**\n * Overrides what backs dictation — e.g. to stream audio to a server-side\n * transcription API instead of the browser's on-device `SpeechRecognition`.\n * See `useSpeechRecognition`'s `engine` option. Passing this makes the\n * button render enabled unconditionally, since browser support no longer\n * applies.\n */\n engine?: SpeechRecognitionEngineFactory;\n /** Rendered next to the icon. Icon-only (the default) when omitted. */\n label?: string;\n /** Accessible name while idle (icon-only buttons only). @default \"Start dictation\" */\n startLabel?: string;\n /** Accessible name while listening (icon-only buttons only). @default \"Stop dictation\" */\n stopLabel?: string;\n /** Renders the interim (not yet finalized) words next to the button. @default false */\n showInterim?: boolean;\n}\n\n/**\n * Push-to-dictate microphone button, backed by the browser's built-in\n * `SpeechRecognition` by default — no API key, no upload, no extra\n * dependency. Pass `engine` to back it with something else instead, such as\n * a server-side transcription API (see `useSpeechRecognition`'s `engine`\n * option). While listening it takes the `destructive` tint (the same one\n * AlertBox's `error` uses) and only the mic icon pulses, so the \"recording\"\n * signal reads at a glance without the whole control throbbing. Where\n * neither `engine` nor the browser API is available (Firefox, most mobile)\n * the button renders disabled with a crossed-out mic rather than vanishing,\n * so the layout doesn't shift between browsers.\n */\nexport const VoiceInputButton = forwardRef<HTMLButtonElement, VoiceInputButtonProps>(\n (\n {\n onTranscript,\n onError,\n lang,\n engine,\n label,\n startLabel = \"Start dictation\",\n stopLabel = \"Stop dictation\",\n showInterim = false,\n size,\n disabled,\n className,\n ...props\n },\n ref,\n ) => {\n const { supported, listening, interim, toggle } = useSpeechRecognition({\n lang,\n onResult: onTranscript,\n onError,\n engine,\n });\n const unsupportedTitle = \"Speech recognition isn't available in this browser\";\n\n return (\n // `title` lives on the wrapper, not the button: buttonVariants sets\n // `disabled:pointer-events-none`, so a disabled button never shows its own.\n <span className=\"inline-flex min-w-0 items-center gap-2\" title={supported ? undefined : unsupportedTitle}>\n <Button\n ref={ref}\n type=\"button\"\n variant=\"outline\"\n size={size ?? (label ? \"default\" : \"icon\")}\n onClick={toggle}\n disabled={disabled || !supported}\n aria-label={label ? undefined : supported ? (listening ? stopLabel : startLabel) : unsupportedTitle}\n aria-pressed={supported ? listening : undefined}\n className={cn(\n listening &&\n \"border-destructive bg-destructive/10 text-red-800 hover:bg-destructive/15 hover:text-red-800 dark:text-red-300 dark:hover:text-red-300\",\n className,\n )}\n {...props}\n >\n {supported ? (\n <Mic className={cn(\"h-4 w-4\", listening && \"animate-pulse motion-reduce:animate-none\")} aria-hidden=\"true\" />\n ) : (\n <MicOff className=\"h-4 w-4\" aria-hidden=\"true\" />\n )}\n {label}\n </Button>\n {showInterim && interim ? (\n <span aria-live=\"polite\" className=\"truncate text-sm text-muted-foreground italic\">\n {interim}\n </span>\n ) : null}\n </span>\n );\n },\n);\nVoiceInputButton.displayName = \"VoiceInputButton\";\n","import { useCallback, useEffect, useRef, useState } from \"react\";\n\n// The Web Speech API isn't in TypeScript's DOM lib, so the minimal shape we\n// actually touch is declared here rather than pulling in @types/dom-speech-recognition.\ninterface SpeechRecognitionAlternative {\n transcript: string;\n}\ninterface SpeechRecognitionResult {\n isFinal: boolean;\n 0: SpeechRecognitionAlternative;\n}\ninterface SpeechRecognitionEventLike {\n resultIndex: number;\n results: { length: number; [index: number]: SpeechRecognitionResult };\n}\n/**\n * The recognizer contract `useSpeechRecognition` drives — matches the shape\n * of the browser's built-in `SpeechRecognition`/`webkitSpeechRecognition`,\n * which is also what the default engine (below) wraps. Implement this to\n * swap in something other than the browser's on-device recognizer — for\n * example a server-side transcription API — via the `engine` option.\n * Whatever backs it, finalized chunks and interim words must arrive through\n * `onresult` the same way the Web Speech API delivers them.\n */\nexport interface SpeechRecognitionEngine {\n lang: string;\n continuous: boolean;\n interimResults: boolean;\n start(): void;\n stop(): void;\n abort(): void;\n onresult: ((event: SpeechRecognitionEventLike) => void) | null;\n onerror: ((event: { error: string }) => void) | null;\n onend: (() => void) | null;\n}\n/** Builds one `SpeechRecognitionEngine` per dictation session (`start()` calls it fresh each time). */\nexport type SpeechRecognitionEngineFactory = () => SpeechRecognitionEngine;\ntype SpeechRecognitionCtor = new () => SpeechRecognitionEngine;\n\nfunction getCtor(): SpeechRecognitionCtor | undefined {\n if (typeof window === \"undefined\") return undefined;\n const w = window as unknown as {\n SpeechRecognition?: SpeechRecognitionCtor;\n webkitSpeechRecognition?: SpeechRecognitionCtor;\n };\n return w.SpeechRecognition ?? w.webkitSpeechRecognition;\n}\n\n/** The default engine: the browser's own `SpeechRecognition`/`webkitSpeechRecognition`. */\nfunction browserEngine(): SpeechRecognitionEngine | null {\n const Ctor = getCtor();\n return Ctor ? new Ctor() : null;\n}\n\n/**\n * Turns a recognizer error code into a sentence a user can act on, or `null`\n * for codes that aren't the user's problem (`aborted` fires on every\n * programmatic stop/unmount and would otherwise flash an alert on each one).\n * `onError` still receives the raw code, for callers who want to branch.\n */\nexport function describeSpeechError(code: string): string | null {\n switch (code) {\n case \"aborted\":\n return null;\n case \"not-allowed\":\n case \"service-not-allowed\":\n return \"Microphone access is blocked. Allow it in the browser's site settings and try again.\";\n case \"audio-capture\":\n return \"No microphone was found.\";\n case \"no-speech\":\n return \"No speech was detected.\";\n case \"network\":\n return \"Speech recognition needs a network connection.\";\n default:\n return `Speech recognition failed (${code}).`;\n }\n}\n\nexport interface UseSpeechRecognitionOptions {\n /** BCP-47 tag passed to the recognizer, e.g. `\"de-CH\"`. @default the document language, else \"en-US\" */\n lang?: string;\n /** Called with each finalized chunk of speech. */\n onResult?: (text: string) => void;\n /** Called when the recognizer reports an error (`\"not-allowed\"`, `\"no-speech\"`, ...). */\n onError?: (error: string) => void;\n /**\n * Overrides what backs dictation — e.g. to stream audio to a server-side\n * transcription API instead of the browser's on-device `SpeechRecognition`.\n * Called once per `start()` to build that session's engine; must satisfy\n * `SpeechRecognitionEngine`. Omit to use the browser's Web Speech API\n * (`supported` then reflects whether that API exists); passing `engine`\n * makes `supported` unconditionally `true`, since the caller's factory is\n * assumed to work wherever the app decides to render the button.\n */\n engine?: SpeechRecognitionEngineFactory;\n}\n\nexport interface SpeechRecognitionState {\n /** False when neither a custom `engine` nor the browser's Web Speech API is available (Firefox, most of mobile, SSR). */\n supported: boolean;\n listening: boolean;\n /** The not-yet-finalized words the recognizer is still revising. */\n interim: string;\n error: string | null;\n start: () => void;\n stop: () => void;\n toggle: () => void;\n}\n\n/**\n * Thin hook over a `SpeechRecognitionEngine` — by default the browser's\n * built-in `SpeechRecognition`, so no dependency and no server round-trip;\n * pass `engine` to back it with something else (e.g. a server-side\n * transcription API) instead. Finalized chunks are pushed to `onResult`;\n * the caller owns the accumulated transcript (so it stays editable), this\n * only reports what's currently being heard.\n */\nexport function useSpeechRecognition({\n lang,\n onResult,\n onError,\n engine,\n}: UseSpeechRecognitionOptions = {}): SpeechRecognitionState {\n const [listening, setListening] = useState(false);\n const [interim, setInterim] = useState(\"\");\n const [error, setError] = useState<string | null>(null);\n const recognitionRef = useRef<SpeechRecognitionEngine | null>(null);\n // Kept in refs so restarting the recognizer isn't needed when a caller\n // passes fresh inline callbacks on every render.\n const onResultRef = useRef(onResult);\n const onErrorRef = useRef(onError);\n const engineRef = useRef(engine);\n onResultRef.current = onResult;\n onErrorRef.current = onError;\n engineRef.current = engine;\n\n const supported = engine !== undefined || getCtor() !== undefined;\n\n const stop = useCallback(() => {\n recognitionRef.current?.stop();\n }, []);\n\n const start = useCallback(() => {\n if (recognitionRef.current) return;\n const recognition = engineRef.current ? engineRef.current() : browserEngine();\n if (!recognition) return;\n recognition.lang =\n lang ?? (typeof document !== \"undefined\" ? document.documentElement.lang : \"\") ?? \"\";\n if (!recognition.lang) recognition.lang = \"en-US\";\n recognition.continuous = true;\n recognition.interimResults = true;\n recognition.onresult = (event) => {\n let pending = \"\";\n for (let i = event.resultIndex; i < event.results.length; i += 1) {\n const result = event.results[i];\n if (!result) continue;\n if (result.isFinal) onResultRef.current?.(result[0].transcript.trim());\n else pending += result[0].transcript;\n }\n setInterim(pending);\n };\n recognition.onerror = (event) => {\n setError(event.error);\n onErrorRef.current?.(event.error);\n };\n recognition.onend = () => {\n recognitionRef.current = null;\n setListening(false);\n setInterim(\"\");\n };\n recognitionRef.current = recognition;\n setError(null);\n setInterim(\"\");\n setListening(true);\n recognition.start();\n }, [lang]);\n\n const toggle = useCallback(() => {\n if (recognitionRef.current) stop();\n else start();\n }, [start, stop]);\n\n // Abort rather than stop on unmount: stop() would still fire a final\n // onresult into callbacks whose component is already gone.\n useEffect(() => () => recognitionRef.current?.abort(), []);\n\n return { supported, listening, interim, error, start, stop, toggle };\n}\n","import { Undo2, Wand2 } from \"lucide-react\";\nimport type { HTMLAttributes, ReactElement } from \"react\";\nimport { useState } from \"react\";\nimport { Textarea } from \"../../primitives/textarea\";\nimport { Button } from \"../../primitives/button\";\nimport { cn } from \"../../lib/utils\";\nimport { AlertBox } from \"../alert-box/AlertBox\";\nimport { AiButton } from \"./AiButton\";\nimport { VoiceInputButton } from \"./VoiceInputButton\";\nimport { describeSpeechError, type SpeechRecognitionEngineFactory } from \"./useSpeechRecognition\";\n\nexport interface VoiceTranscriptProps extends Omit<HTMLAttributes<HTMLDivElement>, \"onChange\"> {\n /** The transcript. Controlled, like `SearchBar` — the caller owns the text. */\n value: string;\n onChange: (value: string) => void;\n /**\n * Rewrites the transcript with AI (clean up, translate, summarize —\n * whatever the caller's model does) and resolves with the new text.\n * Omitted hides the transform button, leaving plain dictation.\n */\n onTransform?: (text: string) => Promise<string> | string;\n /** @default \"Transform with AI\" */\n transformLabel?: string;\n /** @default \"Speak or type…\" */\n placeholder?: string;\n /** BCP-47 tag for dictation, e.g. `\"de-CH\"`. Defaults to the document language. */\n lang?: string;\n /**\n * Overrides what backs dictation — e.g. to stream audio to a server-side\n * transcription API instead of the browser's on-device `SpeechRecognition`.\n * Forwarded to `VoiceInputButton`; see `useSpeechRecognition`'s `engine`\n * option.\n */\n engine?: SpeechRecognitionEngineFactory;\n /** @default 4 */\n rows?: number;\n disabled?: boolean;\n className?: string;\n}\n\n/**\n * Dictate → edit → rewrite-with-AI, in one box: a mic button feeding an\n * editable transcript, plus a \"Transform with AI\" action that hands the text\n * to the caller's model and swaps in the result (with one-click undo, since\n * a model rewriting your own words is exactly where you want an escape hatch).\n */\nexport function VoiceTranscript({\n value,\n onChange,\n onTransform,\n transformLabel = \"Transform with AI\",\n placeholder = \"Speak or type…\",\n lang,\n engine,\n rows = 4,\n disabled,\n className,\n ...props\n}: VoiceTranscriptProps): ReactElement {\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState<string | null>(null);\n const [previous, setPrevious] = useState<string | null>(null);\n\n const append = (chunk: string): void => {\n onChange(value ? `${value.trimEnd()} ${chunk}` : chunk);\n };\n\n const transform = async (): Promise<void> => {\n if (!onTransform) return;\n const before = value;\n setLoading(true);\n setError(null);\n try {\n const next = await onTransform(before);\n setPrevious(before);\n onChange(next);\n } catch (err) {\n setError(err instanceof Error ? err.message : String(err));\n } finally {\n setLoading(false);\n }\n };\n\n const undo = (): void => {\n if (previous === null) return;\n onChange(previous);\n setPrevious(null);\n };\n\n return (\n <div className={cn(\"flex flex-col gap-2\", className)} {...props}>\n <Textarea\n value={value}\n onChange={(event) => onChange(event.target.value)}\n placeholder={placeholder}\n rows={rows}\n disabled={disabled || loading}\n aria-busy={loading || undefined}\n />\n <div className=\"flex flex-wrap items-center gap-2\">\n <VoiceInputButton\n onTranscript={append}\n onError={(code) => setError(describeSpeechError(code))}\n lang={lang}\n engine={engine}\n label=\"Dictate\"\n size=\"sm\"\n showInterim\n disabled={disabled || loading}\n />\n {onTransform ? (\n <AiButton\n variant=\"ai\"\n size=\"sm\"\n icon={Wand2}\n loading={loading}\n disabled={disabled || value.trim().length === 0}\n onClick={() => void transform()}\n >\n {transformLabel}\n </AiButton>\n ) : null}\n {previous !== null && !loading ? (\n <Button type=\"button\" variant=\"ghost\" size=\"sm\" onClick={undo}>\n <Undo2 className=\"h-4 w-4\" aria-hidden=\"true\" />\n Undo\n </Button>\n ) : null}\n </div>\n {error ? (\n // AlertBox has no `role` prop, so the live region wraps it; same shape\n // a consuming app's own form errors take.\n <div role=\"alert\">\n <AlertBox variant=\"error\">{error}</AlertBox>\n </div>\n ) : null}\n </div>\n );\n}\n","import { useEffect, useRef } from \"react\";\nimport { Check, Plus } from \"lucide-react\";\nimport { cn } from \"../../lib/utils\";\n\n/** The minimal shape this component needs to render one chip in the stepper. */\nexport interface StepperStep {\n /** 1-based step number, also used as the React key and navigation target. */\n n: number;\n /** Visible label under the chip. */\n label: string;\n /** Small uppercase caption under the label (e.g. a phase/section name). */\n phase: string;\n}\n\nexport interface StepperProps {\n /** The current step number (1-based, matches a `StepperStep.n`). */\n step: number;\n /** Highest step number reachable so far -- steps beyond this aren't clickable. */\n maxStep: number;\n /** Called with a step's `n` when a navigable chip is clicked. */\n onNavigate: (n: number) => void;\n /** Called when the trailing \"new\" button is clicked. Omit to hide that button entirely. */\n onNew?: () => void;\n /** The steps to render, in order. */\n steps: StepperStep[];\n /** Accessible label for the stepper's `<nav>`. @default \"Steps\" */\n navLabel?: string;\n /** Visible text and title of the trailing `onNew` button. Only relevant when `onNew` is passed. @default \"New\" */\n newLabel?: string;\n /** `data-testid` for the horizontally-scrolling steps region. @default \"stepper-scroll\" */\n scrollTestId?: string;\n /** `data-testid` for the trailing `onNew` button, when rendered. */\n newTestId?: string;\n}\n\n/**\n * Numbered-chip wizard progress indicator: a horizontally-scrolling row of\n * step chips (done/active/upcoming, connected by a line that fills in as\n * steps complete) plus an optional trailing \"start over\" button. Replaces\n * the same shape hand-rolled independently by more than one multi-step\n * wizard.\n *\n * Note: the original OneSales `Stepper` this was ported from also supported\n * a one-off `tinderSubStep` prop that injected a bespoke \"matcher\" chip\n * between two specific steps for a single screen's own sub-flow. That was\n * deliberately left out of this generic version -- it doesn't generalize\n * meaningfully beyond that one screen. Don't re-add it here; a consumer\n * that needs a one-off extra chip should compose its own around this\n * component instead.\n */\nexport function Stepper({\n step,\n maxStep,\n onNavigate,\n onNew,\n steps,\n navLabel = \"Steps\",\n newLabel = \"New\",\n scrollTestId = \"stepper-scroll\",\n newTestId,\n}: StepperProps) {\n const stepRefs = useRef(new Map<number, HTMLButtonElement>());\n\n useEffect(() => {\n const activeStep = stepRefs.current.get(step);\n activeStep?.scrollIntoView({ block: \"nearest\", inline: \"center\" });\n }, [step]);\n\n return (\n // onNew is pinned outside the horizontally-scrolling region below (a sibling of\n // it, not a child) so its own edge never scrolls off-screen along with the\n // later steps once the scroller's min-width doesn't fit the viewport.\n <div className=\"flex w-full shrink-0 items-center gap-2\">\n <nav aria-label={navLabel} className=\"min-w-0 flex-1\">\n <div\n data-testid={scrollTestId}\n className=\"flex w-full items-center gap-0 overflow-x-auto px-2 py-1\"\n >\n <ol className=\"flex min-w-[700px] flex-1 items-start\">\n {steps.map(({ n, label, phase }, i) => {\n const done = step > n;\n const active = step === n;\n const navigable = n <= maxStep && n !== step;\n const last = i === steps.length - 1;\n return (\n <li key={n} className={cn(\"flex items-start\", !last && \"flex-1\")}>\n <button\n ref={(element) => {\n if (element) stepRefs.current.set(n, element);\n else stepRefs.current.delete(n);\n }}\n data-testid={`step-${n}`}\n aria-disabled={!navigable}\n aria-current={active ? \"step\" : undefined}\n onClick={() => navigable && onNavigate(n)}\n className={cn(\n \"flex min-w-[68px] flex-col items-center gap-0.5 transition-opacity\",\n navigable ? \"cursor-pointer hover:opacity-80\" : \"cursor-default\",\n )}\n >\n <div\n className={cn(\n \"flex h-7 w-7 shrink-0 items-center justify-center rounded-full text-[11px] font-bold transition-colors\",\n done\n ? \"bg-primary/15 text-primary\"\n : active\n ? \"bg-primary text-primary-foreground\"\n : \"bg-muted text-muted-foreground\",\n )}\n >\n {done ? <Check className=\"h-3 w-3\" /> : n}\n </div>\n <span\n className={cn(\n \"text-center whitespace-nowrap transition-colors\",\n active\n ? \"text-[12px] font-semibold text-foreground\"\n : done\n ? \"text-[12px] font-medium text-primary\"\n : \"text-[12px] font-medium text-muted-foreground\",\n )}\n >\n {label}\n </span>\n <span className=\"text-[9px] tracking-[0.5px] text-muted-foreground/50 uppercase\">\n {phase}\n </span>\n </button>\n {!last && (\n <div\n className={cn(\n \"mx-1.5 mt-3.5 h-px flex-1 transition-colors\",\n done ? \"bg-primary\" : \"bg-border\",\n )}\n />\n )}\n </li>\n );\n })}\n </ol>\n </div>\n </nav>\n {onNew && (\n <button\n data-testid={newTestId}\n onClick={onNew}\n title={newLabel}\n className=\"flex shrink-0 items-center gap-1.5 rounded-lg border border-border px-3 py-1.5 text-[12px] font-semibold text-foreground transition-colors hover:bg-muted/50\"\n >\n <Plus className=\"h-3.5 w-3.5\" />\n {newLabel}\n </button>\n )}\n </div>\n );\n}\n"],"mappings":"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","names":["forwardRef","jsx","forwardRef","forwardRef","jsx","forwardRef","forwardRef","jsx","forwardRef","jsx","cva","jsx","cva","forwardRef","jsx","forwardRef","forwardRef","jsx","forwardRef","forwardRef","jsx","jsxs","forwardRef","jsx","Check","forwardRef","jsx","forwardRef","Check","forwardRef","jsx","forwardRef","forwardRef","jsx","forwardRef","forwardRef","jsx","forwardRef","forwardRef","jsx","jsxs","forwardRef","forwardRef","jsx","forwardRef","Check","forwardRef","jsx","jsxs","forwardRef","Check","cva","DialogPrimitive","X","forwardRef","jsx","jsxs","forwardRef","cva","X","forwardRef","jsx","forwardRef","jsx","jsxs","useState","useState","Fragment","jsx","jsxs","useState","jsx","useState","useState","jsx","jsxs","useState","useRef","useState","useEffect","useState","jsx","jsxs","useState","useRef","next","useState","jsx","useState","jsx","jsxs","Check","X","useEffect","useRef","useState","jsx","jsxs","jsx","jsxs","useState","useRef","useEffect","Check","X","X","useEffect","useMemo","useRef","useState","jsx","jsxs","useState","useRef","useMemo","useEffect","X","jsx","jsxs","jsx","jsx","jsxs","Icon","cva","jsx","jsxs","cva","X","jsx","jsxs","X","Fragment","jsx","jsxs","KpiCard","Icon","Search","jsx","jsxs","Search","Icon","Search","jsx","Search","jsx","jsxs","Icon","ChevronDown","useState","jsx","jsxs","useState","ChevronDown","useEffect","useRef","useState","Fragment","jsx","jsxs","useState","useRef","useEffect","forwardRef","jsx","jsxs","forwardRef","Icon","Sparkles","useState","jsx","jsxs","useState","Sparkles","forwardRef","useCallback","useEffect","useRef","useState","jsx","jsxs","forwardRef","useState","jsx","jsxs","useState","useEffect","useRef","Check","jsx","jsxs","useRef","useEffect","Check"]}