@loworbitstudio/visor 1.3.4 → 1.5.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.
@@ -71,7 +71,7 @@
71
71
  {
72
72
  "path": "components/ui/stepper/stepper.module.css",
73
73
  "type": "registry:ui",
74
- "content": "/* Stepper container */\n.stepper {\n display: flex;\n align-items: flex-start;\n gap: 0;\n width: 100%;\n}\n\n.stepperVertical {\n flex-direction: column;\n}\n\n/* Stepper item */\n.item {\n display: flex;\n align-items: center;\n gap: var(--spacing-2, 0.5rem);\n flex: 1;\n min-width: 0;\n}\n\n.itemVertical {\n flex-direction: row;\n align-items: flex-start;\n}\n\n/* Trigger (step indicator circle) */\n.trigger {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n width: 2rem;\n height: 2rem;\n border-radius: var(--radius-full, 9999px);\n font-size: var(--font-size-sm, 0.875rem);\n font-weight: var(--font-weight-medium, 500);\n border: 2px solid transparent;\n cursor: pointer;\n transition: background-color var(--motion-duration-200, 200ms) var(--motion-easing-default, ease-in-out),\n border-color var(--motion-duration-200, 200ms) var(--motion-easing-default, ease-in-out),\n color var(--motion-duration-200, 200ms) var(--motion-easing-default, ease-in-out);\n}\n\n.trigger:focus-visible {\n outline: var(--focus-ring-width, 2px) solid var(--border-focus, currentColor);\n outline-offset: var(--focus-ring-offset, 2px);\n}\n\n/* Trigger status variants */\n.trigger--complete {\n background-color: var(--interactive-primary-bg, #111827);\n border-color: var(--interactive-primary-bg, #111827);\n color: var(--interactive-primary-text, #f9fafb);\n}\n\n.trigger--active {\n background-color: transparent;\n border-color: var(--interactive-primary-bg, #111827);\n color: var(--interactive-primary-bg, #111827);\n}\n\n.trigger--upcoming {\n background-color: transparent;\n border-color: var(--border-default, #e5e7eb);\n color: var(--text-tertiary, #9ca3af);\n}\n\n/* Title */\n.title {\n font-size: var(--font-size-sm, 0.875rem);\n font-weight: var(--font-weight-medium, 500);\n color: var(--text-primary, #111827);\n line-height: var(--line-height-snug, 1.375);\n white-space: nowrap;\n}\n\n/* Description */\n.description {\n font-size: var(--font-size-xs, 0.75rem);\n color: var(--text-secondary, #6b7280);\n line-height: var(--line-height-normal, 1.5);\n margin: 0;\n}\n\n/* Separator */\n.separator {\n flex: 1;\n height: 2px;\n min-width: var(--spacing-4, 1rem);\n background-color: var(--border-muted, #e5e7eb);\n align-self: center;\n margin: 0 var(--spacing-2, 0.5rem);\n transition: background-color var(--motion-duration-200, 200ms) var(--motion-easing-default, ease-in-out);\n}\n\n.separatorVertical {\n width: 2px;\n height: var(--spacing-6, 1.5rem);\n min-width: auto;\n margin: var(--spacing-1, 0.25rem) 0 var(--spacing-1, 0.25rem) calc(1rem - 1px);\n align-self: flex-start;\n flex: none;\n}\n\n.separatorComplete {\n background-color: var(--interactive-primary-bg, #111827);\n}\n\n/* Screen reader only */\n.srOnly {\n position: absolute;\n width: 1px;\n height: 1px;\n padding: 0;\n margin: -1px;\n overflow: hidden;\n clip: rect(0, 0, 0, 0);\n white-space: nowrap;\n border-width: 0;\n}\n"
74
+ "content": "/* Stepper container */\n.stepper {\n display: flex;\n align-items: flex-start;\n gap: 0;\n width: 100%;\n}\n\n.stepperVertical {\n flex-direction: column;\n}\n\n/* Stepper item */\n.item {\n display: flex;\n align-items: center;\n gap: var(--spacing-2, 0.5rem);\n flex: 1;\n min-width: 0;\n}\n\n.itemVertical {\n flex-direction: row;\n align-items: flex-start;\n}\n\n/* Trigger (step indicator circle) */\n.trigger {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n width: 2rem;\n height: 2rem;\n border-radius: var(--radius-full, 9999px);\n font-size: var(--font-size-sm, 0.875rem);\n font-weight: var(--font-weight-medium, 500);\n border: 2px solid transparent;\n cursor: pointer;\n transition: background-color var(--motion-duration-200, 200ms) var(--motion-easing-default, ease-in-out),\n border-color var(--motion-duration-200, 200ms) var(--motion-easing-default, ease-in-out),\n color var(--motion-duration-200, 200ms) var(--motion-easing-default, ease-in-out);\n}\n\n.trigger:focus-visible {\n outline: var(--focus-ring-width, 2px) solid var(--border-focus, currentColor);\n outline-offset: var(--focus-ring-offset, 2px);\n}\n\n/* Trigger status variants */\n.trigger--complete {\n background-color: var(--interactive-primary-bg, var(--primary, #111827));\n border-color: var(--interactive-primary-bg, var(--primary, #111827));\n color: var(--interactive-primary-text, #f9fafb);\n}\n\n.trigger--active {\n background-color: transparent;\n border-color: var(--interactive-primary-bg, var(--primary, #111827));\n color: var(--interactive-primary-bg, var(--primary, #111827));\n}\n\n.trigger--upcoming {\n background-color: transparent;\n border-color: var(--border-default, #e5e7eb);\n color: var(--text-tertiary, #9ca3af);\n}\n\n/* Title */\n.title {\n font-size: var(--font-size-sm, 0.875rem);\n font-weight: var(--font-weight-medium, 500);\n color: var(--text-primary, #111827);\n line-height: var(--line-height-snug, 1.375);\n white-space: nowrap;\n}\n\n/* Description */\n.description {\n font-size: var(--font-size-xs, 0.75rem);\n color: var(--text-secondary, #6b7280);\n line-height: var(--line-height-normal, 1.5);\n margin: 0;\n}\n\n/* Separator */\n.separator {\n flex: 1;\n height: 2px;\n min-width: var(--spacing-4, 1rem);\n background-color: var(--border-muted, #e5e7eb);\n align-self: center;\n margin: 0 var(--spacing-2, 0.5rem);\n transition: background-color var(--motion-duration-200, 200ms) var(--motion-easing-default, ease-in-out);\n}\n\n.separatorVertical {\n width: 2px;\n height: var(--spacing-6, 1.5rem);\n min-width: auto;\n margin: var(--spacing-1, 0.25rem) 0 var(--spacing-1, 0.25rem) calc(1rem - 1px);\n align-self: flex-start;\n flex: none;\n}\n\n.separatorComplete {\n background-color: var(--interactive-primary-bg, var(--primary, #111827));\n}\n\n/* Screen reader only */\n.srOnly {\n position: absolute;\n width: 1px;\n height: 1px;\n padding: 0;\n margin: -1px;\n overflow: hidden;\n clip: rect(0, 0, 0, 0);\n white-space: nowrap;\n border-width: 0;\n}\n"
75
75
  }
76
76
  ]
77
77
  },
@@ -120,7 +120,7 @@
120
120
  {
121
121
  "path": "components/ui/timeline/timeline.module.css",
122
122
  "type": "registry:ui",
123
- "content": "/* Timeline container */\n.timeline {\n display: flex;\n flex-direction: column;\n gap: 0;\n}\n\n/* Timeline item */\n.item {\n display: flex;\n gap: var(--spacing-3, 0.75rem);\n position: relative;\n padding-bottom: var(--spacing-6, 1.5rem);\n}\n\n/* Connector line */\n.item::after {\n content: \"\";\n position: absolute;\n left: calc(0.5rem - 1px); /* center of the dot (8px / 2 - 1px border) */\n top: calc(1rem + var(--spacing-1, 0.25rem));\n bottom: 0;\n width: 2px;\n background-color: var(--border-muted, #e5e7eb);\n}\n\n.item:last-child::after {\n display: none;\n}\n\n.item:last-child {\n padding-bottom: 0;\n}\n\n/* Default dot (when no TimelineIcon is provided) */\n.item::before {\n content: \"\";\n flex-shrink: 0;\n width: 1rem;\n height: 1rem;\n border-radius: var(--radius-full, 9999px);\n margin-top: var(--spacing-1, 0.25rem);\n z-index: 1;\n transition: background-color var(--motion-duration-150, 150ms) var(--motion-easing-default, ease-in-out),\n border-color var(--motion-duration-150, 150ms) var(--motion-easing-default, ease-in-out);\n}\n\n/* Status-based dot styling */\n.item--upcoming::before {\n background-color: var(--surface-muted, #f3f4f6);\n border: 2px solid var(--border-default, #e5e7eb);\n}\n\n.item--active::before {\n background-color: var(--interactive-primary-bg, #111827);\n border: 2px solid var(--interactive-primary-bg, #111827);\n}\n\n.item--complete::before {\n background-color: var(--interactive-primary-bg, #111827);\n border: 2px solid var(--interactive-primary-bg, #111827);\n}\n\n/* Hide default dot when TimelineIcon is present */\n.item:has(> [data-slot=\"timeline-icon\"])::before {\n display: none;\n}\n\n/* Adjust connector position when icon is present */\n.item:has(> [data-slot=\"timeline-icon\"])::after {\n left: calc(0.75rem - 1px); /* center of the icon container */\n}\n\n/* Timeline icon slot */\n.icon {\n display: flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n width: 1.5rem;\n height: 1.5rem;\n border-radius: var(--radius-full, 9999px);\n background-color: var(--interactive-primary-bg, #111827);\n color: var(--interactive-primary-text, #f9fafb);\n z-index: 1;\n margin-top: var(--spacing-1, 0.25rem);\n}\n\n/* Content area */\n.content {\n display: flex;\n flex-direction: column;\n gap: var(--spacing-1, 0.25rem);\n min-width: 0;\n padding-top: 0;\n}\n\n/* Title */\n.title {\n font-size: var(--font-size-sm, 0.875rem);\n font-weight: var(--font-weight-medium, 500);\n color: var(--text-primary, #111827);\n line-height: var(--line-height-snug, 1.375);\n}\n\n/* Description */\n.description {\n font-size: var(--font-size-sm, 0.875rem);\n color: var(--text-secondary, #6b7280);\n line-height: var(--line-height-normal, 1.5);\n margin: 0;\n}\n\n/* Timestamp */\n.timestamp {\n font-size: var(--font-size-xs, 0.75rem);\n color: var(--text-tertiary, #9ca3af);\n line-height: var(--line-height-normal, 1.5);\n}\n"
123
+ "content": "/* Timeline container */\n.timeline {\n display: flex;\n flex-direction: column;\n gap: 0;\n}\n\n/* Timeline item */\n.item {\n display: flex;\n gap: var(--spacing-3, 0.75rem);\n position: relative;\n padding-bottom: var(--spacing-6, 1.5rem);\n}\n\n/* Connector line */\n.item::after {\n content: \"\";\n position: absolute;\n left: calc(0.5rem - 1px); /* center of the dot (8px / 2 - 1px border) */\n top: calc(1rem + var(--spacing-1, 0.25rem));\n bottom: 0;\n width: 2px;\n background-color: var(--border-muted, #e5e7eb);\n}\n\n.item:last-child::after {\n display: none;\n}\n\n.item:last-child {\n padding-bottom: 0;\n}\n\n/* Default dot (when no TimelineIcon is provided) */\n.item::before {\n content: \"\";\n flex-shrink: 0;\n width: 1rem;\n height: 1rem;\n border-radius: var(--radius-full, 9999px);\n margin-top: var(--spacing-1, 0.25rem);\n z-index: 1;\n transition: background-color var(--motion-duration-150, 150ms) var(--motion-easing-default, ease-in-out),\n border-color var(--motion-duration-150, 150ms) var(--motion-easing-default, ease-in-out);\n}\n\n/* Status-based dot styling */\n.item--upcoming::before {\n background-color: var(--surface-muted, #f3f4f6);\n border: 2px solid var(--border-default, #e5e7eb);\n}\n\n.item--active::before {\n background-color: var(--interactive-primary-bg, var(--primary, #111827));\n border: 2px solid var(--interactive-primary-bg, var(--primary, #111827));\n}\n\n.item--complete::before {\n background-color: var(--interactive-primary-bg, var(--primary, #111827));\n border: 2px solid var(--interactive-primary-bg, var(--primary, #111827));\n}\n\n/* Hide default dot when TimelineIcon is present */\n.item:has(> [data-slot=\"timeline-icon\"])::before {\n display: none;\n}\n\n/* Adjust connector position when icon is present */\n.item:has(> [data-slot=\"timeline-icon\"])::after {\n left: calc(0.75rem - 1px); /* center of the icon container */\n}\n\n/* Timeline icon slot */\n.icon {\n display: flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n width: 1.5rem;\n height: 1.5rem;\n border-radius: var(--radius-full, 9999px);\n background-color: var(--interactive-primary-bg, var(--primary, #111827));\n color: var(--interactive-primary-text, #f9fafb);\n z-index: 1;\n margin-top: var(--spacing-1, 0.25rem);\n}\n\n/* Content area */\n.content {\n display: flex;\n flex-direction: column;\n gap: var(--spacing-1, 0.25rem);\n min-width: 0;\n padding-top: 0;\n}\n\n/* Title */\n.title {\n font-size: var(--font-size-sm, 0.875rem);\n font-weight: var(--font-weight-medium, 500);\n color: var(--text-primary, #111827);\n line-height: var(--line-height-snug, 1.375);\n}\n\n/* Description */\n.description {\n font-size: var(--font-size-sm, 0.875rem);\n color: var(--text-secondary, #6b7280);\n line-height: var(--line-height-normal, 1.5);\n margin: 0;\n}\n\n/* Timestamp */\n.timestamp {\n font-size: var(--font-size-xs, 0.75rem);\n color: var(--text-tertiary, #9ca3af);\n line-height: var(--line-height-normal, 1.5);\n}\n"
124
124
  }
125
125
  ]
126
126
  },
@@ -141,12 +141,12 @@
141
141
  {
142
142
  "path": "components/ui/button/button.tsx",
143
143
  "type": "registry:ui",
144
- "content": "import * as React from \"react\"\nimport { Slot } from \"@radix-ui/react-slot\"\nimport { cva, type VariantProps } from \"class-variance-authority\"\nimport { cn } from \"../../../lib/utils\"\nimport styles from \"./button.module.css\"\n\nconst buttonVariants = cva(styles.base, {\n variants: {\n variant: {\n default: styles.variantDefault,\n secondary: styles.variantSecondary,\n outline: styles.variantOutline,\n ghost: styles.variantGhost,\n destructive: styles.variantDestructive,\n },\n size: {\n sm: styles.sizeSm,\n md: styles.sizeMd,\n lg: styles.sizeLg,\n },\n },\n defaultVariants: {\n variant: \"default\",\n size: \"md\",\n },\n})\n\nexport interface ButtonProps\n extends React.ButtonHTMLAttributes<HTMLButtonElement>,\n VariantProps<typeof buttonVariants> {\n asChild?: boolean\n}\n\nconst Button = React.forwardRef<HTMLButtonElement, ButtonProps>(\n ({ className, variant, size, asChild, ...props }, ref) => {\n const Comp = asChild ? Slot : \"button\"\n return (\n <Comp\n className={cn(buttonVariants({ variant, size }), className)}\n ref={ref}\n {...props}\n />\n )\n }\n)\nButton.displayName = \"Button\"\n\nexport { Button, buttonVariants }\n"
144
+ "content": "import * as React from \"react\"\nimport { Slot } from \"@radix-ui/react-slot\"\nimport { cva, type VariantProps } from \"class-variance-authority\"\nimport { cn } from \"../../../lib/utils\"\nimport styles from \"./button.module.css\"\nimport {\n Tooltip,\n TooltipContent,\n TooltipTrigger,\n} from \"../tooltip/tooltip\"\n\nconst buttonVariants = cva(styles.base, {\n variants: {\n variant: {\n default: styles.variantDefault,\n secondary: styles.variantSecondary,\n outline: styles.variantOutline,\n ghost: styles.variantGhost,\n destructive: styles.variantDestructive,\n },\n size: {\n sm: styles.sizeSm,\n md: styles.sizeMd,\n lg: styles.sizeLg,\n },\n },\n defaultVariants: {\n variant: \"default\",\n size: \"md\",\n },\n})\n\nexport interface ButtonProps\n extends React.ButtonHTMLAttributes<HTMLButtonElement>,\n VariantProps<typeof buttonVariants> {\n asChild?: boolean\n /**\n * When true, the button renders in an inert gated state — visually dimmed,\n * cursor not-allowed, and click handlers suppressed. Uses `aria-disabled`\n * instead of the native `disabled` attribute so the button remains\n * keyboard-focusable (required for the tooltip to be accessible).\n *\n * Note: a `<TooltipProvider>` ancestor is required when `gatedReason` is set.\n */\n gated?: boolean\n /**\n * Explanation surfaced in an anchored tooltip when the button is gated.\n * Only rendered when `gated` is also true.\n * Example: \"You can't delete this — you're not an owner\"\n */\n gatedReason?: string\n}\n\nconst Button = React.forwardRef<HTMLButtonElement, ButtonProps>(\n ({ className, variant, size, asChild, gated, gatedReason, onClick, ...props }, ref) => {\n const Comp = asChild ? Slot : \"button\"\n\n const handleClick = React.useCallback(\n (e: React.MouseEvent<HTMLButtonElement>) => {\n if (gated) return\n onClick?.(e)\n },\n [gated, onClick]\n )\n\n const button = (\n <Comp\n className={cn(buttonVariants({ variant, size }), className)}\n ref={ref}\n aria-disabled={gated ? true : undefined}\n data-gated={gated ? \"true\" : undefined}\n data-gated-reason={gated && gatedReason ? gatedReason : undefined}\n onClick={handleClick}\n {...props}\n />\n )\n\n if (gated && gatedReason) {\n return (\n <Tooltip>\n <TooltipTrigger asChild>{button}</TooltipTrigger>\n <TooltipContent>{gatedReason}</TooltipContent>\n </Tooltip>\n )\n }\n\n return button\n }\n)\nButton.displayName = \"Button\"\n\nexport { Button, buttonVariants }\n"
145
145
  },
146
146
  {
147
147
  "path": "components/ui/button/button.module.css",
148
148
  "type": "registry:ui",
149
- "content": "/* Button base styles */\n.base {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n gap: var(--spacing-2, 0.5rem);\n white-space: nowrap;\n border-radius: var(--radius-md, 0.375rem);\n font-size: var(--font-size-sm, 0.875rem);\n font-weight: var(--font-weight-medium, 500);\n line-height: 1;\n cursor: pointer;\n border: 1px solid transparent;\n transition: background-color var(--motion-duration-150, 150ms) var(--motion-easing-default, ease-in-out), color var(--motion-duration-150, 150ms) var(--motion-easing-default, ease-in-out), border-color var(--motion-duration-150, 150ms) var(--motion-easing-default, ease-in-out), opacity var(--motion-duration-150, 150ms) var(--motion-easing-default, ease-in-out), transform var(--motion-duration-150, 150ms) var(--motion-easing-default, ease-in-out);\n text-decoration: none;\n outline: none;\n}\n\n.base:focus-visible {\n outline: var(--focus-ring-width, 2px) solid var(--border-focus, currentColor);\n outline-offset: var(--focus-ring-offset, 2px);\n}\n\n.base:active:not(:disabled) {\n transform: translateY(1px);\n transition: none;\n}\n\n.base:disabled {\n pointer-events: none;\n opacity: 0.5;\n}\n\n/* Variants */\n.variantDefault {\n background-color: var(--interactive-primary-bg, #111827);\n color: var(--interactive-primary-text, #f9fafb);\n}\n\n.variantSecondary {\n background-color: var(--interactive-secondary-bg, #f3f4f6);\n color: var(--interactive-secondary-text, #111827);\n}\n\n.variantOutline {\n background-color: transparent;\n color: var(--text-primary, #111827);\n border-color: var(--border-strong, #e5e7eb);\n}\n\n.variantGhost {\n background-color: var(--interactive-ghost-bg, transparent);\n color: var(--text-primary, #111827);\n}\n\n.variantDestructive {\n background-color: var(--interactive-destructive-bg, #ef4444);\n color: var(--interactive-destructive-text, #fef2f2);\n}\n\n@media (hover: hover) {\n .variantDefault:hover {\n background-color: var(--interactive-primary-bg-hover, #1f2937);\n }\n\n .variantSecondary:hover {\n background-color: var(--interactive-secondary-bg-hover, #e5e7eb);\n }\n\n .variantOutline:hover {\n background-color: var(--surface-muted, #f3f4f6);\n }\n\n .variantGhost:hover {\n background-color: var(--interactive-ghost-bg-hover, var(--surface-muted, #f3f4f6));\n }\n\n .variantDestructive:hover {\n background-color: var(--interactive-destructive-bg-hover, #dc2626);\n }\n}\n\n/* Sizes */\n.sizeSm {\n height: 2rem;\n padding: 0 var(--spacing-3, 0.75rem);\n font-size: var(--font-size-xs, 0.75rem);\n}\n\n.sizeMd {\n height: 2.5rem;\n padding: 0 var(--spacing-4, 1rem);\n}\n\n.sizeLg {\n height: 3rem;\n padding: 0 var(--spacing-6, 1.5rem);\n font-size: var(--font-size-base, 1rem);\n}\n"
149
+ "content": "/* Button base styles */\n.base {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n gap: var(--spacing-2, 0.5rem);\n white-space: nowrap;\n border-radius: var(--radius-md, 0.375rem);\n font-size: var(--font-size-sm, 0.875rem);\n font-weight: var(--font-weight-medium, 500);\n line-height: 1;\n cursor: pointer;\n border: 1px solid transparent;\n transition: background-color var(--motion-duration-150, 150ms) var(--motion-easing-default, ease-in-out), color var(--motion-duration-150, 150ms) var(--motion-easing-default, ease-in-out), border-color var(--motion-duration-150, 150ms) var(--motion-easing-default, ease-in-out), opacity var(--motion-duration-150, 150ms) var(--motion-easing-default, ease-in-out), transform var(--motion-duration-150, 150ms) var(--motion-easing-default, ease-in-out);\n text-decoration: none;\n outline: none;\n}\n\n.base:focus-visible {\n outline: var(--focus-ring-width, 2px) solid var(--border-focus, currentColor);\n outline-offset: var(--focus-ring-offset, 2px);\n}\n\n.base:active:not(:disabled) {\n transform: translateY(1px);\n transition: none;\n}\n\n.base:disabled {\n pointer-events: none;\n opacity: 0.5;\n}\n\n/* Variants */\n.variantDefault {\n background-color: var(--interactive-primary-bg, var(--primary, #111827));\n color: var(--interactive-primary-text, #f9fafb);\n}\n\n.variantSecondary {\n background-color: var(--interactive-secondary-bg, #f3f4f6);\n color: var(--interactive-secondary-text, #111827);\n}\n\n.variantOutline {\n background-color: transparent;\n color: var(--text-primary, #111827);\n border-color: var(--border-strong, #e5e7eb);\n}\n\n.variantGhost {\n background-color: var(--interactive-ghost-bg, transparent);\n color: var(--text-primary, #111827);\n}\n\n.variantDestructive {\n background-color: var(--interactive-destructive-bg, #ef4444);\n color: var(--interactive-destructive-text, #fef2f2);\n}\n\n@media (hover: hover) {\n .variantDefault:hover {\n background-color: var(--interactive-primary-bg-hover, #1f2937);\n }\n\n .variantSecondary:hover {\n background-color: var(--interactive-secondary-bg-hover, #e5e7eb);\n }\n\n .variantOutline:hover {\n background-color: var(--surface-muted, #f3f4f6);\n }\n\n .variantGhost:hover {\n background-color: var(--interactive-ghost-bg-hover, var(--surface-muted, #f3f4f6));\n }\n\n .variantDestructive:hover {\n background-color: var(--interactive-destructive-bg-hover, #dc2626);\n }\n}\n\n/* Gated state — orthogonal to variant, works with all variants */\n.base[data-gated=\"true\"] {\n opacity: var(--opacity-50, 0.5);\n cursor: not-allowed;\n border-color: var(--border-default, #e5e7eb);\n}\n\n/* Suppress active transform when gated */\n.base[data-gated=\"true\"]:active {\n transform: none;\n transition: opacity var(--motion-duration-150, 150ms) var(--motion-easing-default, ease-in-out);\n}\n\n/* Sizes */\n.sizeSm {\n height: 2rem;\n padding: 0 var(--spacing-3, 0.75rem);\n font-size: var(--font-size-xs, 0.75rem);\n}\n\n.sizeMd {\n height: 2.5rem;\n padding: 0 var(--spacing-4, 1rem);\n}\n\n.sizeLg {\n height: 3rem;\n padding: 0 var(--spacing-6, 1.5rem);\n font-size: var(--font-size-base, 1rem);\n}\n"
150
150
  }
151
151
  ]
152
152
  },
@@ -172,7 +172,7 @@
172
172
  {
173
173
  "path": "components/ui/input/input.module.css",
174
174
  "type": "registry:ui",
175
- "content": "/* Input base styles */\n.base {\n width: 100%;\n min-width: 0;\n border: 1px solid var(--border-default, #e5e7eb);\n background-color: var(--surface-interactive-default, #f9fafb);\n line-height: 1.5;\n color: var(--text-primary, #111827);\n transition: border-color var(--motion-duration-150, 150ms) var(--motion-easing-default, ease-in-out), box-shadow var(--motion-duration-150, 150ms) var(--motion-easing-default, ease-in-out);\n outline: none;\n}\n\n.base::placeholder {\n color: var(--text-secondary, #9ca3af);\n}\n\n@media (hover: hover) {\n .base:hover:not(:focus-visible):not(:disabled):not([aria-invalid=\"true\"]) {\n border-color: var(--border-strong, #d1d5db);\n }\n}\n\n.base:focus-visible {\n border-color: var(--border-focus, #111827);\n box-shadow: 0 0 0 var(--focus-ring-width, 2px) color-mix(in srgb, var(--border-focus, #111827) 15%, transparent);\n}\n\n.base:disabled {\n pointer-events: none;\n cursor: not-allowed;\n opacity: 0.5;\n}\n\n.base[aria-invalid=\"true\"] {\n border-color: var(--border-error, #ef4444);\n box-shadow: 0 0 0 var(--focus-ring-width, 2px) color-mix(in srgb, var(--border-error, #ef4444) 15%, transparent);\n}\n\n/* File input styles */\n.base[type=\"file\"] {\n font-size: var(--font-size-sm, 0.875rem);\n}\n\n/* Leading-icon wrapper\n *\n * When the consumer passes a leadingIcon node, Input wraps its <input> in a\n * <span> and positions the icon absolutely inside it. The <input> itself\n * picks up .hasLeadingIcon, which adds enough left padding to clear the\n * icon (sized in em so it scales with the field's font-size). */\n.leadingIconWrapper {\n position: relative;\n display: flex;\n align-items: center;\n width: 100%;\n min-width: 0;\n}\n\n.leadingIcon {\n position: absolute;\n left: var(--spacing-3, 0.75rem);\n top: 50%;\n transform: translateY(-50%);\n display: inline-flex;\n align-items: center;\n justify-content: center;\n color: var(--text-secondary, #9ca3af);\n pointer-events: none;\n font-size: 1.125em;\n line-height: 1;\n}\n\n/* Size variants */\n.sizeSm {\n height: 2.25rem;\n padding: var(--spacing-1, 0.25rem) var(--spacing-3, 0.75rem);\n font-size: var(--font-size-sm, 0.875rem);\n border-radius: var(--radius-sm, 0.25rem);\n}\n\n.sizeMd {\n height: auto;\n padding: var(--spacing-3_5, 0.875rem) var(--spacing-4, 1rem);\n font-size: var(--font-size-sm, 0.875rem);\n border-radius: var(--radius-sm, 0.5rem);\n}\n\n.sizeLg {\n height: auto;\n padding: var(--spacing-4_5, 1.125rem) var(--spacing-5, 1.25rem);\n font-size: var(--font-size-base, 1rem);\n border-radius: var(--radius-sm, 0.5rem);\n}\n\n/* Leading-icon left-padding override.\n *\n * Declared AFTER the size variants so the padding-left value wins the\n * cascade against the shorthand `padding` each size sets. Double-class\n * selector bumps specificity above the size classes for good measure. */\n.sizeSm.hasLeadingIcon {\n padding-left: calc(var(--spacing-3, 0.75rem) * 2 + 1.125em);\n}\n\n.sizeMd.hasLeadingIcon {\n padding-left: calc(var(--spacing-4, 1rem) + var(--spacing-3, 0.75rem) + 1.125em);\n}\n\n.sizeLg.hasLeadingIcon {\n padding-left: calc(var(--spacing-5, 1.25rem) + var(--spacing-3, 0.75rem) + 1.125em);\n}\n"
175
+ "content": "/* Input base styles */\n.base {\n width: 100%;\n min-width: 0;\n border: 1px solid var(--input-border, var(--border-default, #e5e7eb));\n background-color: var(--input-bg, var(--surface-interactive-default, #f9fafb));\n line-height: 1.5;\n color: var(--text-primary, #111827);\n transition: border-color var(--motion-duration-150, 150ms) var(--motion-easing-default, ease-in-out), box-shadow var(--motion-duration-150, 150ms) var(--motion-easing-default, ease-in-out);\n outline: none;\n}\n\n.base::placeholder {\n color: var(--text-secondary, #9ca3af);\n}\n\n@media (hover: hover) {\n .base:hover:not(:focus-visible):not(:disabled):not([aria-invalid=\"true\"]) {\n border-color: var(--border-strong, #d1d5db);\n }\n}\n\n.base:focus-visible {\n border-color: var(--border-focus, #111827);\n box-shadow: 0 0 0 var(--focus-ring-width, 2px) color-mix(in srgb, var(--border-focus, #111827) 15%, transparent);\n}\n\n.base:disabled {\n pointer-events: none;\n cursor: not-allowed;\n opacity: 0.5;\n}\n\n.base[aria-invalid=\"true\"] {\n border-color: transparent;\n background-color: var(--input-bg-invalid, var(--surface-error-subtle, color-mix(in srgb, var(--border-error, #ef4444) 6%, var(--input-bg, #f9fafb))));\n box-shadow: inset 0 0 0 1.5px var(--border-error, #ef4444);\n}\n\n.base[aria-invalid=\"true\"]:focus-visible {\n border-color: transparent;\n outline-offset: var(--focus-ring-offset, 2px);\n box-shadow: inset 0 0 0 1.5px var(--border-error, #ef4444),\n 0 0 0 var(--focus-ring-width, 2px) color-mix(in srgb, var(--border-error, #ef4444) 30%, transparent);\n}\n\n/* File input styles */\n.base[type=\"file\"] {\n font-size: var(--font-size-sm, 0.875rem);\n}\n\n/* Leading-icon wrapper\n *\n * When the consumer passes a leadingIcon node, Input wraps its <input> in a\n * <span> and positions the icon absolutely inside it. The <input> itself\n * picks up .hasLeadingIcon, which adds enough left padding to clear the\n * icon (sized in em so it scales with the field's font-size). */\n.leadingIconWrapper {\n position: relative;\n display: flex;\n align-items: center;\n width: 100%;\n min-width: 0;\n}\n\n.leadingIcon {\n position: absolute;\n left: var(--spacing-3, 0.75rem);\n top: 50%;\n transform: translateY(-50%);\n display: inline-flex;\n align-items: center;\n justify-content: center;\n color: var(--text-secondary, #9ca3af);\n pointer-events: none;\n font-size: 1.125em;\n line-height: 1;\n}\n\n/* Size variants */\n.sizeSm {\n height: 2.25rem;\n padding: var(--spacing-1, 0.25rem) var(--spacing-3, 0.75rem);\n font-size: var(--font-size-sm, 0.875rem);\n border-radius: var(--radius-sm, 0.25rem);\n}\n\n.sizeMd {\n height: auto;\n padding: var(--spacing-3_5, 0.875rem) var(--spacing-4, 1rem);\n font-size: var(--font-size-sm, 0.875rem);\n border-radius: var(--radius-sm, 0.5rem);\n}\n\n.sizeLg {\n height: auto;\n padding: var(--spacing-4_5, 1.125rem) var(--spacing-5, 1.25rem);\n font-size: var(--font-size-base, 1rem);\n border-radius: var(--radius-sm, 0.5rem);\n}\n\n/* Leading-icon left-padding override.\n *\n * Declared AFTER the size variants so the padding-left value wins the\n * cascade against the shorthand `padding` each size sets. Double-class\n * selector bumps specificity above the size classes for good measure. */\n.sizeSm.hasLeadingIcon {\n padding-left: calc(var(--spacing-3, 0.75rem) * 2 + 1.125em);\n}\n\n.sizeMd.hasLeadingIcon {\n padding-left: calc(var(--spacing-4, 1rem) + var(--spacing-3, 0.75rem) + 1.125em);\n}\n\n.sizeLg.hasLeadingIcon {\n padding-left: calc(var(--spacing-5, 1.25rem) + var(--spacing-3, 0.75rem) + 1.125em);\n}\n"
176
176
  }
177
177
  ]
178
178
  },
@@ -223,7 +223,7 @@
223
223
  {
224
224
  "path": "components/ui/textarea/textarea.module.css",
225
225
  "type": "registry:ui",
226
- "content": "/* Textarea base styles */\n.base {\n display: flex;\n width: 100%;\n resize: none;\n border: 1px solid var(--border-default, #e5e7eb);\n background-color: var(--surface-interactive-default, #f9fafb);\n line-height: 1.5;\n color: var(--text-primary, #111827);\n transition: border-color var(--motion-duration-150, 150ms) var(--motion-easing-default, ease-in-out), box-shadow var(--motion-duration-150, 150ms) var(--motion-easing-default, ease-in-out);\n outline: none;\n font-family: inherit;\n}\n\n.base::placeholder {\n color: var(--text-secondary, #9ca3af);\n}\n\n@media (hover: hover) {\n .base:hover:not(:focus-visible):not(:disabled):not([aria-invalid=\"true\"]) {\n border-color: var(--border-strong, #d1d5db);\n }\n}\n\n.base:focus-visible {\n border-color: var(--border-focus, #111827);\n box-shadow: 0 0 0 var(--focus-ring-width, 2px) color-mix(in srgb, var(--border-focus, #111827) 15%, transparent);\n}\n\n.base:disabled {\n cursor: not-allowed;\n opacity: 0.5;\n}\n\n.base[aria-invalid=\"true\"] {\n border-color: var(--border-error, #ef4444);\n box-shadow: 0 0 0 var(--focus-ring-width, 2px) color-mix(in srgb, var(--border-error, #ef4444) 15%, transparent);\n}\n\n/* Size variants */\n.sizeSm {\n min-height: 4rem;\n padding: var(--spacing-3, 0.75rem);\n font-size: var(--font-size-sm, 0.875rem);\n border-radius: var(--radius-sm, 0.25rem);\n}\n\n.sizeMd {\n min-height: 6.25rem;\n padding: var(--spacing-3_5, 0.875rem) var(--spacing-4, 1rem);\n font-size: var(--font-size-sm, 0.875rem);\n border-radius: var(--radius-sm, 0.5rem);\n}\n\n.sizeLg {\n min-height: 8rem;\n padding: var(--spacing-4_5, 1.125rem) var(--spacing-5, 1.25rem);\n font-size: var(--font-size-base, 1rem);\n border-radius: var(--radius-sm, 0.5rem);\n}\n"
226
+ "content": "/* Textarea base styles */\n.base {\n display: flex;\n width: 100%;\n resize: none;\n border: 1px solid var(--textarea-border, var(--border-default, #e5e7eb));\n background-color: var(--textarea-bg, var(--surface-interactive-default, #f9fafb));\n line-height: 1.5;\n color: var(--text-primary, #111827);\n transition: border-color var(--motion-duration-150, 150ms) var(--motion-easing-default, ease-in-out), box-shadow var(--motion-duration-150, 150ms) var(--motion-easing-default, ease-in-out);\n outline: none;\n font-family: inherit;\n}\n\n.base::placeholder {\n color: var(--text-secondary, #9ca3af);\n}\n\n@media (hover: hover) {\n .base:hover:not(:focus-visible):not(:disabled):not([aria-invalid=\"true\"]) {\n border-color: var(--border-strong, #d1d5db);\n }\n}\n\n.base:focus-visible {\n border-color: var(--border-focus, #111827);\n box-shadow: 0 0 0 var(--focus-ring-width, 2px) color-mix(in srgb, var(--border-focus, #111827) 15%, transparent);\n}\n\n.base:disabled {\n cursor: not-allowed;\n opacity: 0.5;\n}\n\n.base[aria-invalid=\"true\"] {\n border-color: var(--border-error, #ef4444);\n box-shadow: 0 0 0 var(--focus-ring-width, 2px) color-mix(in srgb, var(--border-error, #ef4444) 15%, transparent);\n}\n\n/* Size variants */\n.sizeSm {\n min-height: 4rem;\n padding: var(--spacing-3, 0.75rem);\n font-size: var(--font-size-sm, 0.875rem);\n border-radius: var(--radius-sm, 0.25rem);\n}\n\n.sizeMd {\n min-height: 6.25rem;\n padding: var(--spacing-3_5, 0.875rem) var(--spacing-4, 1rem);\n font-size: var(--font-size-sm, 0.875rem);\n border-radius: var(--radius-sm, 0.5rem);\n}\n\n.sizeLg {\n min-height: 8rem;\n padding: var(--spacing-4_5, 1.125rem) var(--spacing-5, 1.25rem);\n font-size: var(--font-size-base, 1rem);\n border-radius: var(--radius-sm, 0.5rem);\n}\n"
227
227
  }
228
228
  ]
229
229
  },
@@ -249,7 +249,7 @@
249
249
  {
250
250
  "path": "components/ui/checkbox/checkbox.module.css",
251
251
  "type": "registry:ui",
252
- "content": "/* Checkbox root styles */\n.root {\n position: relative;\n display: flex;\n width: 1rem;\n height: 1rem;\n flex-shrink: 0;\n align-items: center;\n justify-content: center;\n border-radius: var(--radius-sm, 0.25rem);\n border: 1px solid var(--checkbox-border, var(--border-default, #e5e7eb));\n background-color: var(--checkbox-bg, transparent);\n transition: border-color var(--motion-duration-150, 150ms) var(--motion-easing-default, ease-in-out), background-color var(--motion-duration-150, 150ms) var(--motion-easing-default, ease-in-out), box-shadow var(--motion-duration-150, 150ms) var(--motion-easing-default, ease-in-out);\n outline: none;\n cursor: pointer;\n}\n\n@media (hover: hover) {\n .root:hover:not(:focus-visible):not(:disabled):not([aria-invalid=\"true\"]) {\n border-color: var(--checkbox-border-hover, var(--border-strong, #d1d5db));\n background-color: var(--checkbox-bg-hover, transparent);\n }\n}\n\n.root:focus-visible {\n border-color: var(--border-focus, #111827);\n box-shadow: 0 0 0 var(--focus-ring-width, 2px) color-mix(in srgb, var(--border-focus, #111827) 15%, transparent);\n}\n\n.root:disabled {\n cursor: not-allowed;\n opacity: 0.5;\n}\n\n.root[aria-invalid=\"true\"] {\n border-color: var(--border-error, #ef4444);\n box-shadow: 0 0 0 var(--focus-ring-width, 2px) color-mix(in srgb, var(--border-error, #ef4444) 15%, transparent);\n}\n\n.root[data-state=\"checked\"] {\n border-color: var(--checkbox-border-checked, var(--interactive-primary-bg, #111827));\n background-color: var(--checkbox-bg-checked, var(--interactive-primary-bg, #111827));\n color: var(--interactive-primary-text, #f9fafb);\n}\n\n.root[data-state=\"indeterminate\"] {\n border-color: var(--checkbox-border-checked, var(--interactive-primary-bg, #111827));\n background-color: var(--checkbox-bg-checked, var(--interactive-primary-bg, #111827));\n color: var(--interactive-primary-text, #f9fafb);\n}\n\n/* Indicator */\n.indicator {\n display: grid;\n place-content: center;\n color: currentColor;\n transition: none;\n}\n\n.icon {\n width: 0.875rem;\n height: 0.875rem;\n}\n"
252
+ "content": "/* Checkbox root styles */\n.root {\n position: relative;\n display: flex;\n width: 1rem;\n height: 1rem;\n flex-shrink: 0;\n align-items: center;\n justify-content: center;\n border-radius: var(--radius-sm, 0.25rem);\n border: 1px solid var(--checkbox-border, var(--border-default, #e5e7eb));\n background-color: var(--checkbox-bg, transparent);\n transition: border-color var(--motion-duration-150, 150ms) var(--motion-easing-default, ease-in-out), background-color var(--motion-duration-150, 150ms) var(--motion-easing-default, ease-in-out), box-shadow var(--motion-duration-150, 150ms) var(--motion-easing-default, ease-in-out);\n outline: none;\n cursor: pointer;\n}\n\n@media (hover: hover) {\n .root:hover:not(:focus-visible):not(:disabled):not([aria-invalid=\"true\"]) {\n border-color: var(--checkbox-border-hover, var(--border-strong, #d1d5db));\n background-color: var(--checkbox-bg-hover, transparent);\n }\n}\n\n.root:focus-visible {\n border-color: var(--border-focus, #111827);\n box-shadow: 0 0 0 var(--focus-ring-width, 2px) color-mix(in srgb, var(--border-focus, #111827) 15%, transparent);\n}\n\n.root:disabled {\n cursor: not-allowed;\n opacity: 0.5;\n}\n\n.root[aria-invalid=\"true\"] {\n border-color: var(--border-error, #ef4444);\n box-shadow: 0 0 0 var(--focus-ring-width, 2px) color-mix(in srgb, var(--border-error, #ef4444) 15%, transparent);\n}\n\n.root[data-state=\"checked\"] {\n border-color: var(--checkbox-border-checked, var(--interactive-primary-bg, var(--primary, #111827)));\n background-color: var(--checkbox-bg-checked, var(--interactive-primary-bg, var(--primary, #111827)));\n color: var(--interactive-primary-text, #f9fafb);\n}\n\n.root[data-state=\"indeterminate\"] {\n border-color: var(--checkbox-border-checked, var(--interactive-primary-bg, var(--primary, #111827)));\n background-color: var(--checkbox-bg-checked, var(--interactive-primary-bg, var(--primary, #111827)));\n color: var(--interactive-primary-text, #f9fafb);\n}\n\n/* Indicator */\n.indicator {\n display: grid;\n place-content: center;\n color: currentColor;\n transition: none;\n}\n\n.icon {\n width: 0.875rem;\n height: 0.875rem;\n}\n"
253
253
  }
254
254
  ]
255
255
  },
@@ -275,7 +275,7 @@
275
275
  {
276
276
  "path": "components/ui/select/select.module.css",
277
277
  "type": "registry:ui",
278
- "content": "/* Select Trigger */\n.trigger {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: calc(var(--spacing-1, 0.25rem) * 1.5);\n width: fit-content;\n border-radius: var(--radius-md, 0.375rem);\n border: 1px solid var(--border-default, #e5e7eb);\n background-color: var(--surface-interactive-default, #f9fafb);\n padding: var(--spacing-2, 0.5rem) var(--spacing-3, 0.75rem);\n font-size: var(--font-size-sm, 0.875rem);\n /* Match Input's line-height so the trigger's height tracks the text field at\n the same size. Without this the trigger inherited line-height 2.0, rendering\n ~7px taller than a same-size Input. */\n line-height: 1.5;\n white-space: nowrap;\n color: var(--text-primary, #111827);\n transition: border-color var(--motion-duration-150, 150ms) var(--motion-easing-default, ease-in-out), box-shadow var(--motion-duration-150, 150ms) var(--motion-easing-default, ease-in-out);\n outline: none;\n cursor: pointer;\n}\n\n@media (hover: hover) {\n .trigger:hover:not(:focus-visible):not(:disabled):not([aria-invalid=\"true\"]) {\n border-color: var(--border-strong, #d1d5db);\n }\n}\n\n.trigger:focus-visible {\n border-color: var(--border-focus, #111827);\n box-shadow: 0 0 0 var(--focus-ring-width, 2px) color-mix(in srgb, var(--border-focus, #111827) 15%, transparent);\n}\n\n.trigger:disabled {\n cursor: not-allowed;\n opacity: 0.5;\n}\n\n.trigger[aria-invalid=\"true\"] {\n border-color: var(--border-error, #ef4444);\n box-shadow: 0 0 0 var(--focus-ring-width, 2px) color-mix(in srgb, var(--border-error, #ef4444) 15%, transparent);\n}\n\n.trigger[data-placeholder] {\n color: var(--text-secondary, #9ca3af);\n}\n\n.triggerSizeSm {\n height: 2.25rem;\n border-radius: var(--radius-sm, 0.25rem);\n}\n\n.triggerSizeMd {\n height: auto;\n padding: var(--spacing-3_5, 0.875rem) var(--spacing-4, 1rem);\n font-size: var(--font-size-sm, 0.875rem);\n border-radius: var(--radius-sm, 0.5rem);\n}\n\n.triggerSizeLg {\n height: auto;\n padding: var(--spacing-4_5, 1.125rem) var(--spacing-5, 1.25rem);\n font-size: var(--font-size-base, 1rem);\n border-radius: var(--radius-sm, 0.5rem);\n}\n\n.triggerIcon {\n pointer-events: none;\n width: 1rem;\n height: 1rem;\n flex-shrink: 0;\n color: var(--text-secondary, #9ca3af);\n}\n\n/* Select Content */\n.content {\n position: relative;\n z-index: 50;\n max-height: var(--radix-select-content-available-height, 300px);\n min-width: 9rem;\n overflow: hidden;\n border-radius: var(--radius-lg, 0.5rem);\n background-color: var(--surface-popover, var(--surface-card, #ffffff));\n color: var(--text-primary, #111827);\n box-shadow: var(--shadow-lg);\n}\n\n/* Select Viewport */\n.viewport {\n padding: var(--spacing-1, 0.25rem);\n}\n\n.viewportPopper {\n height: var(--radix-select-trigger-height);\n width: 100%;\n min-width: var(--radix-select-trigger-width);\n}\n\n/* Select Label */\n.label {\n padding: var(--spacing-2, 0.5rem) var(--spacing-3, 0.75rem);\n font-size: var(--font-size-xs, 0.75rem);\n color: var(--text-secondary, #9ca3af);\n}\n\n/* Select Item */\n.item {\n position: relative;\n display: flex;\n width: 100%;\n cursor: default;\n align-items: center;\n gap: calc(var(--spacing-2, 0.5rem) + var(--spacing-1, 0.25rem) / 2);\n border-radius: var(--radius-sm, 0.25rem);\n padding: var(--spacing-2, 0.5rem) var(--spacing-8, 2rem) var(--spacing-2, 0.5rem) var(--spacing-3, 0.75rem);\n font-size: var(--font-size-sm, 0.875rem);\n outline: none;\n user-select: none;\n}\n\n.item:focus,\n.item[data-highlighted] {\n background-color: var(--surface-interactive-hover, #f3f4f6);\n color: var(--text-primary, #111827);\n}\n\n.item[data-disabled] {\n pointer-events: none;\n opacity: 0.5;\n}\n\n.itemIndicatorWrapper {\n position: absolute;\n right: 0.5rem;\n display: flex;\n width: 1rem;\n height: 1rem;\n align-items: center;\n justify-content: center;\n}\n\n.itemIndicatorIcon {\n width: 0.875rem;\n height: 0.875rem;\n pointer-events: none;\n}\n\n/* Select Separator */\n.separator {\n pointer-events: none;\n margin: var(--spacing-1, 0.25rem) calc(-1 * var(--spacing-1, 0.25rem));\n height: 1px;\n background-color: var(--border-default, #e5e7eb);\n}\n\n/* Scroll Buttons */\n.scrollButton {\n display: flex;\n cursor: default;\n align-items: center;\n justify-content: center;\n padding: var(--spacing-1, 0.25rem);\n background-color: var(--surface-popover, var(--surface-card, #ffffff));\n}\n\n.scrollButtonIcon {\n width: 1rem;\n height: 1rem;\n}\n"
278
+ "content": "/* Select Trigger */\n.trigger {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: calc(var(--spacing-1, 0.25rem) * 1.5);\n width: fit-content;\n border-radius: var(--radius-md, 0.375rem);\n border: 1px solid var(--select-border, var(--border-default, #e5e7eb));\n background-color: var(--select-bg, var(--surface-interactive-default, #f9fafb));\n padding: var(--spacing-2, 0.5rem) var(--spacing-3, 0.75rem);\n font-size: var(--font-size-sm, 0.875rem);\n /* Match Input's line-height so the trigger's height tracks the text field at\n the same size. Without this the trigger inherited line-height 2.0, rendering\n ~7px taller than a same-size Input. */\n line-height: 1.5;\n white-space: nowrap;\n color: var(--text-primary, #111827);\n transition: border-color var(--motion-duration-150, 150ms) var(--motion-easing-default, ease-in-out), box-shadow var(--motion-duration-150, 150ms) var(--motion-easing-default, ease-in-out);\n outline: none;\n cursor: pointer;\n}\n\n@media (hover: hover) {\n .trigger:hover:not(:focus-visible):not(:disabled):not([aria-invalid=\"true\"]) {\n border-color: var(--border-strong, #d1d5db);\n }\n}\n\n.trigger:focus-visible {\n border-color: var(--border-focus, #111827);\n box-shadow: 0 0 0 var(--focus-ring-width, 2px) color-mix(in srgb, var(--border-focus, #111827) 15%, transparent);\n}\n\n.trigger:disabled {\n cursor: not-allowed;\n opacity: 0.5;\n}\n\n.trigger[aria-invalid=\"true\"] {\n border-color: var(--border-error, #ef4444);\n box-shadow: 0 0 0 var(--focus-ring-width, 2px) color-mix(in srgb, var(--border-error, #ef4444) 15%, transparent);\n}\n\n.trigger[data-placeholder] {\n color: var(--text-secondary, #9ca3af);\n}\n\n.triggerSizeSm {\n height: 2.25rem;\n border-radius: var(--radius-sm, 0.25rem);\n}\n\n.triggerSizeMd {\n height: auto;\n padding: var(--spacing-3_5, 0.875rem) var(--spacing-4, 1rem);\n font-size: var(--font-size-sm, 0.875rem);\n border-radius: var(--radius-sm, 0.5rem);\n}\n\n.triggerSizeLg {\n height: auto;\n padding: var(--spacing-4_5, 1.125rem) var(--spacing-5, 1.25rem);\n font-size: var(--font-size-base, 1rem);\n border-radius: var(--radius-sm, 0.5rem);\n}\n\n.triggerIcon {\n pointer-events: none;\n width: 1rem;\n height: 1rem;\n flex-shrink: 0;\n color: var(--text-secondary, #9ca3af);\n}\n\n/* Select Content */\n.content {\n position: relative;\n z-index: 50;\n max-height: var(--radix-select-content-available-height, 300px);\n min-width: 9rem;\n overflow: hidden;\n border-radius: var(--radius-lg, 0.5rem);\n background-color: var(--field-menu-bg, var(--surface-popover, var(--surface-card, #ffffff)));\n color: var(--text-primary, #111827);\n box-shadow: var(--shadow-lg);\n}\n\n/* Select Viewport */\n.viewport {\n padding: var(--spacing-1, 0.25rem);\n}\n\n.viewportPopper {\n height: var(--radix-select-trigger-height);\n width: 100%;\n min-width: var(--radix-select-trigger-width);\n}\n\n/* Select Label */\n.label {\n padding: var(--spacing-2, 0.5rem) var(--spacing-3, 0.75rem);\n font-size: var(--font-size-xs, 0.75rem);\n color: var(--text-secondary, #9ca3af);\n}\n\n/* Select Item */\n.item {\n position: relative;\n display: flex;\n width: 100%;\n cursor: default;\n align-items: center;\n gap: calc(var(--spacing-2, 0.5rem) + var(--spacing-1, 0.25rem) / 2);\n border-radius: var(--radius-sm, 0.25rem);\n padding: var(--spacing-2, 0.5rem) var(--spacing-8, 2rem) var(--spacing-2, 0.5rem) var(--spacing-3, 0.75rem);\n font-size: var(--font-size-sm, 0.875rem);\n outline: none;\n user-select: none;\n}\n\n.item:focus,\n.item[data-highlighted] {\n background-color: var(--surface-interactive-hover, #f3f4f6);\n color: var(--text-primary, #111827);\n}\n\n.item[data-disabled] {\n pointer-events: none;\n opacity: 0.5;\n}\n\n.itemIndicatorWrapper {\n position: absolute;\n right: 0.5rem;\n display: flex;\n width: 1rem;\n height: 1rem;\n align-items: center;\n justify-content: center;\n}\n\n.itemIndicatorIcon {\n width: 0.875rem;\n height: 0.875rem;\n pointer-events: none;\n}\n\n/* Select Separator */\n.separator {\n pointer-events: none;\n margin: var(--spacing-1, 0.25rem) calc(-1 * var(--spacing-1, 0.25rem));\n height: 1px;\n background-color: var(--border-default, #e5e7eb);\n}\n\n/* Scroll Buttons */\n.scrollButton {\n display: flex;\n cursor: default;\n align-items: center;\n justify-content: center;\n padding: var(--spacing-1, 0.25rem);\n background-color: var(--field-menu-bg, var(--surface-popover, var(--surface-card, #ffffff)));\n}\n\n.scrollButtonIcon {\n width: 1rem;\n height: 1rem;\n}\n"
279
279
  }
280
280
  ]
281
281
  },
@@ -301,7 +301,7 @@
301
301
  {
302
302
  "path": "components/ui/switch/switch.module.css",
303
303
  "type": "registry:ui",
304
- "content": "/* Switch root styles */\n.root {\n position: relative;\n display: inline-flex;\n flex-shrink: 0;\n align-items: center;\n border-radius: 9999px;\n border: 1px solid transparent;\n background-color: var(--border-default, #e5e7eb);\n transition: background-color var(--motion-duration-150, 150ms) var(--motion-easing-default, ease-in-out), border-color var(--motion-duration-150, 150ms) var(--motion-easing-default, ease-in-out), box-shadow var(--motion-duration-150, 150ms) var(--motion-easing-default, ease-in-out);\n outline: none;\n cursor: pointer;\n}\n\n@media (hover: hover) {\n .root:hover:not(:focus-visible):not(:disabled):not([aria-invalid=\"true\"]) {\n background-color: var(--border-strong, #d1d5db);\n }\n}\n\n.root:focus-visible {\n border-color: var(--border-focus, #111827);\n box-shadow: 0 0 0 var(--focus-ring-width, 2px) color-mix(in srgb, var(--border-focus, #111827) 15%, transparent);\n}\n\n.root:disabled {\n cursor: not-allowed;\n opacity: 0.5;\n}\n\n.root[aria-invalid=\"true\"] {\n border-color: var(--border-error, #ef4444);\n box-shadow: 0 0 0 var(--focus-ring-width, 2px) color-mix(in srgb, var(--border-error, #ef4444) 15%, transparent);\n}\n\n.root[data-state=\"checked\"] {\n background-color: var(--interactive-primary-bg, #111827);\n}\n\n/* Size variants */\n.sizeDefault {\n height: 1.15rem;\n width: 2rem;\n}\n\n.sizeSm {\n height: 0.875rem;\n width: 1.5rem;\n}\n\n/* Thumb */\n.thumb {\n display: block;\n border-radius: 9999px;\n background-color: var(--surface-page, #ffffff);\n box-shadow: var(--shadow-sm);\n transition: transform var(--motion-duration-150, 150ms) var(--motion-easing-default, ease-in-out);\n pointer-events: none;\n}\n\n/* Thumb size — derived from parent via CSS nesting */\n.sizeDefault .thumb {\n width: 1rem;\n height: 1rem;\n}\n\n.sizeSm .thumb {\n width: 0.75rem;\n height: 0.75rem;\n}\n\n.root[data-state=\"unchecked\"] .thumb {\n transform: translateX(0);\n}\n\n.sizeDefault[data-state=\"checked\"] .thumb {\n transform: translateX(calc(100% - 2px));\n}\n\n.sizeSm[data-state=\"checked\"] .thumb {\n transform: translateX(calc(100% - 2px));\n}\n"
304
+ "content": "/* Switch root styles */\n.root {\n position: relative;\n display: inline-flex;\n flex-shrink: 0;\n align-items: center;\n border-radius: 9999px;\n border: 1px solid transparent;\n background-color: var(--switch-track-bg, var(--border-default, #e5e7eb));\n transition: background-color var(--motion-duration-150, 150ms) var(--motion-easing-default, ease-in-out), border-color var(--motion-duration-150, 150ms) var(--motion-easing-default, ease-in-out), box-shadow var(--motion-duration-150, 150ms) var(--motion-easing-default, ease-in-out);\n outline: none;\n cursor: pointer;\n}\n\n@media (hover: hover) {\n .root:hover:not(:focus-visible):not(:disabled):not([aria-invalid=\"true\"]) {\n background-color: var(--border-strong, #d1d5db);\n }\n}\n\n.root:focus-visible {\n border-color: var(--border-focus, #111827);\n box-shadow: 0 0 0 var(--focus-ring-width, 2px) color-mix(in srgb, var(--border-focus, #111827) 15%, transparent);\n}\n\n.root:disabled {\n cursor: not-allowed;\n opacity: 0.5;\n}\n\n.root[aria-invalid=\"true\"] {\n border-color: var(--border-error, #ef4444);\n box-shadow: 0 0 0 var(--focus-ring-width, 2px) color-mix(in srgb, var(--border-error, #ef4444) 15%, transparent);\n}\n\n.root[data-state=\"checked\"] {\n background-color: var(--interactive-primary-bg, var(--primary, #111827));\n}\n\n/* Size variants */\n.sizeDefault {\n height: 1.15rem;\n width: 2rem;\n}\n\n.sizeSm {\n height: 0.875rem;\n width: 1.5rem;\n}\n\n/* Thumb */\n.thumb {\n display: block;\n border-radius: 9999px;\n background-color: var(--surface-page, #ffffff);\n box-shadow: var(--shadow-sm);\n transition: transform var(--motion-duration-150, 150ms) var(--motion-easing-default, ease-in-out);\n pointer-events: none;\n}\n\n/* Thumb size — derived from parent via CSS nesting */\n.sizeDefault .thumb {\n width: 1rem;\n height: 1rem;\n}\n\n.sizeSm .thumb {\n width: 0.75rem;\n height: 0.75rem;\n}\n\n.root[data-state=\"unchecked\"] .thumb {\n transform: translateX(0);\n}\n\n.sizeDefault[data-state=\"checked\"] .thumb {\n transform: translateX(calc(100% - 2px));\n}\n\n.sizeSm[data-state=\"checked\"] .thumb {\n transform: translateX(calc(100% - 2px));\n}\n"
305
305
  }
306
306
  ]
307
307
  },
@@ -327,7 +327,7 @@
327
327
  {
328
328
  "path": "components/ui/field/field.module.css",
329
329
  "type": "registry:ui",
330
- "content": "/* Field */\n.field {\n display: flex;\n width: 100%;\n gap: var(--spacing-2, 0.5rem);\n}\n\n.fieldVertical {\n flex-direction: column;\n}\n\n.fieldHorizontal {\n flex-direction: row;\n align-items: center;\n}\n\n/* Field Label */\n.fieldLabel {\n font-size: var(--font-size-sm, 0.875rem);\n font-weight: var(--font-weight-medium, 500);\n color: var(--text-primary, #111827);\n line-height: 1.4;\n}\n\n/* Field Description */\n.fieldDescription {\n font-size: var(--font-size-xs, 0.75rem);\n font-weight: var(--font-weight-normal, 400);\n color: var(--text-secondary, #9ca3af);\n line-height: 1.5;\n margin: 0;\n}\n\n/* Field Error */\n.fieldError {\n font-size: var(--font-size-sm, 0.875rem);\n font-weight: var(--font-weight-normal, 400);\n color: var(--text-error, #ef4444);\n}\n\n.fieldErrorList {\n margin-left: var(--spacing-4, 1rem);\n list-style: disc;\n display: flex;\n flex-direction: column;\n gap: var(--spacing-1, 0.25rem);\n}\n"
330
+ "content": "/* Field */\n.field {\n display: flex;\n width: 100%;\n gap: var(--spacing-2, 0.5rem);\n}\n\n.fieldVertical {\n flex-direction: column;\n}\n\n.fieldHorizontal {\n flex-direction: row;\n align-items: center;\n}\n\n/* Field Label */\n.fieldLabel {\n font-size: var(--font-size-sm, 0.875rem);\n font-weight: var(--font-weight-medium, 500);\n color: var(--text-primary, currentColor);\n line-height: 1.4;\n}\n\n/* Field Description */\n.fieldDescription {\n font-size: var(--font-size-xs, 0.75rem);\n font-weight: var(--font-weight-normal, 400);\n color: var(--text-secondary, currentColor);\n line-height: 1.5;\n margin: 0;\n}\n\n/* Field Error */\n.fieldError {\n font-size: var(--font-size-sm, 0.875rem);\n font-weight: var(--font-weight-normal, 400);\n color: var(--text-error, currentColor);\n}\n\n.fieldErrorList {\n margin-left: var(--spacing-4, 1rem);\n list-style: disc;\n display: flex;\n flex-direction: column;\n gap: var(--spacing-1, 0.25rem);\n}\n"
331
331
  }
332
332
  ]
333
333
  },
@@ -396,12 +396,12 @@
396
396
  {
397
397
  "path": "components/ui/badge/badge.tsx",
398
398
  "type": "registry:ui",
399
- "content": "import * as React from \"react\"\nimport { cva, type VariantProps } from \"class-variance-authority\"\nimport { cn } from \"../../../lib/utils\"\nimport styles from \"./badge.module.css\"\n\nconst badgeVariants = cva(styles.base, {\n variants: {\n variant: {\n default: styles.variantDefault,\n secondary: styles.variantSecondary,\n outline: styles.variantOutline,\n destructive: styles.variantDestructive,\n success: styles.variantSuccess,\n warning: styles.variantWarning,\n info: styles.variantInfo,\n \"filled-destructive\": styles.variantFilledDestructive,\n \"filled-success\": styles.variantFilledSuccess,\n \"filled-warning\": styles.variantFilledWarning,\n \"filled-info\": styles.variantFilledInfo,\n },\n },\n defaultVariants: {\n variant: \"default\",\n },\n})\n\nexport interface BadgeProps\n extends React.HTMLAttributes<HTMLSpanElement>,\n VariantProps<typeof badgeVariants> {}\n\nconst Badge = React.forwardRef<HTMLSpanElement, BadgeProps>(\n ({ className, variant, ...props }, ref) => {\n return (\n <span\n ref={ref}\n data-slot=\"badge\"\n data-variant={variant ?? \"default\"}\n className={cn(badgeVariants({ variant }), className)}\n {...props}\n />\n )\n }\n)\nBadge.displayName = \"Badge\"\n\nexport { Badge, badgeVariants }\n"
399
+ "content": "import * as React from \"react\"\nimport { cva, type VariantProps } from \"class-variance-authority\"\nimport { cn } from \"../../../lib/utils\"\nimport styles from \"./badge.module.css\"\n\nconst badgeVariants = cva(styles.base, {\n variants: {\n variant: {\n default: styles.variantDefault,\n secondary: styles.variantSecondary,\n outline: styles.variantOutline,\n destructive: styles.variantDestructive,\n success: styles.variantSuccess,\n warning: styles.variantWarning,\n info: styles.variantInfo,\n neutral: styles.variantNeutral,\n \"filled-destructive\": styles.variantFilledDestructive,\n \"filled-success\": styles.variantFilledSuccess,\n \"filled-warning\": styles.variantFilledWarning,\n \"filled-info\": styles.variantFilledInfo,\n \"filled-neutral\": styles.variantFilledNeutral,\n },\n size: {\n sm: styles.sizeSm,\n md: styles.sizeMd,\n lg: styles.sizeLg,\n },\n },\n defaultVariants: {\n variant: \"default\",\n size: \"md\",\n },\n})\n\nexport interface BadgeProps\n extends React.HTMLAttributes<HTMLSpanElement>,\n VariantProps<typeof badgeVariants> {}\n\nconst Badge = React.forwardRef<HTMLSpanElement, BadgeProps>(\n ({ className, variant, size, ...props }, ref) => {\n return (\n <span\n ref={ref}\n data-slot=\"badge\"\n data-variant={variant ?? \"default\"}\n data-size={size ?? \"md\"}\n className={cn(badgeVariants({ variant, size }), className)}\n {...props}\n />\n )\n }\n)\nBadge.displayName = \"Badge\"\n\nexport { Badge, badgeVariants }\n"
400
400
  },
401
401
  {
402
402
  "path": "components/ui/badge/badge.module.css",
403
403
  "type": "registry:ui",
404
- "content": "/* Badge base */\n.base {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n height: 1.25rem;\n width: fit-content;\n flex-shrink: 0;\n gap: var(--spacing-1, 0.25rem);\n overflow: hidden;\n border-radius: var(--radius-full, 9999px);\n border: 1px solid transparent;\n padding: calc(var(--spacing-1, 0.25rem) / 2) var(--spacing-2, 0.5rem);\n font-size: var(--font-size-xs, 0.75rem);\n font-weight: var(--font-weight-medium, 500);\n white-space: nowrap;\n transition: background-color var(--motion-duration-150, 150ms) var(--motion-easing-default, ease-in-out), color var(--motion-duration-150, 150ms) var(--motion-easing-default, ease-in-out), border-color var(--motion-duration-150, 150ms) var(--motion-easing-default, ease-in-out);\n}\n\n.base:focus-visible {\n outline: var(--focus-ring-width, 2px) solid var(--border-focus, currentColor);\n outline-offset: var(--focus-ring-offset, 2px);\n}\n\n/* Variants */\n.variantDefault {\n background-color: var(--interactive-primary-bg, currentColor);\n color: var(--interactive-primary-text, var(--text-inverse, #f9fafb));\n border-color: transparent;\n}\n\n.variantSecondary {\n background-color: var(--interactive-secondary-bg, var(--surface-subtle, transparent));\n color: var(--interactive-secondary-text, var(--text-primary, currentColor));\n border-color: transparent;\n}\n\n.variantOutline {\n background-color: transparent;\n color: var(--text-primary, #111827);\n border-color: var(--border-default, #e5e7eb);\n}\n\n.variantDestructive {\n background-color: var(--surface-error-subtle, transparent);\n color: var(--text-error, currentColor);\n border-color: transparent;\n}\n\n.variantSuccess {\n background-color: var(--surface-success-subtle, transparent);\n color: var(--text-success, currentColor);\n border-color: transparent;\n}\n\n.variantWarning {\n background-color: var(--surface-warning-subtle, transparent);\n color: var(--text-warning, currentColor);\n border-color: transparent;\n}\n\n.variantInfo {\n background-color: var(--surface-info-subtle, transparent);\n color: var(--text-info, currentColor);\n border-color: transparent;\n}\n\n/* Filled variants — step 9 bg + contrast text */\n.variantFilledDestructive {\n background-color: var(--surface-error-default, transparent);\n color: var(--text-inverse, currentColor);\n border-color: transparent;\n}\n\n.variantFilledSuccess {\n background-color: var(--surface-success-default, transparent);\n color: var(--text-inverse, currentColor);\n border-color: transparent;\n}\n\n.variantFilledWarning {\n background-color: var(--surface-warning-default, transparent);\n color: var(--text-inverse, currentColor);\n border-color: transparent;\n}\n\n.variantFilledInfo {\n background-color: var(--surface-info-default, transparent);\n color: var(--text-inverse, currentColor);\n border-color: transparent;\n}\n"
404
+ "content": "/* Badge base — sizing (height, padding, font-size, gap) is driven by the\n * size classes below. Height is intrinsic (padding + line-height) so badges\n * stay correct when text wraps or icon slots are introduced. */\n.base {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: fit-content;\n flex-shrink: 0;\n overflow: hidden;\n border-radius: var(--radius-full, 9999px);\n border: 1px solid transparent;\n line-height: 1;\n font-weight: var(--font-weight-medium, 500);\n white-space: nowrap;\n transition: background-color var(--motion-duration-150, 150ms) var(--motion-easing-default, ease-in-out), color var(--motion-duration-150, 150ms) var(--motion-easing-default, ease-in-out), border-color var(--motion-duration-150, 150ms) var(--motion-easing-default, ease-in-out);\n}\n\n.base:focus-visible {\n outline: var(--focus-ring-width, 2px) solid var(--border-focus, currentColor);\n outline-offset: var(--focus-ring-offset, 2px);\n}\n\n/* Sizes — token-driven padding + font-size + gap on the 4px grid.\n * No --spacing-1.5 token exists, so the 6px step uses\n * calc(--spacing-1 + --spacing-1/2) — mirrors the pattern used in kbd. */\n.sizeSm {\n gap: var(--spacing-1, 0.25rem);\n padding: 0 calc(var(--spacing-1, 0.25rem) + var(--spacing-1, 0.25rem) / 2);\n font-size: var(--font-size-xs, 0.75rem);\n}\n\n/* md — matches today's rendering byte-for-byte (1.25rem total height). */\n.sizeMd {\n gap: var(--spacing-1, 0.25rem);\n padding: calc(var(--spacing-1, 0.25rem) / 2) var(--spacing-2, 0.5rem);\n font-size: var(--font-size-xs, 0.75rem);\n}\n\n.sizeLg {\n gap: calc(var(--spacing-1, 0.25rem) + var(--spacing-1, 0.25rem) / 2);\n padding: var(--spacing-1, 0.25rem) var(--spacing-3, 0.75rem);\n font-size: var(--font-size-sm, 0.875rem);\n}\n\n/* Icon scaling — leading glyphs track the per-size font-size step. */\n.sizeSm > svg {\n width: 0.75rem;\n height: 0.75rem;\n}\n\n.sizeMd > svg {\n width: 0.875rem;\n height: 0.875rem;\n}\n\n.sizeLg > svg {\n width: 1rem;\n height: 1rem;\n}\n\n/* Variants */\n.variantDefault {\n background-color: var(--interactive-primary-bg, currentColor);\n color: var(--interactive-primary-text, var(--text-inverse, #f9fafb));\n border-color: transparent;\n}\n\n.variantSecondary {\n background-color: var(--interactive-secondary-bg, var(--surface-subtle, transparent));\n color: var(--interactive-secondary-text, var(--text-primary, currentColor));\n border-color: transparent;\n}\n\n.variantOutline {\n background-color: transparent;\n color: var(--text-primary, #111827);\n border-color: var(--border-default, #e5e7eb);\n}\n\n.variantDestructive {\n background-color: var(--surface-error-subtle, transparent);\n color: var(--text-error, currentColor);\n border-color: transparent;\n}\n\n.variantSuccess {\n background-color: var(--surface-success-subtle, transparent);\n color: var(--text-success, currentColor);\n border-color: transparent;\n}\n\n.variantWarning {\n background-color: var(--surface-warning-subtle, transparent);\n color: var(--text-warning, currentColor);\n border-color: transparent;\n}\n\n.variantInfo {\n background-color: var(--surface-info-subtle, transparent);\n color: var(--text-info, currentColor);\n border-color: transparent;\n}\n\n.variantNeutral {\n background-color: var(--surface-muted, #f3f4f6);\n color: var(--text-secondary, var(--text-primary, #374151));\n border-color: transparent;\n}\n\n/* Filled variants — step 9 bg + contrast text */\n.variantFilledDestructive {\n background-color: var(--surface-error-default, transparent);\n color: var(--text-inverse, currentColor);\n border-color: transparent;\n}\n\n.variantFilledSuccess {\n background-color: var(--surface-success-default, transparent);\n color: var(--text-inverse, currentColor);\n border-color: transparent;\n}\n\n.variantFilledWarning {\n background-color: var(--surface-warning-default, transparent);\n color: var(--text-inverse, currentColor);\n border-color: transparent;\n}\n\n.variantFilledInfo {\n background-color: var(--surface-info-default, transparent);\n color: var(--text-inverse, currentColor);\n border-color: transparent;\n}\n\n/* filled-neutral — the saturated counterpart to `neutral`. Neutral has no\n * brand `-default` surface, so it uses a fixed neutral-600 fill. Because that\n * fill is dark in BOTH modes, text must stay white (not `--text-inverse`,\n * which flips to a dark value in dark mode). */\n.variantFilledNeutral {\n background-color: var(--color-neutral-600, #4b5563);\n color: var(--color-white, #ffffff);\n border-color: transparent;\n}\n"
405
405
  }
406
406
  ]
407
407
  },
@@ -417,12 +417,12 @@
417
417
  {
418
418
  "path": "components/ui/sparkline/sparkline.tsx",
419
419
  "type": "registry:ui",
420
- "content": "import * as React from \"react\"\nimport styles from \"./sparkline.module.css\"\n\nexport interface SparklineProps\n extends Omit<React.SVGAttributes<SVGSVGElement>, \"viewBox\" | \"values\"> {\n /** Numeric series — minimum 2 values required to render. */\n values: number[]\n /** SVG width in px. Defaults to 96. */\n width?: number\n /** SVG height in px. Defaults to 22. */\n height?: number\n /** Stroke color — accepts CSS var, hex, hsl. Defaults to `var(--accent-primary)`. */\n color?: string\n /** Stroke width in px. Defaults to 1.5. */\n strokeWidth?: number\n /**\n * When true, the rendered `<svg>` omits its `width` attribute so it fills its\n * container (the `viewBox` preserves the aspect ratio). A CSS class forces\n * `width: 100%; height: auto; display: block;`. Defaults to `false`.\n */\n fluid?: boolean\n /** When supplied, the sparkline becomes a labeled image instead of decorative. */\n \"aria-label\"?: string\n}\n\nconst Sparkline = React.forwardRef<SVGSVGElement, SparklineProps>(\n (\n {\n values,\n width = 96,\n height = 22,\n color = \"var(--accent-primary)\",\n strokeWidth = 1.5,\n fluid = false,\n className,\n \"aria-label\": ariaLabel,\n ...props\n },\n ref\n ) => {\n if (!values || values.length < 2) return null\n\n const min = Math.min(...values)\n const max = Math.max(...values)\n const range = max - min || 1\n const stepX = width / (values.length - 1)\n const points = values\n .map((v, i) => {\n const x = i * stepX\n const y = height - ((v - min) / range) * height\n return `${x.toFixed(1)},${y.toFixed(1)}`\n })\n .join(\" \")\n\n const isLabeled = typeof ariaLabel === \"string\" && ariaLabel.length > 0\n\n return (\n <svg\n ref={ref}\n data-slot=\"sparkline\"\n className={[styles.svg, fluid && styles.svgFluid, className]\n .filter(Boolean)\n .join(\" \")}\n {...(fluid ? {} : { width })}\n height={height}\n viewBox={`0 0 ${width} ${height}`}\n role=\"img\"\n {...(isLabeled\n ? { \"aria-label\": ariaLabel }\n : { \"aria-hidden\": true })}\n {...props}\n >\n <polyline\n points={points}\n fill=\"none\"\n stroke={color}\n strokeWidth={strokeWidth}\n strokeLinejoin=\"round\"\n strokeLinecap=\"round\"\n />\n </svg>\n )\n }\n)\nSparkline.displayName = \"Sparkline\"\n\nexport { Sparkline }\n"
420
+ "content": "import * as React from \"react\"\nimport styles from \"./sparkline.module.css\"\n\nexport interface SparklineProps\n extends Omit<React.SVGAttributes<SVGSVGElement>, \"viewBox\" | \"values\"> {\n /** Numeric series — minimum 2 values required to render. */\n values: number[]\n /** SVG width in px. Defaults to 96. */\n width?: number\n /** SVG height in px. Defaults to 22. */\n height?: number\n /**\n * Stroke color — accepts CSS var, hex, hsl. Defaults to the theme brand color\n * (`var(--primary, currentColor)`); `currentColor` is the can't-go-invisible\n * fallback if a theme omits `--primary`.\n */\n color?: string\n /** Stroke width in px. Defaults to 1.5. */\n strokeWidth?: number\n /**\n * When true, the rendered `<svg>` omits its `width` attribute so it fills its\n * container (the `viewBox` preserves the aspect ratio). A CSS class forces\n * `width: 100%; height: auto; display: block;`. Defaults to `false`.\n */\n fluid?: boolean\n /** When supplied, the sparkline becomes a labeled image instead of decorative. */\n \"aria-label\"?: string\n /**\n * When true (default), the polyline draws left→right on mount via a\n * `stroke-dashoffset` animation. Set to `false` for a static render\n * identical to the pre-animation baseline.\n */\n animate?: boolean\n /**\n * Duration of the entrance animation in milliseconds. Defaults to 1500.\n * Has no effect when `animate={false}`.\n */\n duration?: number\n}\n\n/** Compute the total length of a polyline from its parsed point pairs. */\nfunction polylineLength(pointPairs: [number, number][]): number {\n let total = 0\n for (let i = 1; i < pointPairs.length; i++) {\n const dx = pointPairs[i][0] - pointPairs[i - 1][0]\n const dy = pointPairs[i][1] - pointPairs[i - 1][1]\n total += Math.sqrt(dx * dx + dy * dy)\n }\n return total\n}\n\nconst Sparkline = React.forwardRef<SVGSVGElement, SparklineProps>(\n (\n {\n values,\n width = 96,\n height = 22,\n color = \"var(--primary, currentColor)\",\n strokeWidth = 1.5,\n fluid = false,\n animate = true,\n duration = 1500,\n className,\n \"aria-label\": ariaLabel,\n ...props\n },\n ref\n ) => {\n if (values == null || values.length < 2) return null\n\n const min = Math.min(...values)\n const max = Math.max(...values)\n const range = max - min || 1\n const stepX = width / (values.length - 1)\n\n const pointPairs: [number, number][] = values.map((v, i) => [\n i * stepX,\n height - ((v - min) / range) * height,\n ])\n const points = pointPairs\n .map(([x, y]) => `${x.toFixed(1)},${y.toFixed(1)}`)\n .join(\" \")\n\n const isLabeled = typeof ariaLabel === \"string\" && ariaLabel.length > 0\n\n // Entrance animation is driven entirely by CSS (`@keyframes sparkline-draw`).\n // The polyline's resting state is fully drawn (`stroke-dashoffset: 0`), so the\n // line is always visible — even during SSR or if JS never runs. The keyframe\n // animates from `--sparkline-length` (fully undrawn) to 0 on mount. This is\n // SSR-safe and behaves identically on reload and client navigation; there is\n // no JS state to race against hydration.\n const totalLength = animate ? polylineLength(pointPairs) : 0\n const polylineProps = animate\n ? {\n className: styles.animatedPolyline,\n style: {\n \"--sparkline-animation-duration\": `${duration}ms`,\n \"--sparkline-length\": `${totalLength}`,\n strokeDasharray: totalLength,\n } as React.CSSProperties,\n }\n : {}\n\n return (\n <svg\n ref={ref}\n data-slot=\"sparkline\"\n className={[styles.svg, fluid && styles.svgFluid, className]\n .filter(Boolean)\n .join(\" \")}\n {...(fluid ? {} : { width })}\n height={height}\n viewBox={`0 0 ${width} ${height}`}\n role=\"img\"\n {...(isLabeled\n ? { \"aria-label\": ariaLabel }\n : { \"aria-hidden\": true })}\n {...props}\n >\n <polyline\n points={points}\n fill=\"none\"\n stroke={color}\n strokeWidth={strokeWidth}\n strokeLinejoin=\"round\"\n strokeLinecap=\"round\"\n {...polylineProps}\n />\n </svg>\n )\n }\n)\nSparkline.displayName = \"Sparkline\"\n\nexport { Sparkline }\n"
421
421
  },
422
422
  {
423
423
  "path": "components/ui/sparkline/sparkline.module.css",
424
424
  "type": "registry:ui",
425
- "content": "/* Sparkline — inline SVG mini-trend chart */\n.svg {\n display: block;\n}\n\n.svgFluid {\n width: 100%;\n height: auto;\n display: block;\n}\n"
425
+ "content": "/* Sparkline — inline SVG mini-trend chart */\n.svg {\n display: block;\n}\n\n.svgFluid {\n width: 100%;\n height: auto;\n display: block;\n}\n\n/*\n * Path-draw entrance animation.\n *\n * Driven by a CSS keyframe — not a JS-toggled transition — so it is SSR-safe and\n * runs identically on full reload and client navigation. The resting state is\n * `stroke-dashoffset: 0` (fully drawn), so the line is ALWAYS visible even if the\n * animation never plays (no JS, hydration race, etc.). The keyframe animates from\n * `--sparkline-length` (the polyline's total length = fully undrawn) to 0 on mount.\n */\n.animatedPolyline {\n --sparkline-animation-duration: var(--motion-duration-1500, 1500ms);\n --sparkline-animation-easing: var(--motion-easing-ease-out, cubic-bezier(0, 0, 0.2, 1));\n stroke-dashoffset: 0;\n animation: sparkline-draw var(--sparkline-animation-duration)\n var(--sparkline-animation-easing) both;\n}\n\n@keyframes sparkline-draw {\n from {\n stroke-dashoffset: var(--sparkline-length, 0);\n }\n to {\n stroke-dashoffset: 0;\n }\n}\n\n/* Respect prefers-reduced-motion — skip the draw, render fully drawn immediately */\n@media (prefers-reduced-motion: reduce) {\n .animatedPolyline {\n animation: none;\n stroke-dashoffset: 0;\n }\n}\n"
426
426
  }
427
427
  ]
428
428
  },
@@ -443,19 +443,19 @@
443
443
  {
444
444
  "path": "components/ui/chip/chip.tsx",
445
445
  "type": "registry:ui",
446
- "content": "\"use client\"\n\nimport * as React from \"react\"\nimport { XIcon } from \"@phosphor-icons/react\"\nimport { cva, type VariantProps } from \"class-variance-authority\"\nimport { cn } from \"../../../lib/utils\"\nimport styles from \"./chip.module.css\"\n\n/* ─── Chip (base) ────────────────────────────────────────────────────── */\n\nconst chipVariants = cva(styles.base, {\n variants: {\n variant: {\n default: styles.variantDefault,\n outlined: styles.variantOutlined,\n },\n size: {\n sm: styles.sizeSm,\n md: styles.sizeMd,\n lg: styles.sizeLg,\n },\n },\n defaultVariants: {\n variant: \"default\",\n size: \"md\",\n },\n})\n\nexport interface ChipProps\n extends React.HTMLAttributes<HTMLDivElement>,\n VariantProps<typeof chipVariants> {\n /** Optional avatar/icon rendered before the label. */\n avatar?: React.ReactNode\n /** Optional leading icon rendered before the label (after avatar). */\n leadingIcon?: React.ReactNode\n /** Label content. Renders as children if omitted. */\n label?: React.ReactNode\n /** Custom delete icon. Defaults to XIcon. */\n deleteIcon?: React.ReactNode\n /** Called when the delete button is activated. When provided the delete button is shown. */\n onDeleted?: () => void\n /** Aria label for the delete button. Defaults to \"Remove\". */\n deleteLabel?: string\n}\n\nconst Chip = React.forwardRef<HTMLDivElement, ChipProps>(\n (\n {\n className,\n variant,\n size,\n avatar,\n leadingIcon,\n label,\n children,\n deleteIcon,\n onDeleted,\n deleteLabel = \"Remove\",\n ...props\n },\n ref,\n ) => {\n const content = label ?? children\n\n return (\n <div\n ref={ref}\n data-slot=\"chip\"\n data-variant={variant ?? \"default\"}\n data-size={size ?? \"md\"}\n className={cn(chipVariants({ variant, size }), className)}\n {...props}\n >\n {avatar ? (\n <span className={styles.avatar} aria-hidden=\"true\">\n {avatar}\n </span>\n ) : null}\n {leadingIcon ? (\n <span className={styles.leadingIcon} aria-hidden=\"true\">\n {leadingIcon}\n </span>\n ) : null}\n <span className={styles.label}>{content}</span>\n {onDeleted ? (\n <button\n type=\"button\"\n aria-label={deleteLabel}\n className={styles.deleteButton}\n onClick={(e) => {\n e.stopPropagation()\n onDeleted()\n }}\n tabIndex={0}\n >\n {deleteIcon ?? (\n <XIcon\n size={12}\n weight=\"bold\"\n aria-hidden=\"true\"\n className={styles.deleteIcon}\n />\n )}\n </button>\n ) : null}\n </div>\n )\n },\n)\nChip.displayName = \"Chip\"\n\n/* ─── ChoiceChip (radio-style single-select) ─────────────────────────── */\n\nexport interface ChoiceChipProps\n extends Omit<React.ButtonHTMLAttributes<HTMLButtonElement>, \"onClick\">,\n VariantProps<typeof chipVariants> {\n /** Whether this chip is currently selected. */\n selected?: boolean\n /** Optional avatar/icon rendered before the label. */\n avatar?: React.ReactNode\n /** Optional leading icon rendered before the label. */\n leadingIcon?: React.ReactNode\n /** Label text or content. */\n label?: React.ReactNode\n /** Called when the chip is pressed. */\n onPressed?: () => void\n /** Value used when in a ChipGroup. */\n value?: string\n}\n\nconst ChoiceChip = React.forwardRef<HTMLButtonElement, ChoiceChipProps>(\n (\n {\n className,\n variant,\n size,\n selected = false,\n avatar,\n leadingIcon,\n label,\n children,\n onPressed,\n value,\n disabled,\n ...props\n },\n ref,\n ) => {\n const content = label ?? children\n\n return (\n <button\n ref={ref}\n type=\"button\"\n role=\"radio\"\n aria-checked={selected}\n data-slot=\"choice-chip\"\n data-variant={variant ?? \"default\"}\n data-size={size ?? \"md\"}\n data-selected={selected ? \"true\" : \"false\"}\n data-value={value}\n disabled={disabled}\n className={cn(\n chipVariants({ variant, size }),\n styles.interactive,\n selected && styles.selected,\n className,\n )}\n onClick={onPressed}\n {...props}\n >\n {avatar ? (\n <span className={styles.avatar} aria-hidden=\"true\">\n {avatar}\n </span>\n ) : null}\n {leadingIcon ? (\n <span className={styles.leadingIcon} aria-hidden=\"true\">\n {leadingIcon}\n </span>\n ) : null}\n <span className={styles.label}>{content}</span>\n </button>\n )\n },\n)\nChoiceChip.displayName = \"ChoiceChip\"\n\n/* ─── FilterChip (multi-select toggle-style) ─────────────────────────── */\n\nexport interface FilterChipProps\n extends Omit<React.ButtonHTMLAttributes<HTMLButtonElement>, \"onClick\">,\n VariantProps<typeof chipVariants> {\n /** Whether this chip is currently active/selected. */\n selected?: boolean\n /** Optional leading icon. */\n leadingIcon?: React.ReactNode\n /** Label text or content. */\n label?: React.ReactNode\n /** Called when the chip is toggled. */\n onPressed?: () => void\n /** Value used when in a ChipGroup. */\n value?: string\n}\n\nconst FilterChip = React.forwardRef<HTMLButtonElement, FilterChipProps>(\n (\n {\n className,\n variant,\n size,\n selected = false,\n leadingIcon,\n label,\n children,\n onPressed,\n value,\n disabled,\n ...props\n },\n ref,\n ) => {\n const content = label ?? children\n\n return (\n <button\n ref={ref}\n type=\"button\"\n role=\"checkbox\"\n aria-checked={selected}\n data-slot=\"filter-chip\"\n data-variant={variant ?? \"default\"}\n data-size={size ?? \"md\"}\n data-selected={selected ? \"true\" : \"false\"}\n data-value={value}\n disabled={disabled}\n className={cn(\n chipVariants({ variant, size }),\n styles.interactive,\n selected && styles.selected,\n className,\n )}\n onClick={onPressed}\n {...props}\n >\n {leadingIcon ? (\n <span className={styles.leadingIcon} aria-hidden=\"true\">\n {leadingIcon}\n </span>\n ) : null}\n <span className={styles.label}>{content}</span>\n </button>\n )\n },\n)\nFilterChip.displayName = \"FilterChip\"\n\nexport { Chip, chipVariants, ChoiceChip, FilterChip }\n"
446
+ "content": "\"use client\"\n\nimport * as React from \"react\"\nimport { XIcon } from \"@phosphor-icons/react\"\nimport { cva, type VariantProps } from \"class-variance-authority\"\nimport { cn } from \"../../../lib/utils\"\nimport styles from \"./chip.module.css\"\n\n/* ─── Chip (base) ────────────────────────────────────────────────────── */\n\nconst chipVariants = cva(styles.base, {\n variants: {\n variant: {\n default: styles.variantDefault,\n outlined: styles.variantOutlined,\n },\n size: {\n sm: styles.sizeSm,\n md: styles.sizeMd,\n lg: styles.sizeLg,\n },\n },\n defaultVariants: {\n variant: \"default\",\n size: \"md\",\n },\n})\n\nexport interface ChipProps\n extends React.HTMLAttributes<HTMLDivElement>,\n VariantProps<typeof chipVariants> {\n /** Optional avatar/icon rendered before the label. */\n avatar?: React.ReactNode\n /** Optional leading icon rendered before the label (after avatar). */\n leadingIcon?: React.ReactNode\n /** Label content. Renders as children if omitted. */\n label?: React.ReactNode\n /** Custom delete icon. Defaults to XIcon. */\n deleteIcon?: React.ReactNode\n /** Called when the delete button is activated. When provided the delete button is shown. */\n onDeleted?: () => void\n /** Aria label for the delete button. Defaults to \"Remove\". */\n deleteLabel?: string\n}\n\nconst Chip = React.forwardRef<HTMLDivElement, ChipProps>(\n (\n {\n className,\n variant,\n size,\n avatar,\n leadingIcon,\n label,\n children,\n deleteIcon,\n onDeleted,\n deleteLabel = \"Remove\",\n ...props\n },\n ref,\n ) => {\n const content = label ?? children\n\n return (\n <div\n ref={ref}\n data-slot=\"chip\"\n data-variant={variant ?? \"default\"}\n data-size={size ?? \"md\"}\n className={cn(chipVariants({ variant, size }), className)}\n {...props}\n >\n {avatar ? (\n <span className={styles.avatar} aria-hidden=\"true\">\n {avatar}\n </span>\n ) : null}\n {leadingIcon ? (\n <span className={styles.leadingIcon} aria-hidden=\"true\">\n {leadingIcon}\n </span>\n ) : null}\n <span className={styles.label}>{content}</span>\n {onDeleted ? (\n <button\n type=\"button\"\n aria-label={deleteLabel}\n className={styles.deleteButton}\n onClick={(e) => {\n e.stopPropagation()\n onDeleted()\n }}\n tabIndex={0}\n >\n {deleteIcon ?? (\n <XIcon\n size={12}\n weight=\"bold\"\n aria-hidden=\"true\"\n className={styles.deleteIcon}\n />\n )}\n </button>\n ) : null}\n </div>\n )\n },\n)\nChip.displayName = \"Chip\"\n\n/* ─── ChoiceChip (radio-style single-select) ─────────────────────────── */\n\nexport interface ChoiceChipProps\n extends Omit<React.ButtonHTMLAttributes<HTMLButtonElement>, \"onClick\">,\n VariantProps<typeof chipVariants> {\n /** Whether this chip is currently selected. */\n selected?: boolean\n /** Optional avatar/icon rendered before the label. */\n avatar?: React.ReactNode\n /** Optional leading icon rendered before the label. */\n leadingIcon?: React.ReactNode\n /** Label text or content. */\n label?: React.ReactNode\n /** Called when the chip is pressed. */\n onPressed?: () => void\n /** Value used when in a ChipGroup. */\n value?: string\n}\n\nconst ChoiceChip = React.forwardRef<HTMLButtonElement, ChoiceChipProps>(\n (\n {\n className,\n variant,\n size,\n selected = false,\n avatar,\n leadingIcon,\n label,\n children,\n onPressed,\n value,\n disabled,\n ...props\n },\n ref,\n ) => {\n const content = label ?? children\n\n return (\n <button\n ref={ref}\n type=\"button\"\n role=\"radio\"\n aria-checked={selected}\n data-slot=\"choice-chip\"\n data-variant={variant ?? \"default\"}\n data-size={size ?? \"md\"}\n data-selected={selected ? \"true\" : \"false\"}\n data-value={value}\n disabled={disabled}\n className={cn(\n chipVariants({ variant, size }),\n styles.interactive,\n selected && styles.selected,\n className,\n )}\n onClick={onPressed}\n {...props}\n >\n {avatar ? (\n <span className={styles.avatar} aria-hidden=\"true\">\n {avatar}\n </span>\n ) : null}\n {leadingIcon ? (\n <span className={styles.leadingIcon} aria-hidden=\"true\">\n {leadingIcon}\n </span>\n ) : null}\n <span className={styles.label}>{content}</span>\n </button>\n )\n },\n)\nChoiceChip.displayName = \"ChoiceChip\"\n\n/* ─── FilterChip (multi-select toggle-style) ─────────────────────────── */\n\nexport interface FilterChipProps\n extends Omit<React.ButtonHTMLAttributes<HTMLButtonElement>, \"onClick\">,\n VariantProps<typeof chipVariants> {\n /** Whether this chip is currently active/selected. */\n selected?: boolean\n /** Optional leading icon. */\n leadingIcon?: React.ReactNode\n /** Label text or content. */\n label?: React.ReactNode\n /** Called when the chip is toggled. */\n onPressed?: () => void\n /** Value used when in a ChipGroup. */\n value?: string\n /** Optional count pill rendered after the label (e.g. \"47\", 132). */\n count?: React.ReactNode\n /** Tone for the count pill. \"neutral\" uses muted surface; \"primary\" uses accent surface. Defaults to \"neutral\". */\n countTone?: \"primary\" | \"neutral\"\n}\n\nconst FilterChip = React.forwardRef<HTMLButtonElement, FilterChipProps>(\n (\n {\n className,\n variant,\n size,\n selected = false,\n leadingIcon,\n label,\n children,\n onPressed,\n value,\n disabled,\n count,\n countTone = \"neutral\",\n ...props\n },\n ref,\n ) => {\n const content = label ?? children\n\n return (\n <button\n ref={ref}\n type=\"button\"\n role=\"checkbox\"\n aria-checked={selected}\n data-slot=\"filter-chip\"\n data-variant={variant ?? \"default\"}\n data-size={size ?? \"md\"}\n data-selected={selected ? \"true\" : \"false\"}\n data-value={value}\n disabled={disabled}\n className={cn(\n chipVariants({ variant, size }),\n styles.interactive,\n selected && styles.selected,\n className,\n )}\n onClick={onPressed}\n {...props}\n >\n {leadingIcon ? (\n <span className={styles.leadingIcon} aria-hidden=\"true\">\n {leadingIcon}\n </span>\n ) : null}\n <span className={styles.label}>{content}</span>\n {count != null ? (\n <span\n data-slot=\"filter-chip-count\"\n data-tone={countTone}\n aria-hidden=\"false\"\n className={cn(\n styles.count,\n countTone === \"primary\" ? styles.countPrimary : styles.countNeutral,\n )}\n >\n {count}\n </span>\n ) : null}\n </button>\n )\n },\n)\nFilterChip.displayName = \"FilterChip\"\n\nexport { Chip, chipVariants, ChoiceChip, FilterChip }\n"
447
447
  },
448
448
  {
449
449
  "path": "components/ui/chip/chip.module.css",
450
450
  "type": "registry:ui",
451
- "content": "/* Chip base */\n.base {\n display: inline-flex;\n align-items: center;\n gap: var(--spacing-1, 0.25rem);\n width: fit-content;\n flex-shrink: 0;\n border-radius: var(--radius-full, 9999px);\n border: var(--stroke-width-thin, 1px) solid var(--border-default, #e5e7eb);\n background-color: var(--surface-card, #ffffff);\n color: var(--text-primary, #111827);\n font-family: var(--font-body, inherit);\n font-weight: var(--font-weight-medium, 500);\n white-space: nowrap;\n user-select: none;\n transition:\n background-color var(--motion-duration-150, 150ms) var(--motion-easing-default, ease-in-out),\n color var(--motion-duration-150, 150ms) var(--motion-easing-default, ease-in-out),\n border-color var(--motion-duration-150, 150ms) var(--motion-easing-default, ease-in-out);\n}\n\n/* Variant: default (filled/tonal surface) */\n.variantDefault {\n background-color: var(--surface-muted, #f3f4f6);\n border-color: transparent;\n color: var(--text-primary, #111827);\n}\n\n/* Variant: outlined */\n.variantOutlined {\n background-color: transparent;\n border-color: var(--border-default, #e5e7eb);\n color: var(--text-primary, #111827);\n}\n\n/* Sizes */\n.sizeSm {\n height: 1.5rem;\n padding: 0 var(--spacing-2, 0.5rem);\n font-size: var(--font-size-xs, 0.75rem);\n gap: var(--spacing-1, 0.25rem);\n}\n\n.sizeMd {\n height: 2rem;\n padding: 0 var(--spacing-3, 0.75rem);\n font-size: var(--font-size-sm, 0.875rem);\n gap: var(--spacing-1, 0.25rem);\n}\n\n.sizeLg {\n height: 2.5rem;\n padding: 0 var(--spacing-4, 1rem);\n font-size: var(--font-size-base, 1rem);\n gap: var(--spacing-2, 0.5rem);\n}\n\n/* Sub-parts */\n.avatar {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n}\n\n.leadingIcon {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n}\n\n.label {\n flex: 1 1 auto;\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.deleteButton {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n background: transparent;\n border: none;\n padding: 0;\n cursor: pointer;\n color: var(--text-secondary, #6b7280);\n border-radius: var(--radius-full, 9999px);\n transition: color var(--motion-duration-150, 150ms) var(--motion-easing-default, ease-in-out),\n background-color var(--motion-duration-150, 150ms) var(--motion-easing-default, ease-in-out);\n width: 1rem;\n height: 1rem;\n}\n\n@media (hover: hover) {\n .deleteButton:hover {\n color: var(--text-primary, #111827);\n background-color: color-mix(in srgb, var(--surface-interactive-hover, #f3f4f6) 60%, transparent);\n }\n}\n\n.deleteButton:focus-visible {\n outline: var(--focus-ring-width, 2px) solid var(--border-focus, #6b7280);\n outline-offset: var(--focus-ring-offset, 1px);\n}\n\n.deleteIcon {\n display: block;\n}\n\n/* Interactive chips (ChoiceChip, FilterChip) */\n.interactive {\n cursor: pointer;\n border: var(--stroke-width-thin, 1px) solid transparent;\n}\n\nbutton.base,\n.interactive {\n /* Inherit base layout; add button-specific resets */\n text-align: left;\n appearance: none;\n -webkit-appearance: none;\n}\n\n.interactive:disabled {\n cursor: not-allowed;\n opacity: var(--opacity-40, 0.4);\n pointer-events: none;\n}\n\n.interactive:focus-visible {\n outline: var(--focus-ring-width, 2px) solid var(--border-focus, #6b7280);\n outline-offset: var(--focus-ring-offset, 2px);\n}\n\n@media (hover: hover) {\n .interactive:hover:not(:disabled):not([data-selected=\"true\"]) {\n background-color: var(--surface-interactive-hover, #f3f4f6);\n border-color: var(--border-default, #e5e7eb);\n }\n}\n\n.interactive:active:not(:disabled) {\n transform: translateY(1px);\n transition: none;\n}\n\n/* Selected state */\n.selected {\n background-color: var(--surface-accent-subtle, #eff6ff);\n border-color: var(--surface-accent-default, #3b82f6);\n color: var(--text-link, #2563eb);\n}\n\n@media (hover: hover) {\n .interactive.selected:hover:not(:disabled) {\n background-color: color-mix(in srgb, var(--surface-accent-subtle, #eff6ff) 80%, var(--surface-interactive-hover, #f3f4f6) 20%);\n }\n}\n"
451
+ "content": "/* Chip base */\n.base {\n display: inline-flex;\n align-items: center;\n gap: var(--spacing-1, 0.25rem);\n width: fit-content;\n flex-shrink: 0;\n border-radius: var(--radius-full, 9999px);\n border: var(--stroke-width-thin, 1px) solid var(--border-default, #e5e7eb);\n background-color: var(--surface-card, #ffffff);\n color: var(--text-primary, #111827);\n font-family: var(--font-body, inherit);\n font-weight: var(--font-weight-medium, 500);\n white-space: nowrap;\n user-select: none;\n transition:\n background-color var(--motion-duration-150, 150ms) var(--motion-easing-default, ease-in-out),\n color var(--motion-duration-150, 150ms) var(--motion-easing-default, ease-in-out),\n border-color var(--motion-duration-150, 150ms) var(--motion-easing-default, ease-in-out);\n}\n\n/* Variant: default (filled/tonal surface) */\n.variantDefault {\n background-color: var(--surface-muted, #f3f4f6);\n border-color: transparent;\n color: var(--text-primary, #111827);\n}\n\n/* Variant: outlined */\n.variantOutlined {\n background-color: transparent;\n border-color: var(--border-default, #e5e7eb);\n color: var(--text-primary, #111827);\n}\n\n/* Sizes */\n.sizeSm {\n height: 1.5rem;\n padding: 0 var(--spacing-2, 0.5rem);\n font-size: var(--font-size-xs, 0.75rem);\n gap: var(--spacing-1, 0.25rem);\n}\n\n.sizeMd {\n height: 2rem;\n padding: 0 var(--spacing-3, 0.75rem);\n font-size: var(--font-size-sm, 0.875rem);\n gap: var(--spacing-1, 0.25rem);\n}\n\n.sizeLg {\n height: 2.5rem;\n padding: 0 var(--spacing-4, 1rem);\n font-size: var(--font-size-base, 1rem);\n gap: var(--spacing-2, 0.5rem);\n}\n\n/* Sub-parts */\n.avatar {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n}\n\n.leadingIcon {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n}\n\n.label {\n flex: 1 1 auto;\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.deleteButton {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n background: transparent;\n border: none;\n padding: 0;\n cursor: pointer;\n color: var(--text-secondary, #6b7280);\n border-radius: var(--radius-full, 9999px);\n transition: color var(--motion-duration-150, 150ms) var(--motion-easing-default, ease-in-out),\n background-color var(--motion-duration-150, 150ms) var(--motion-easing-default, ease-in-out);\n width: 1rem;\n height: 1rem;\n}\n\n@media (hover: hover) {\n .deleteButton:hover {\n color: var(--text-primary, #111827);\n background-color: color-mix(in srgb, var(--surface-interactive-hover, #f3f4f6) 60%, transparent);\n }\n}\n\n.deleteButton:focus-visible {\n outline: var(--focus-ring-width, 2px) solid var(--border-focus, #6b7280);\n outline-offset: var(--focus-ring-offset, 1px);\n}\n\n.deleteIcon {\n display: block;\n}\n\n/* Count pill (FilterChip only) */\n.count {\n display: inline-flex;\n align-items: center;\n flex-shrink: 0;\n border-radius: var(--radius-full, 9999px);\n padding: 0 var(--spacing-2, 0.5rem);\n font-size: var(--font-size-xs, 0.75rem);\n font-weight: var(--font-weight-medium, 500);\n font-variant-numeric: tabular-nums;\n line-height: 1;\n align-self: baseline;\n}\n\n.countNeutral {\n background-color: var(--surface-muted, #f3f4f6);\n color: var(--text-primary, #111827);\n}\n\n.countPrimary {\n background-color: var(--surface-accent-subtle, #eff6ff);\n color: var(--text-link, #2563eb);\n}\n\n[data-selected=\"true\"] .count {\n background-color: var(--surface-card, #ffffff);\n color: var(--text-link, #2563eb);\n}\n\n/* Interactive chips (ChoiceChip, FilterChip) */\n.interactive {\n cursor: pointer;\n border: var(--stroke-width-thin, 1px) solid transparent;\n}\n\nbutton.base,\n.interactive {\n /* Inherit base layout; add button-specific resets */\n text-align: left;\n appearance: none;\n -webkit-appearance: none;\n}\n\n.interactive:disabled {\n cursor: not-allowed;\n opacity: var(--opacity-40, 0.4);\n pointer-events: none;\n}\n\n.interactive:focus-visible {\n outline: var(--focus-ring-width, 2px) solid var(--border-focus, #6b7280);\n outline-offset: var(--focus-ring-offset, 2px);\n}\n\n@media (hover: hover) {\n .interactive:hover:not(:disabled):not([data-selected=\"true\"]) {\n background-color: var(--surface-interactive-hover, #f3f4f6);\n border-color: var(--border-default, #e5e7eb);\n }\n}\n\n.interactive:active:not(:disabled) {\n transform: translateY(1px);\n transition: none;\n}\n\n/* Selected state */\n.selected {\n background-color: var(--surface-accent-subtle, #eff6ff);\n border-color: var(--surface-accent-default, #3b82f6);\n color: var(--text-link, #2563eb);\n}\n\n@media (hover: hover) {\n .interactive.selected:hover:not(:disabled) {\n background-color: color-mix(in srgb, var(--surface-accent-subtle, #eff6ff) 80%, var(--surface-interactive-hover, #f3f4f6) 20%);\n }\n}\n"
452
452
  }
453
453
  ]
454
454
  },
455
455
  {
456
456
  "name": "avatar",
457
457
  "type": "registry:ui",
458
- "description": "An avatar component with image and fallback support, built on Radix UI Avatar.",
458
+ "description": "An avatar component with image and fallback support, built on Radix UI Avatar. Includes the AvatarStack compound primitive for overlapping avatar groups with a +N overflow indicator.",
459
459
  "category": "data-display",
460
460
  "dependencies": [
461
461
  "@radix-ui/react-avatar",
@@ -468,12 +468,17 @@
468
468
  {
469
469
  "path": "components/ui/avatar/avatar.tsx",
470
470
  "type": "registry:ui",
471
- "content": "\"use client\"\n\nimport * as React from \"react\"\nimport * as AvatarPrimitive from \"@radix-ui/react-avatar\"\nimport { cn } from \"../../../lib/utils\"\nimport styles from \"./avatar.module.css\"\n\nexport interface AvatarProps\n extends React.ComponentPropsWithoutRef<typeof AvatarPrimitive.Root> {\n size?: \"sm\" | \"default\" | \"lg\"\n}\n\nconst Avatar = React.forwardRef<\n React.ElementRef<typeof AvatarPrimitive.Root>,\n AvatarProps\n>(({ className, size = \"default\", ...props }, ref) => {\n return (\n <AvatarPrimitive.Root\n ref={ref}\n data-slot=\"avatar\"\n data-size={size}\n className={cn(\n styles.avatar,\n size === \"sm\" && styles.avatarSm,\n size === \"lg\" && styles.avatarLg,\n className\n )}\n {...props}\n />\n )\n})\nAvatar.displayName = \"Avatar\"\n\nconst AvatarImage = React.forwardRef<\n React.ElementRef<typeof AvatarPrimitive.Image>,\n React.ComponentPropsWithoutRef<typeof AvatarPrimitive.Image>\n>(({ className, ...props }, ref) => {\n return (\n <AvatarPrimitive.Image\n ref={ref}\n data-slot=\"avatar-image\"\n className={cn(styles.avatarImage, className)}\n {...props}\n />\n )\n})\nAvatarImage.displayName = \"AvatarImage\"\n\nconst AvatarFallback = React.forwardRef<\n React.ElementRef<typeof AvatarPrimitive.Fallback>,\n React.ComponentPropsWithoutRef<typeof AvatarPrimitive.Fallback>\n>(({ className, ...props }, ref) => {\n return (\n <AvatarPrimitive.Fallback\n ref={ref}\n data-slot=\"avatar-fallback\"\n className={cn(styles.avatarFallback, className)}\n {...props}\n />\n )\n})\nAvatarFallback.displayName = \"AvatarFallback\"\n\nexport { Avatar, AvatarImage, AvatarFallback }\n"
471
+ "content": "\"use client\"\n\nimport * as React from \"react\"\nimport * as AvatarPrimitive from \"@radix-ui/react-avatar\"\nimport { cn } from \"../../../lib/utils\"\nimport styles from \"./avatar.module.css\"\nimport stackStyles from \"./avatar-stack.module.css\"\n\nexport interface AvatarProps\n extends React.ComponentPropsWithoutRef<typeof AvatarPrimitive.Root> {\n size?: \"sm\" | \"default\" | \"lg\"\n}\n\nconst Avatar = React.forwardRef<\n React.ElementRef<typeof AvatarPrimitive.Root>,\n AvatarProps\n>(({ className, size = \"default\", ...props }, ref) => {\n return (\n <AvatarPrimitive.Root\n ref={ref}\n data-slot=\"avatar\"\n data-size={size}\n className={cn(\n styles.avatar,\n size === \"sm\" && styles.avatarSm,\n size === \"lg\" && styles.avatarLg,\n className\n )}\n {...props}\n />\n )\n})\nAvatar.displayName = \"Avatar\"\n\nconst AvatarImage = React.forwardRef<\n React.ElementRef<typeof AvatarPrimitive.Image>,\n React.ComponentPropsWithoutRef<typeof AvatarPrimitive.Image>\n>(({ className, ...props }, ref) => {\n return (\n <AvatarPrimitive.Image\n ref={ref}\n data-slot=\"avatar-image\"\n className={cn(styles.avatarImage, className)}\n {...props}\n />\n )\n})\nAvatarImage.displayName = \"AvatarImage\"\n\nconst AvatarFallback = React.forwardRef<\n React.ElementRef<typeof AvatarPrimitive.Fallback>,\n React.ComponentPropsWithoutRef<typeof AvatarPrimitive.Fallback>\n>(({ className, ...props }, ref) => {\n return (\n <AvatarPrimitive.Fallback\n ref={ref}\n data-slot=\"avatar-fallback\"\n className={cn(styles.avatarFallback, className)}\n {...props}\n />\n )\n})\nAvatarFallback.displayName = \"AvatarFallback\"\n\nexport interface AvatarStackProps\n extends Omit<React.HTMLAttributes<HTMLDivElement>, \"role\" | \"aria-label\"> {\n /**\n * Avatar image sources to render, in display order. `undefined` entries\n * render with the `·` fallback so server-truncated lists still occupy a\n * slot.\n */\n avatars: (string | undefined)[]\n /**\n * Total member count. May exceed `avatars.length` when the caller has\n * server-truncated the avatar URLs and only knows the count. The overflow\n * indicator is computed against this value.\n */\n total: number\n /**\n * Maximum number of avatar slots rendered before the `+N` overflow\n * indicator. Defaults to `6`.\n */\n max?: number\n /** Avatar size. Defaults to `\"sm\"`. */\n size?: \"sm\" | \"default\" | \"lg\"\n /**\n * Accessible label override. Defaults to ``${total} members``.\n */\n label?: string\n}\n\nconst AvatarStack = React.forwardRef<HTMLDivElement, AvatarStackProps>(\n function AvatarStack(\n {\n avatars,\n total,\n max = 6,\n size = \"sm\",\n label,\n className,\n ...rest\n },\n ref,\n ) {\n const visible = avatars.slice(0, max)\n const overflow = Math.max(0, total - visible.length)\n const ariaLabel = label ?? `${total} members`\n\n return (\n <div\n ref={ref}\n role=\"img\"\n aria-label={ariaLabel}\n data-slot=\"avatar-stack\"\n data-size={size}\n className={cn(stackStyles.root, className)}\n {...rest}\n >\n {visible.map((src, index) => (\n <Avatar\n key={index}\n size={size}\n className={stackStyles.avatar}\n data-stack-item=\"\"\n >\n {src ? (\n <AvatarImage src={src} alt=\"\" />\n ) : (\n <AvatarFallback>·</AvatarFallback>\n )}\n </Avatar>\n ))}\n {overflow > 0 ? (\n <Avatar\n size={size}\n className={stackStyles.avatar}\n data-stack-overflow=\"\"\n >\n <AvatarFallback>+{overflow}</AvatarFallback>\n </Avatar>\n ) : null}\n </div>\n )\n },\n)\n\nAvatarStack.displayName = \"AvatarStack\"\n\nexport { Avatar, AvatarImage, AvatarFallback, AvatarStack }\n"
472
472
  },
473
473
  {
474
474
  "path": "components/ui/avatar/avatar.module.css",
475
475
  "type": "registry:ui",
476
476
  "content": "/* Avatar */\n.avatar {\n position: relative;\n display: flex;\n width: 2rem;\n height: 2rem;\n flex-shrink: 0;\n border-radius: var(--radius-full, 9999px);\n user-select: none;\n overflow: hidden;\n}\n\n.avatarSm {\n width: 1.5rem;\n height: 1.5rem;\n}\n\n.avatarLg {\n width: 2.5rem;\n height: 2.5rem;\n}\n\n/* AvatarImage */\n.avatarImage {\n aspect-ratio: 1 / 1;\n width: 100%;\n height: 100%;\n border-radius: var(--radius-full, 9999px);\n object-fit: cover;\n}\n\n/* AvatarFallback */\n.avatarFallback {\n display: flex;\n width: 100%;\n height: 100%;\n align-items: center;\n justify-content: center;\n border-radius: var(--radius-full, 9999px);\n background-color: var(--surface-muted, #f3f4f6);\n color: var(--text-secondary, #6b7280);\n font-size: var(--font-size-sm, 0.875rem);\n font-weight: var(--font-weight-medium, 500);\n}\n"
477
+ },
478
+ {
479
+ "path": "components/ui/avatar/avatar-stack.module.css",
480
+ "type": "registry:ui",
481
+ "content": "/* AvatarStack root */\n.root {\n display: inline-flex;\n flex-direction: row;\n align-items: center;\n isolation: isolate;\n}\n\n/* Each avatar gets a ring matching the parent surface so adjacent avatars\n read as separate circles. Avatar's own `overflow: hidden` clips inner\n shadows, so the ring is projected outward via box-shadow. */\n.avatar {\n box-shadow: 0 0 0 var(--stroke-width-medium, 2px) var(--surface-default, #ffffff);\n}\n\n/* Overlap every avatar except the first. Later siblings stack on top of\n earlier ones because `isolation: isolate` establishes a single stacking\n context and DOM order wins inside it. */\n.avatar:not(:first-child) {\n margin-inline-start: calc(-1 * var(--spacing-2, 0.5rem));\n}\n"
477
482
  }
478
483
  ]
479
484
  },
@@ -554,7 +559,7 @@
554
559
  {
555
560
  "name": "alert",
556
561
  "type": "registry:ui",
557
- "description": "An alert component with title and description sub-components, supporting default, destructive, success, and warning variants.",
562
+ "description": "An alert component with title, description, and right-aligned actions sub-components, supporting default, destructive, success, and warning variants.",
558
563
  "category": "feedback",
559
564
  "dependencies": [
560
565
  "class-variance-authority",
@@ -567,12 +572,12 @@
567
572
  {
568
573
  "path": "components/ui/alert/alert.tsx",
569
574
  "type": "registry:ui",
570
- "content": "import * as React from \"react\"\nimport { cva, type VariantProps } from \"class-variance-authority\"\nimport { cn } from \"../../../lib/utils\"\nimport styles from \"./alert.module.css\"\n\nconst alertVariants = cva(styles.base, {\n variants: {\n variant: {\n default: styles.variantDefault,\n destructive: styles.variantDestructive,\n success: styles.variantSuccess,\n warning: styles.variantWarning,\n info: styles.variantInfo,\n },\n },\n defaultVariants: {\n variant: \"default\",\n },\n})\n\nexport interface AlertProps\n extends React.HTMLAttributes<HTMLDivElement>,\n VariantProps<typeof alertVariants> {}\n\nconst Alert = React.forwardRef<HTMLDivElement, AlertProps>(\n ({ className, variant, ...props }, ref) => {\n return (\n <div\n ref={ref}\n data-slot=\"alert\"\n role=\"alert\"\n className={cn(alertVariants({ variant }), className)}\n {...props}\n />\n )\n }\n)\nAlert.displayName = \"Alert\"\n\nconst AlertTitle = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(\n ({ className, ...props }, ref) => {\n return (\n <div\n ref={ref}\n data-slot=\"alert-title\"\n className={cn(styles.title, className)}\n {...props}\n />\n )\n }\n)\nAlertTitle.displayName = \"AlertTitle\"\n\nconst AlertDescription = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(\n ({ className, ...props }, ref) => {\n return (\n <div\n ref={ref}\n data-slot=\"alert-description\"\n className={cn(styles.description, className)}\n {...props}\n />\n )\n }\n)\nAlertDescription.displayName = \"AlertDescription\"\n\nexport { Alert, AlertTitle, AlertDescription, alertVariants }\n"
575
+ "content": "import * as React from \"react\"\nimport { cva, type VariantProps } from \"class-variance-authority\"\nimport { cn } from \"../../../lib/utils\"\nimport styles from \"./alert.module.css\"\n\nconst alertVariants = cva(styles.base, {\n variants: {\n variant: {\n default: styles.variantDefault,\n destructive: styles.variantDestructive,\n success: styles.variantSuccess,\n warning: styles.variantWarning,\n info: styles.variantInfo,\n },\n },\n defaultVariants: {\n variant: \"default\",\n },\n})\n\nexport interface AlertProps\n extends React.HTMLAttributes<HTMLDivElement>,\n VariantProps<typeof alertVariants> {}\n\nconst Alert = React.forwardRef<HTMLDivElement, AlertProps>(\n ({ className, variant, ...props }, ref) => {\n return (\n <div\n ref={ref}\n data-slot=\"alert\"\n role=\"alert\"\n className={cn(alertVariants({ variant }), className)}\n {...props}\n />\n )\n }\n)\nAlert.displayName = \"Alert\"\n\nconst AlertTitle = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(\n ({ className, ...props }, ref) => {\n return (\n <div\n ref={ref}\n data-slot=\"alert-title\"\n className={cn(styles.title, className)}\n {...props}\n />\n )\n }\n)\nAlertTitle.displayName = \"AlertTitle\"\n\nconst AlertDescription = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(\n ({ className, ...props }, ref) => {\n return (\n <div\n ref={ref}\n data-slot=\"alert-description\"\n className={cn(styles.description, className)}\n {...props}\n />\n )\n }\n)\nAlertDescription.displayName = \"AlertDescription\"\n\nconst AlertActions = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(\n ({ className, ...props }, ref) => {\n return (\n <div\n ref={ref}\n data-slot=\"alert-actions\"\n className={cn(styles.actions, className)}\n {...props}\n />\n )\n }\n)\nAlertActions.displayName = \"AlertActions\"\n\nexport { Alert, AlertTitle, AlertDescription, AlertActions, alertVariants }\n"
571
576
  },
572
577
  {
573
578
  "path": "components/ui/alert/alert.module.css",
574
579
  "type": "registry:ui",
575
- "content": "/* Alert base */\n.base {\n position: relative;\n display: grid;\n width: 100%;\n gap: calc(var(--spacing-1, 0.25rem) / 2);\n border-radius: var(--radius-lg, 0.5rem);\n box-shadow: var(--shadow-sm);\n padding: var(--spacing-3, 0.75rem) var(--spacing-4, 1rem);\n font-size: var(--font-size-sm, 0.875rem);\n text-align: left;\n}\n\n/* Variants */\n.variantDefault {\n background-color: var(--surface-card, #ffffff);\n color: var(--text-primary, #111827);\n}\n\n.variantDestructive {\n background-color: var(--surface-error-subtle, #fef2f2);\n color: var(--text-error, #b91c1c);\n border: 1px solid var(--border-error, #ef4444);\n}\n\n.variantSuccess {\n background-color: var(--surface-success-subtle, #f0fdf4);\n color: var(--text-success, #15803d);\n border: 1px solid var(--border-success, #22c55e);\n}\n\n.variantWarning {\n background-color: var(--surface-warning-subtle, #fffbeb);\n color: var(--text-warning, #b45309);\n border: 1px solid var(--border-warning, #f59e0b);\n}\n\n.variantInfo {\n background-color: var(--surface-info-subtle, #f0f9ff);\n color: var(--text-info, #0369a1);\n border: 1px solid var(--border-info, #0ea5e9);\n}\n\n/* AlertTitle */\n.title {\n font-weight: var(--font-weight-semibold, 600);\n line-height: 1.5;\n color: inherit;\n}\n\n/* AlertDescription */\n.description {\n font-size: var(--font-size-sm, 0.875rem);\n color: var(--text-secondary, #6b7280);\n line-height: 1.5;\n}\n\n.variantDestructive .description {\n color: color-mix(in srgb, var(--text-error, #b91c1c) 90%, transparent);\n}\n\n.variantSuccess .description {\n color: color-mix(in srgb, var(--text-success, #15803d) 90%, transparent);\n}\n\n.variantWarning .description {\n color: color-mix(in srgb, var(--text-warning, #b45309) 90%, transparent);\n}\n\n.variantInfo .description {\n color: color-mix(in srgb, var(--text-info, #0369a1) 90%, transparent);\n}\n"
580
+ "content": "/* Alert base */\n.base {\n position: relative;\n display: grid;\n width: 100%;\n gap: calc(var(--spacing-1, 0.25rem) / 2);\n border-radius: var(--radius-lg, 0.5rem);\n box-shadow: var(--shadow-sm);\n padding: var(--spacing-3, 0.75rem) var(--spacing-4, 1rem);\n font-size: var(--font-size-sm, 0.875rem);\n text-align: left;\n}\n\n/* Variants */\n.variantDefault {\n background-color: var(--surface-card, transparent);\n color: var(--text-primary, currentColor);\n}\n\n.variantDestructive {\n background-color: var(--surface-error-subtle, transparent);\n color: var(--text-error, currentColor);\n border: 1px solid var(--border-error, currentColor);\n}\n\n.variantSuccess {\n background-color: var(--surface-success-subtle, transparent);\n color: var(--text-success, currentColor);\n border: 1px solid var(--border-success, currentColor);\n}\n\n.variantWarning {\n background-color: var(--surface-warning-subtle, transparent);\n color: var(--text-warning, currentColor);\n border: 1px solid var(--border-warning, currentColor);\n}\n\n.variantInfo {\n background-color: var(--surface-info-subtle, transparent);\n color: var(--text-info, currentColor);\n border: 1px solid var(--border-info, currentColor);\n}\n\n/* AlertTitle */\n.title {\n font-weight: var(--font-weight-semibold, 600);\n line-height: 1.5;\n color: inherit;\n}\n\n/* AlertDescription */\n.description {\n font-size: var(--font-size-sm, 0.875rem);\n color: var(--text-secondary, currentColor);\n line-height: 1.5;\n}\n\n/* AlertActions — right-aligned, gap-aware row for inline action buttons */\n.actions {\n display: flex;\n align-items: center;\n justify-content: flex-end;\n gap: var(--spacing-2, 0.5rem);\n flex-wrap: wrap;\n margin-top: var(--spacing-2, 0.5rem);\n}\n\n.variantDestructive .description {\n color: color-mix(in srgb, var(--text-error, currentColor) 90%, transparent);\n}\n\n.variantSuccess .description {\n color: color-mix(in srgb, var(--text-success, currentColor) 90%, transparent);\n}\n\n.variantWarning .description {\n color: color-mix(in srgb, var(--text-warning, currentColor) 90%, transparent);\n}\n\n.variantInfo .description {\n color: color-mix(in srgb, var(--text-info, currentColor) 90%, transparent);\n}\n"
576
581
  }
577
582
  ]
578
583
  },
@@ -592,12 +597,12 @@
592
597
  {
593
598
  "path": "components/ui/progress/progress.tsx",
594
599
  "type": "registry:ui",
595
- "content": "\"use client\"\n\nimport * as React from \"react\"\nimport * as ProgressPrimitive from \"@radix-ui/react-progress\"\nimport { cn } from \"../../../lib/utils\"\nimport styles from \"./progress.module.css\"\n\nexport interface ProgressProps\n extends React.ComponentPropsWithoutRef<typeof ProgressPrimitive.Root> {\n /** Track size. `\"thin\"` renders a 4px-tall variant for static admin chrome. */\n size?: \"default\" | \"thin\"\n /** Whether the indicator transitions on value change. Defaults to `true`. */\n animate?: boolean\n}\n\nconst Progress = React.forwardRef<\n React.ElementRef<typeof ProgressPrimitive.Root>,\n ProgressProps\n>(({ className, value, size = \"default\", animate = true, ...props }, ref) => {\n return (\n <ProgressPrimitive.Root\n ref={ref}\n data-slot=\"progress\"\n data-size={size === \"thin\" ? \"thin\" : undefined}\n data-animate={animate === false ? \"false\" : undefined}\n className={cn(styles.root, className)}\n {...props}\n >\n <ProgressPrimitive.Indicator\n data-slot=\"progress-indicator\"\n className={styles.indicator}\n style={{ transform: `translateX(-${100 - (value || 0)}%)` }}\n />\n </ProgressPrimitive.Root>\n )\n})\nProgress.displayName = \"Progress\"\n\nexport { Progress }\n"
600
+ "content": "\"use client\"\n\nimport * as React from \"react\"\nimport * as ProgressPrimitive from \"@radix-ui/react-progress\"\nimport { cn } from \"../../../lib/utils\"\nimport styles from \"./progress.module.css\"\n\nexport interface ProgressProps\n extends React.ComponentPropsWithoutRef<typeof ProgressPrimitive.Root> {\n /** Track size. `\"thin\"` renders a 4px-tall variant for static admin chrome. */\n size?: \"default\" | \"thin\"\n /** Whether the indicator transitions on value change. Defaults to `true`. */\n animate?: boolean\n /**\n * Entrance animation duration in ms. Defaults to 1500. Only applies when\n * `animate={true}` and the user has not opted into reduced motion.\n */\n duration?: number\n}\n\nconst Progress = React.forwardRef<\n React.ElementRef<typeof ProgressPrimitive.Root>,\n ProgressProps\n>(\n (\n { className, value, size = \"default\", animate = true, duration = 1500, ...props },\n ref\n ) => {\n // The indicator always renders at its real value (`translateX`), so the bar is\n // visible immediately — during SSR and before/without hydration. The entrance\n // sweep is a pure CSS keyframe (`@keyframes progress-fill`) that animates from\n // 0% to the resting value on mount; subsequent value changes are handled by the\n // indicator's `transition`. No JS state, so it is SSR-safe and behaves the same\n // on full reload and client navigation.\n const resolvedValue = value ?? 0\n const indicatorStyle: React.CSSProperties = animate\n ? ({ transform: `translateX(-${100 - resolvedValue}%)`, \"--progress-animation-duration\": `${duration}ms` } as React.CSSProperties)\n : { transform: `translateX(-${100 - resolvedValue}%)` }\n\n return (\n <ProgressPrimitive.Root\n ref={ref}\n data-slot=\"progress\"\n data-size={size === \"thin\" ? \"thin\" : undefined}\n data-animate={animate === false ? \"false\" : undefined}\n className={cn(styles.root, className)}\n {...props}\n >\n <ProgressPrimitive.Indicator\n data-slot=\"progress-indicator\"\n className={cn(styles.indicator, animate && styles.indicatorAnimated)}\n style={indicatorStyle}\n />\n </ProgressPrimitive.Root>\n )\n }\n)\nProgress.displayName = \"Progress\"\n\nexport { Progress }\n"
596
601
  },
597
602
  {
598
603
  "path": "components/ui/progress/progress.module.css",
599
604
  "type": "registry:ui",
600
- "content": "/* Progress root */\n.root {\n position: relative;\n display: flex;\n width: 100%;\n height: 0.75rem;\n align-items: center;\n overflow: hidden;\n border-radius: var(--radius-full, 9999px);\n background-color: var(--surface-muted, #f3f4f6);\n}\n\n/* Progress indicator */\n.indicator {\n width: 100%;\n height: 100%;\n flex: 1;\n background-color: var(--interactive-primary-bg, #111827);\n transition: transform var(--motion-duration-300, 300ms) var(--motion-easing-default, ease-in-out);\n}\n\n/* Thin static-chrome variant — 4px capacity bar for admin KPI strips */\n.root[data-size=\"thin\"] {\n height: 4px;\n background-color: var(--surface-interactive-active, #e5e7eb);\n}\n\n/* animate={false} — drop the indicator transition for static chrome */\n.root[data-animate=\"false\"] .indicator {\n transition: none;\n}\n"
605
+ "content": "/* Progress root */\n.root {\n position: relative;\n display: flex;\n width: 100%;\n height: 0.75rem;\n align-items: center;\n overflow: hidden;\n border-radius: var(--radius-full, 9999px);\n background-color: var(--surface-muted, #f3f4f6);\n}\n\n/* Progress indicator */\n.indicator {\n width: 100%;\n height: 100%;\n flex: 1;\n background-color: var(--interactive-primary-bg, var(--primary, #111827));\n transition: transform var(--progress-animation-duration, var(--motion-duration-1500, 1500ms)) var(--motion-easing-default, ease-in-out);\n}\n\n/*\n * Entrance sweep — pure CSS keyframe, runs once on mount. The indicator's resting\n * transform is its real value (set inline), so the bar is visible immediately (SSR\n * and pre-hydration); the keyframe only animates the sweep FROM empty (-100%) TO\n * that resting value. SSR-safe and identical on reload vs. client navigation.\n */\n.indicatorAnimated {\n animation: progress-fill\n var(--progress-animation-duration, var(--motion-duration-1500, 1500ms))\n var(--motion-easing-default, ease-in-out) both;\n}\n\n@keyframes progress-fill {\n from {\n transform: translateX(-100%);\n }\n}\n\n/* Thin static-chrome variant — 4px capacity bar for admin KPI strips */\n.root[data-size=\"thin\"] {\n height: 4px;\n background-color: var(--surface-interactive-active, #e5e7eb);\n}\n\n/* animate={false} — drop the indicator transition for static chrome */\n.root[data-animate=\"false\"] .indicator {\n transition: none;\n}\n\n/* Reduced motion — instant fill, no entrance sweep, no transition */\n@media (prefers-reduced-motion: reduce) {\n .indicator {\n transition: none;\n }\n .indicatorAnimated {\n animation: none;\n }\n}\n"
601
606
  }
602
607
  ]
603
608
  },
@@ -671,12 +676,12 @@
671
676
  {
672
677
  "path": "components/ui/dropdown-menu/dropdown-menu.tsx",
673
678
  "type": "registry:ui",
674
- "content": "\"use client\"\n\nimport * as React from \"react\"\nimport * as DropdownMenuPrimitive from \"@radix-ui/react-dropdown-menu\"\nimport { CheckIcon, CaretRightIcon } from \"@phosphor-icons/react\"\nimport { cn } from \"../../../lib/utils\"\nimport styles from \"./dropdown-menu.module.css\"\n\nfunction DropdownMenu({ ...props }: React.ComponentProps<typeof DropdownMenuPrimitive.Root>) {\n return <DropdownMenuPrimitive.Root data-slot=\"dropdown-menu\" {...props} />\n}\nDropdownMenu.displayName = \"DropdownMenu\"\n\nfunction DropdownMenuPortal({ ...props }: React.ComponentProps<typeof DropdownMenuPrimitive.Portal>) {\n return <DropdownMenuPrimitive.Portal data-slot=\"dropdown-menu-portal\" {...props} />\n}\nDropdownMenuPortal.displayName = \"DropdownMenuPortal\"\n\nfunction DropdownMenuTrigger({ ...props }: React.ComponentProps<typeof DropdownMenuPrimitive.Trigger>) {\n return <DropdownMenuPrimitive.Trigger data-slot=\"dropdown-menu-trigger\" {...props} />\n}\nDropdownMenuTrigger.displayName = \"DropdownMenuTrigger\"\n\nconst DropdownMenuContent = React.forwardRef<\n React.ComponentRef<typeof DropdownMenuPrimitive.Content>,\n React.ComponentProps<typeof DropdownMenuPrimitive.Content>\n>(({ className, align = \"start\", sideOffset = 4, ...props }, ref) => (\n <DropdownMenuPrimitive.Portal>\n <DropdownMenuPrimitive.Content\n ref={ref}\n data-slot=\"dropdown-menu-content\"\n sideOffset={sideOffset}\n align={align}\n className={cn(styles.content, className)}\n {...props}\n />\n </DropdownMenuPrimitive.Portal>\n))\nDropdownMenuContent.displayName = \"DropdownMenuContent\"\n\nfunction DropdownMenuGroup({ ...props }: React.ComponentProps<typeof DropdownMenuPrimitive.Group>) {\n return <DropdownMenuPrimitive.Group data-slot=\"dropdown-menu-group\" {...props} />\n}\nDropdownMenuGroup.displayName = \"DropdownMenuGroup\"\n\nexport interface DropdownMenuItemProps\n extends React.ComponentProps<typeof DropdownMenuPrimitive.Item> {\n inset?: boolean\n variant?: \"default\" | \"destructive\"\n}\n\nconst DropdownMenuItem = React.forwardRef<\n React.ComponentRef<typeof DropdownMenuPrimitive.Item>,\n DropdownMenuItemProps\n>(({ className, inset, variant = \"default\", ...props }, ref) => (\n <DropdownMenuPrimitive.Item\n ref={ref}\n data-slot=\"dropdown-menu-item\"\n data-inset={inset}\n data-variant={variant}\n className={cn(\n styles.item,\n variant === \"destructive\" && styles.itemDestructive,\n inset && styles.itemInset,\n className\n )}\n {...props}\n />\n))\nDropdownMenuItem.displayName = \"DropdownMenuItem\"\n\nconst DropdownMenuCheckboxItem = React.forwardRef<\n React.ComponentRef<typeof DropdownMenuPrimitive.CheckboxItem>,\n React.ComponentProps<typeof DropdownMenuPrimitive.CheckboxItem> & { inset?: boolean }\n>(({ className, children, checked, inset, ...props }, ref) => (\n <DropdownMenuPrimitive.CheckboxItem\n ref={ref}\n data-slot=\"dropdown-menu-checkbox-item\"\n data-inset={inset}\n className={cn(styles.checkboxItem, inset && styles.itemInset, className)}\n checked={checked}\n {...props}\n >\n <span className={styles.itemIndicator} data-slot=\"dropdown-menu-checkbox-item-indicator\">\n <DropdownMenuPrimitive.ItemIndicator>\n <CheckIcon />\n </DropdownMenuPrimitive.ItemIndicator>\n </span>\n {children}\n </DropdownMenuPrimitive.CheckboxItem>\n))\nDropdownMenuCheckboxItem.displayName = \"DropdownMenuCheckboxItem\"\n\nfunction DropdownMenuRadioGroup({ ...props }: React.ComponentProps<typeof DropdownMenuPrimitive.RadioGroup>) {\n return <DropdownMenuPrimitive.RadioGroup data-slot=\"dropdown-menu-radio-group\" {...props} />\n}\nDropdownMenuRadioGroup.displayName = \"DropdownMenuRadioGroup\"\n\nconst DropdownMenuRadioItem = React.forwardRef<\n React.ComponentRef<typeof DropdownMenuPrimitive.RadioItem>,\n React.ComponentProps<typeof DropdownMenuPrimitive.RadioItem> & { inset?: boolean }\n>(({ className, children, inset, ...props }, ref) => (\n <DropdownMenuPrimitive.RadioItem\n ref={ref}\n data-slot=\"dropdown-menu-radio-item\"\n data-inset={inset}\n className={cn(styles.radioItem, inset && styles.itemInset, className)}\n {...props}\n >\n <span className={styles.itemIndicator} data-slot=\"dropdown-menu-radio-item-indicator\">\n <DropdownMenuPrimitive.ItemIndicator>\n <CheckIcon />\n </DropdownMenuPrimitive.ItemIndicator>\n </span>\n {children}\n </DropdownMenuPrimitive.RadioItem>\n))\nDropdownMenuRadioItem.displayName = \"DropdownMenuRadioItem\"\n\nconst DropdownMenuLabel = React.forwardRef<\n React.ComponentRef<typeof DropdownMenuPrimitive.Label>,\n React.ComponentProps<typeof DropdownMenuPrimitive.Label> & { inset?: boolean }\n>(({ className, inset, ...props }, ref) => (\n <DropdownMenuPrimitive.Label\n ref={ref}\n data-slot=\"dropdown-menu-label\"\n data-inset={inset}\n className={cn(styles.label, inset && styles.itemInset, className)}\n {...props}\n />\n))\nDropdownMenuLabel.displayName = \"DropdownMenuLabel\"\n\nconst DropdownMenuSeparator = React.forwardRef<\n React.ComponentRef<typeof DropdownMenuPrimitive.Separator>,\n React.ComponentProps<typeof DropdownMenuPrimitive.Separator>\n>(({ className, ...props }, ref) => (\n <DropdownMenuPrimitive.Separator\n ref={ref}\n data-slot=\"dropdown-menu-separator\"\n className={cn(styles.separator, className)}\n {...props}\n />\n))\nDropdownMenuSeparator.displayName = \"DropdownMenuSeparator\"\n\nfunction DropdownMenuShortcut({ className, ...props }: React.ComponentProps<\"span\">) {\n return (\n <span\n data-slot=\"dropdown-menu-shortcut\"\n className={cn(styles.shortcut, className)}\n {...props}\n />\n )\n}\nDropdownMenuShortcut.displayName = \"DropdownMenuShortcut\"\n\nfunction DropdownMenuSub({ ...props }: React.ComponentProps<typeof DropdownMenuPrimitive.Sub>) {\n return <DropdownMenuPrimitive.Sub data-slot=\"dropdown-menu-sub\" {...props} />\n}\nDropdownMenuSub.displayName = \"DropdownMenuSub\"\n\nconst DropdownMenuSubTrigger = React.forwardRef<\n React.ComponentRef<typeof DropdownMenuPrimitive.SubTrigger>,\n React.ComponentProps<typeof DropdownMenuPrimitive.SubTrigger> & { inset?: boolean }\n>(({ className, inset, children, ...props }, ref) => (\n <DropdownMenuPrimitive.SubTrigger\n ref={ref}\n data-slot=\"dropdown-menu-sub-trigger\"\n data-inset={inset}\n className={cn(styles.subTrigger, inset && styles.itemInset, className)}\n {...props}\n >\n {children}\n <CaretRightIcon className={styles.subTriggerIcon} />\n </DropdownMenuPrimitive.SubTrigger>\n))\nDropdownMenuSubTrigger.displayName = \"DropdownMenuSubTrigger\"\n\nconst DropdownMenuSubContent = React.forwardRef<\n React.ComponentRef<typeof DropdownMenuPrimitive.SubContent>,\n React.ComponentProps<typeof DropdownMenuPrimitive.SubContent>\n>(({ className, ...props }, ref) => (\n <DropdownMenuPrimitive.SubContent\n ref={ref}\n data-slot=\"dropdown-menu-sub-content\"\n className={cn(styles.subContent, className)}\n {...props}\n />\n))\nDropdownMenuSubContent.displayName = \"DropdownMenuSubContent\"\n\nexport {\n DropdownMenu,\n DropdownMenuPortal,\n DropdownMenuTrigger,\n DropdownMenuContent,\n DropdownMenuGroup,\n DropdownMenuLabel,\n DropdownMenuItem,\n DropdownMenuCheckboxItem,\n DropdownMenuRadioGroup,\n DropdownMenuRadioItem,\n DropdownMenuSeparator,\n DropdownMenuShortcut,\n DropdownMenuSub,\n DropdownMenuSubTrigger,\n DropdownMenuSubContent,\n}\n"
679
+ "content": "\"use client\"\n\nimport * as React from \"react\"\nimport * as DropdownMenuPrimitive from \"@radix-ui/react-dropdown-menu\"\nimport { CheckIcon, CaretRightIcon } from \"@phosphor-icons/react\"\nimport { cn } from \"../../../lib/utils\"\nimport styles from \"./dropdown-menu.module.css\"\n\nfunction DropdownMenu({ ...props }: React.ComponentProps<typeof DropdownMenuPrimitive.Root>) {\n return <DropdownMenuPrimitive.Root data-slot=\"dropdown-menu\" {...props} />\n}\nDropdownMenu.displayName = \"DropdownMenu\"\n\nfunction DropdownMenuPortal({ ...props }: React.ComponentProps<typeof DropdownMenuPrimitive.Portal>) {\n return <DropdownMenuPrimitive.Portal data-slot=\"dropdown-menu-portal\" {...props} />\n}\nDropdownMenuPortal.displayName = \"DropdownMenuPortal\"\n\nfunction DropdownMenuTrigger({ ...props }: React.ComponentProps<typeof DropdownMenuPrimitive.Trigger>) {\n return <DropdownMenuPrimitive.Trigger data-slot=\"dropdown-menu-trigger\" {...props} />\n}\nDropdownMenuTrigger.displayName = \"DropdownMenuTrigger\"\n\nexport interface DropdownMenuContentProps\n extends React.ComponentProps<typeof DropdownMenuPrimitive.Content> {\n variant?: \"default\" | \"breakout\"\n}\n\nconst DropdownMenuContent = React.forwardRef<\n React.ComponentRef<typeof DropdownMenuPrimitive.Content>,\n DropdownMenuContentProps\n>(({ className, align = \"start\", sideOffset = 4, variant = \"default\", ...props }, ref) => (\n <DropdownMenuPrimitive.Portal>\n <DropdownMenuPrimitive.Content\n ref={ref}\n data-slot=\"dropdown-menu-content\"\n sideOffset={sideOffset}\n align={align}\n className={cn(styles.content, variant === \"breakout\" && styles.contentBreakout, className)}\n {...props}\n />\n </DropdownMenuPrimitive.Portal>\n))\nDropdownMenuContent.displayName = \"DropdownMenuContent\"\n\nfunction DropdownMenuGroup({ ...props }: React.ComponentProps<typeof DropdownMenuPrimitive.Group>) {\n return <DropdownMenuPrimitive.Group data-slot=\"dropdown-menu-group\" {...props} />\n}\nDropdownMenuGroup.displayName = \"DropdownMenuGroup\"\n\nexport interface DropdownMenuItemProps\n extends React.ComponentProps<typeof DropdownMenuPrimitive.Item> {\n inset?: boolean\n variant?: \"default\" | \"destructive\"\n}\n\nconst DropdownMenuItem = React.forwardRef<\n React.ComponentRef<typeof DropdownMenuPrimitive.Item>,\n DropdownMenuItemProps\n>(({ className, inset, variant = \"default\", ...props }, ref) => (\n <DropdownMenuPrimitive.Item\n ref={ref}\n data-slot=\"dropdown-menu-item\"\n data-inset={inset}\n data-variant={variant}\n className={cn(\n styles.item,\n variant === \"destructive\" && styles.itemDestructive,\n inset && styles.itemInset,\n className\n )}\n {...props}\n />\n))\nDropdownMenuItem.displayName = \"DropdownMenuItem\"\n\nconst DropdownMenuCheckboxItem = React.forwardRef<\n React.ComponentRef<typeof DropdownMenuPrimitive.CheckboxItem>,\n React.ComponentProps<typeof DropdownMenuPrimitive.CheckboxItem> & { inset?: boolean }\n>(({ className, children, checked, inset, ...props }, ref) => (\n <DropdownMenuPrimitive.CheckboxItem\n ref={ref}\n data-slot=\"dropdown-menu-checkbox-item\"\n data-inset={inset}\n className={cn(styles.checkboxItem, inset && styles.itemInset, className)}\n checked={checked}\n {...props}\n >\n <span className={styles.itemIndicator} data-slot=\"dropdown-menu-checkbox-item-indicator\">\n <DropdownMenuPrimitive.ItemIndicator>\n <CheckIcon />\n </DropdownMenuPrimitive.ItemIndicator>\n </span>\n {children}\n </DropdownMenuPrimitive.CheckboxItem>\n))\nDropdownMenuCheckboxItem.displayName = \"DropdownMenuCheckboxItem\"\n\nfunction DropdownMenuRadioGroup({ ...props }: React.ComponentProps<typeof DropdownMenuPrimitive.RadioGroup>) {\n return <DropdownMenuPrimitive.RadioGroup data-slot=\"dropdown-menu-radio-group\" {...props} />\n}\nDropdownMenuRadioGroup.displayName = \"DropdownMenuRadioGroup\"\n\nconst DropdownMenuRadioItem = React.forwardRef<\n React.ComponentRef<typeof DropdownMenuPrimitive.RadioItem>,\n React.ComponentProps<typeof DropdownMenuPrimitive.RadioItem> & { inset?: boolean }\n>(({ className, children, inset, ...props }, ref) => (\n <DropdownMenuPrimitive.RadioItem\n ref={ref}\n data-slot=\"dropdown-menu-radio-item\"\n data-inset={inset}\n className={cn(styles.radioItem, inset && styles.itemInset, className)}\n {...props}\n >\n <span className={styles.itemIndicator} data-slot=\"dropdown-menu-radio-item-indicator\">\n <DropdownMenuPrimitive.ItemIndicator>\n <CheckIcon />\n </DropdownMenuPrimitive.ItemIndicator>\n </span>\n {children}\n </DropdownMenuPrimitive.RadioItem>\n))\nDropdownMenuRadioItem.displayName = \"DropdownMenuRadioItem\"\n\nconst DropdownMenuLabel = React.forwardRef<\n React.ComponentRef<typeof DropdownMenuPrimitive.Label>,\n React.ComponentProps<typeof DropdownMenuPrimitive.Label> & { inset?: boolean }\n>(({ className, inset, ...props }, ref) => (\n <DropdownMenuPrimitive.Label\n ref={ref}\n data-slot=\"dropdown-menu-label\"\n data-inset={inset}\n className={cn(styles.label, inset && styles.itemInset, className)}\n {...props}\n />\n))\nDropdownMenuLabel.displayName = \"DropdownMenuLabel\"\n\nconst DropdownMenuSeparator = React.forwardRef<\n React.ComponentRef<typeof DropdownMenuPrimitive.Separator>,\n React.ComponentProps<typeof DropdownMenuPrimitive.Separator>\n>(({ className, ...props }, ref) => (\n <DropdownMenuPrimitive.Separator\n ref={ref}\n data-slot=\"dropdown-menu-separator\"\n className={cn(styles.separator, className)}\n {...props}\n />\n))\nDropdownMenuSeparator.displayName = \"DropdownMenuSeparator\"\n\nfunction DropdownMenuShortcut({ className, ...props }: React.ComponentProps<\"span\">) {\n return (\n <span\n data-slot=\"dropdown-menu-shortcut\"\n className={cn(styles.shortcut, className)}\n {...props}\n />\n )\n}\nDropdownMenuShortcut.displayName = \"DropdownMenuShortcut\"\n\nfunction DropdownMenuSub({ ...props }: React.ComponentProps<typeof DropdownMenuPrimitive.Sub>) {\n return <DropdownMenuPrimitive.Sub data-slot=\"dropdown-menu-sub\" {...props} />\n}\nDropdownMenuSub.displayName = \"DropdownMenuSub\"\n\nconst DropdownMenuSubTrigger = React.forwardRef<\n React.ComponentRef<typeof DropdownMenuPrimitive.SubTrigger>,\n React.ComponentProps<typeof DropdownMenuPrimitive.SubTrigger> & { inset?: boolean }\n>(({ className, inset, children, ...props }, ref) => (\n <DropdownMenuPrimitive.SubTrigger\n ref={ref}\n data-slot=\"dropdown-menu-sub-trigger\"\n data-inset={inset}\n className={cn(styles.subTrigger, inset && styles.itemInset, className)}\n {...props}\n >\n {children}\n <CaretRightIcon className={styles.subTriggerIcon} />\n </DropdownMenuPrimitive.SubTrigger>\n))\nDropdownMenuSubTrigger.displayName = \"DropdownMenuSubTrigger\"\n\nexport interface DropdownMenuSubContentProps\n extends React.ComponentProps<typeof DropdownMenuPrimitive.SubContent> {\n variant?: \"default\" | \"breakout\"\n}\n\nconst DropdownMenuSubContent = React.forwardRef<\n React.ComponentRef<typeof DropdownMenuPrimitive.SubContent>,\n DropdownMenuSubContentProps\n>(({ className, variant = \"default\", ...props }, ref) => (\n <DropdownMenuPrimitive.SubContent\n ref={ref}\n data-slot=\"dropdown-menu-sub-content\"\n className={cn(styles.subContent, variant === \"breakout\" && styles.contentBreakout, className)}\n {...props}\n />\n))\nDropdownMenuSubContent.displayName = \"DropdownMenuSubContent\"\n\nexport {\n DropdownMenu,\n DropdownMenuPortal,\n DropdownMenuTrigger,\n DropdownMenuContent,\n DropdownMenuGroup,\n DropdownMenuLabel,\n DropdownMenuItem,\n DropdownMenuCheckboxItem,\n DropdownMenuRadioGroup,\n DropdownMenuRadioItem,\n DropdownMenuSeparator,\n DropdownMenuShortcut,\n DropdownMenuSub,\n DropdownMenuSubTrigger,\n DropdownMenuSubContent,\n}\n"
675
680
  },
676
681
  {
677
682
  "path": "components/ui/dropdown-menu/dropdown-menu.module.css",
678
683
  "type": "registry:ui",
679
- "content": "/* Dropdown menu content */\n.content {\n z-index: 50;\n min-width: 12rem;\n overflow: hidden;\n border-radius: var(--radius-lg, 0.5rem);\n background-color: var(--surface-popover, var(--surface-card, #ffffff));\n color: var(--text-primary, #111827);\n padding: var(--spacing-1, 0.25rem);\n box-shadow: var(--shadow-lg);\n}\n\n.content[data-state=\"open\"] {\n animation: contentShow var(--motion-duration-fast, 100ms) var(--motion-easing-enter, ease-out);\n}\n\n.content[data-state=\"closed\"] {\n animation: contentHide var(--motion-duration-fast, 100ms) var(--motion-easing-exit, ease-in);\n}\n\n/* Sub content */\n.subContent {\n z-index: 50;\n min-width: 9rem;\n overflow: hidden;\n border-radius: var(--radius-lg, 0.5rem);\n background-color: var(--surface-popover, var(--surface-card, #ffffff));\n color: var(--text-primary, #111827);\n padding: var(--spacing-1, 0.25rem);\n box-shadow: var(--shadow-lg);\n}\n\n.subContent[data-state=\"open\"] {\n animation: contentShow var(--motion-duration-fast, 100ms) var(--motion-easing-enter, ease-out);\n}\n\n.subContent[data-state=\"closed\"] {\n animation: contentHide var(--motion-duration-fast, 100ms) var(--motion-easing-exit, ease-in);\n}\n\n/* Menu item */\n.item {\n position: relative;\n display: flex;\n cursor: default;\n user-select: none;\n align-items: center;\n gap: calc(var(--spacing-2, 0.5rem) + var(--spacing-1, 0.25rem) / 2);\n border-radius: var(--radius-md, 0.375rem);\n padding: var(--spacing-2, 0.5rem) var(--spacing-3, 0.75rem);\n font-size: var(--font-size-sm, 0.875rem);\n outline: none;\n transition: background-color var(--motion-duration-fast, 100ms) var(--motion-easing-default, ease-in-out), color var(--motion-duration-fast, 100ms) var(--motion-easing-default, ease-in-out);\n}\n\n.item:focus,\n.item[data-highlighted] {\n background-color: var(--surface-interactive-hover, #f3f4f6);\n color: var(--text-primary, #111827);\n}\n\n.item[data-disabled] {\n pointer-events: none;\n opacity: 0.5;\n}\n\n.itemDestructive {\n color: var(--text-error, #ef4444);\n}\n\n.itemDestructive:focus,\n.itemDestructive[data-highlighted] {\n background-color: var(--surface-error-subtle, rgba(239, 68, 68, 0.1));\n color: var(--text-error, #ef4444);\n}\n\n.itemInset {\n padding-left: calc(var(--spacing-8, 2rem) + var(--spacing-1, 0.25rem) * 1.5);\n}\n\n/* Checkbox and radio items */\n.checkboxItem,\n.radioItem {\n position: relative;\n display: flex;\n cursor: default;\n user-select: none;\n align-items: center;\n gap: calc(var(--spacing-2, 0.5rem) + var(--spacing-1, 0.25rem) / 2);\n border-radius: var(--radius-md, 0.375rem);\n padding: var(--spacing-2, 0.5rem) var(--spacing-3, 0.75rem);\n padding-right: var(--spacing-8, 2rem);\n font-size: var(--font-size-sm, 0.875rem);\n outline: none;\n transition: background-color var(--motion-duration-fast, 100ms) var(--motion-easing-default, ease-in-out), color var(--motion-duration-fast, 100ms) var(--motion-easing-default, ease-in-out);\n}\n\n.checkboxItem:focus,\n.checkboxItem[data-highlighted],\n.radioItem:focus,\n.radioItem[data-highlighted] {\n background-color: var(--surface-interactive-hover, #f3f4f6);\n color: var(--text-primary, #111827);\n}\n\n.checkboxItem[data-disabled],\n.radioItem[data-disabled] {\n pointer-events: none;\n opacity: 0.5;\n}\n\n/* Item indicator */\n.itemIndicator {\n pointer-events: none;\n position: absolute;\n right: 0.5rem;\n display: flex;\n align-items: center;\n justify-content: center;\n width: 1rem;\n height: 1rem;\n}\n\n/* Label */\n.label {\n padding: calc(var(--spacing-2, 0.5rem) + var(--spacing-1, 0.25rem) / 2) var(--spacing-3, 0.75rem);\n font-size: var(--font-size-xs, 0.75rem);\n color: var(--text-secondary, #6b7280);\n}\n\n/* Separator */\n.separator {\n height: 1px;\n margin: var(--spacing-1, 0.25rem) calc(-1 * var(--spacing-1, 0.25rem));\n background-color: var(--border-default, #e5e7eb);\n}\n\n/* Shortcut */\n.shortcut {\n margin-left: auto;\n font-size: var(--font-size-xs, 0.75rem);\n letter-spacing: 0.1em;\n color: var(--text-secondary, #6b7280);\n}\n\n/* Sub trigger */\n.subTrigger {\n display: flex;\n cursor: default;\n user-select: none;\n align-items: center;\n gap: var(--spacing-2, 0.5rem);\n border-radius: var(--radius-md, 0.375rem);\n padding: var(--spacing-2, 0.5rem) var(--spacing-3, 0.75rem);\n font-size: var(--font-size-sm, 0.875rem);\n outline: none;\n transition: background-color var(--motion-duration-fast, 100ms) var(--motion-easing-default, ease-in-out), color var(--motion-duration-fast, 100ms) var(--motion-easing-default, ease-in-out);\n}\n\n.subTrigger:focus,\n.subTrigger[data-state=\"open\"] {\n background-color: var(--surface-interactive-hover, #f3f4f6);\n color: var(--text-primary, #111827);\n}\n\n.subTriggerIcon {\n margin-left: auto;\n width: 1rem;\n height: 1rem;\n}\n\n@keyframes contentShow {\n from {\n opacity: 0;\n transform: scale(0.95);\n }\n to {\n opacity: 1;\n transform: scale(1);\n }\n}\n\n@keyframes contentHide {\n from {\n opacity: 1;\n transform: scale(1);\n }\n to {\n opacity: 0;\n transform: scale(0.95);\n }\n}\n"
684
+ "content": "/* Dropdown menu content */\n.content {\n z-index: 50;\n min-width: 12rem;\n overflow: hidden;\n border-radius: var(--radius-lg, 0.5rem);\n background-color: var(--surface-popover, var(--surface-card, #ffffff));\n color: var(--text-primary, #111827);\n padding: var(--spacing-1, 0.25rem);\n box-shadow: var(--shadow-lg);\n}\n\n.content[data-state=\"open\"] {\n animation: contentShow var(--motion-duration-fast, 100ms) var(--motion-easing-enter, ease-out);\n}\n\n.content[data-state=\"closed\"] {\n animation: contentHide var(--motion-duration-fast, 100ms) var(--motion-easing-exit, ease-in);\n}\n\n/* Breakout variant — use inside scroll-clipped containers (ex: DataTable rows) */\n.contentBreakout {\n z-index: 200;\n box-shadow: var(--shadow-xl, 0 28px 64px rgba(0, 0, 0, 0.55), 0 8px 16px rgba(0, 0, 0, 0.30), 0 0 0 1px rgba(255, 255, 255, 0.06));\n}\n\n/* Sub content */\n.subContent {\n z-index: 50;\n min-width: 9rem;\n overflow: hidden;\n border-radius: var(--radius-lg, 0.5rem);\n background-color: var(--surface-popover, var(--surface-card, #ffffff));\n color: var(--text-primary, #111827);\n padding: var(--spacing-1, 0.25rem);\n box-shadow: var(--shadow-lg);\n}\n\n.subContent[data-state=\"open\"] {\n animation: contentShow var(--motion-duration-fast, 100ms) var(--motion-easing-enter, ease-out);\n}\n\n.subContent[data-state=\"closed\"] {\n animation: contentHide var(--motion-duration-fast, 100ms) var(--motion-easing-exit, ease-in);\n}\n\n/* Menu item */\n.item {\n position: relative;\n display: flex;\n cursor: default;\n user-select: none;\n align-items: center;\n gap: calc(var(--spacing-2, 0.5rem) + var(--spacing-1, 0.25rem) / 2);\n border-radius: var(--radius-md, 0.375rem);\n padding: var(--spacing-2, 0.5rem) var(--spacing-3, 0.75rem);\n font-size: var(--font-size-sm, 0.875rem);\n outline: none;\n transition: background-color var(--motion-duration-fast, 100ms) var(--motion-easing-default, ease-in-out), color var(--motion-duration-fast, 100ms) var(--motion-easing-default, ease-in-out);\n}\n\n.item:focus,\n.item[data-highlighted] {\n background-color: var(--surface-interactive-hover, #f3f4f6);\n color: var(--text-primary, #111827);\n}\n\n.item[data-disabled] {\n pointer-events: none;\n opacity: 0.5;\n}\n\n.itemDestructive {\n color: var(--text-error, #ef4444);\n}\n\n.itemDestructive:focus,\n.itemDestructive[data-highlighted] {\n background-color: var(--surface-error-subtle, rgba(239, 68, 68, 0.1));\n color: var(--text-error, #ef4444);\n}\n\n.itemInset {\n padding-left: calc(var(--spacing-8, 2rem) + var(--spacing-1, 0.25rem) * 1.5);\n}\n\n/* Checkbox and radio items */\n.checkboxItem,\n.radioItem {\n position: relative;\n display: flex;\n cursor: default;\n user-select: none;\n align-items: center;\n gap: calc(var(--spacing-2, 0.5rem) + var(--spacing-1, 0.25rem) / 2);\n border-radius: var(--radius-md, 0.375rem);\n padding: var(--spacing-2, 0.5rem) var(--spacing-3, 0.75rem);\n padding-right: var(--spacing-8, 2rem);\n font-size: var(--font-size-sm, 0.875rem);\n outline: none;\n transition: background-color var(--motion-duration-fast, 100ms) var(--motion-easing-default, ease-in-out), color var(--motion-duration-fast, 100ms) var(--motion-easing-default, ease-in-out);\n}\n\n.checkboxItem:focus,\n.checkboxItem[data-highlighted],\n.radioItem:focus,\n.radioItem[data-highlighted] {\n background-color: var(--surface-interactive-hover, #f3f4f6);\n color: var(--text-primary, #111827);\n}\n\n.checkboxItem[data-disabled],\n.radioItem[data-disabled] {\n pointer-events: none;\n opacity: 0.5;\n}\n\n/* Item indicator */\n.itemIndicator {\n pointer-events: none;\n position: absolute;\n right: 0.5rem;\n display: flex;\n align-items: center;\n justify-content: center;\n width: 1rem;\n height: 1rem;\n}\n\n/* Label */\n.label {\n padding: calc(var(--spacing-2, 0.5rem) + var(--spacing-1, 0.25rem) / 2) var(--spacing-3, 0.75rem);\n font-size: var(--font-size-xs, 0.75rem);\n color: var(--text-secondary, #6b7280);\n}\n\n/* Separator */\n.separator {\n height: 1px;\n margin: var(--spacing-1, 0.25rem) calc(-1 * var(--spacing-1, 0.25rem));\n background-color: var(--border-default, #e5e7eb);\n}\n\n/* Shortcut */\n.shortcut {\n margin-left: auto;\n font-size: var(--font-size-xs, 0.75rem);\n letter-spacing: 0.1em;\n color: var(--text-secondary, #6b7280);\n}\n\n/* Sub trigger */\n.subTrigger {\n display: flex;\n cursor: default;\n user-select: none;\n align-items: center;\n gap: var(--spacing-2, 0.5rem);\n border-radius: var(--radius-md, 0.375rem);\n padding: var(--spacing-2, 0.5rem) var(--spacing-3, 0.75rem);\n font-size: var(--font-size-sm, 0.875rem);\n outline: none;\n transition: background-color var(--motion-duration-fast, 100ms) var(--motion-easing-default, ease-in-out), color var(--motion-duration-fast, 100ms) var(--motion-easing-default, ease-in-out);\n}\n\n.subTrigger:focus,\n.subTrigger[data-state=\"open\"] {\n background-color: var(--surface-interactive-hover, #f3f4f6);\n color: var(--text-primary, #111827);\n}\n\n.subTriggerIcon {\n margin-left: auto;\n width: 1rem;\n height: 1rem;\n}\n\n@keyframes contentShow {\n from {\n opacity: 0;\n transform: scale(0.95);\n }\n to {\n opacity: 1;\n transform: scale(1);\n }\n}\n\n@keyframes contentHide {\n from {\n opacity: 1;\n transform: scale(1);\n }\n to {\n opacity: 0;\n transform: scale(0.95);\n }\n}\n"
680
685
  }
681
686
  ]
682
687
  },
@@ -697,12 +702,12 @@
697
702
  {
698
703
  "path": "components/ui/tabs/tabs.tsx",
699
704
  "type": "registry:ui",
700
- "content": "\"use client\"\n\nimport * as React from \"react\"\nimport * as TabsPrimitive from \"@radix-ui/react-tabs\"\nimport { cva, type VariantProps } from \"class-variance-authority\"\nimport { cn } from \"../../../lib/utils\"\nimport styles from \"./tabs.module.css\"\n\nconst Tabs = React.forwardRef<\n React.ComponentRef<typeof TabsPrimitive.Root>,\n React.ComponentProps<typeof TabsPrimitive.Root>\n>(({ className, ...props }, ref) => (\n <TabsPrimitive.Root\n ref={ref}\n data-slot=\"tabs\"\n className={cn(styles.root, className)}\n {...props}\n />\n))\nTabs.displayName = \"Tabs\"\n\nconst tabsListVariants = cva(styles.list, {\n variants: {\n variant: {\n default: styles.listVariantDefault,\n line: styles.listVariantLine,\n },\n },\n defaultVariants: {\n variant: \"default\",\n },\n})\n\nexport interface TabsListProps\n extends React.ComponentProps<typeof TabsPrimitive.List>,\n VariantProps<typeof tabsListVariants> {}\n\nconst TabsList = React.forwardRef<\n React.ComponentRef<typeof TabsPrimitive.List>,\n TabsListProps\n>(({ className, variant = \"default\", children, ...props }, ref) => {\n const internalRef = React.useRef<HTMLDivElement>(null)\n const [indicatorStyle, setIndicatorStyle] = React.useState<{\n left: number\n width: number\n } | null>(null)\n\n // Merge forwarded ref with internal ref\n const mergedRef = React.useCallback(\n (node: HTMLDivElement | null) => {\n internalRef.current = node\n if (typeof ref === \"function\") {\n ref(node)\n } else if (ref) {\n ref.current = node\n }\n },\n [ref]\n )\n\n const updateIndicator = React.useCallback(() => {\n if (variant !== \"line\" || !internalRef.current) return\n const activeTab = internalRef.current.querySelector<HTMLElement>(\n '[data-state=\"active\"]'\n )\n if (activeTab) {\n setIndicatorStyle({\n left: activeTab.offsetLeft,\n width: activeTab.offsetWidth,\n })\n }\n }, [variant])\n\n React.useEffect(() => {\n if (variant !== \"line\" || !internalRef.current) return\n updateIndicator()\n\n const observer = new MutationObserver(updateIndicator)\n observer.observe(internalRef.current, {\n attributes: true,\n attributeFilter: [\"data-state\"],\n subtree: true,\n })\n\n window.addEventListener(\"resize\", updateIndicator)\n return () => {\n observer.disconnect()\n window.removeEventListener(\"resize\", updateIndicator)\n }\n }, [variant, updateIndicator])\n\n return (\n <TabsPrimitive.List\n ref={mergedRef}\n data-slot=\"tabs-list\"\n data-variant={variant}\n className={cn(tabsListVariants({ variant }), className)}\n {...props}\n >\n {children}\n {variant === \"line\" && indicatorStyle && (\n <span\n className={styles.indicator}\n style={{\n left: indicatorStyle.left,\n width: indicatorStyle.width,\n }}\n />\n )}\n </TabsPrimitive.List>\n )\n})\nTabsList.displayName = \"TabsList\"\n\nconst TabsTrigger = React.forwardRef<\n React.ComponentRef<typeof TabsPrimitive.Trigger>,\n React.ComponentProps<typeof TabsPrimitive.Trigger>\n>(({ className, ...props }, ref) => (\n <TabsPrimitive.Trigger\n ref={ref}\n data-slot=\"tabs-trigger\"\n className={cn(styles.trigger, className)}\n {...props}\n />\n))\nTabsTrigger.displayName = \"TabsTrigger\"\n\nconst TabsContent = React.forwardRef<\n React.ComponentRef<typeof TabsPrimitive.Content>,\n React.ComponentProps<typeof TabsPrimitive.Content>\n>(({ className, ...props }, ref) => (\n <TabsPrimitive.Content\n ref={ref}\n data-slot=\"tabs-content\"\n className={cn(styles.content, className)}\n {...props}\n />\n))\nTabsContent.displayName = \"TabsContent\"\n\nexport { Tabs, TabsList, TabsTrigger, TabsContent, tabsListVariants }\n"
705
+ "content": "\"use client\"\n\nimport * as React from \"react\"\nimport * as TabsPrimitive from \"@radix-ui/react-tabs\"\nimport { cva, type VariantProps } from \"class-variance-authority\"\nimport { cn } from \"../../../lib/utils\"\nimport styles from \"./tabs.module.css\"\n\nconst Tabs = React.forwardRef<\n React.ComponentRef<typeof TabsPrimitive.Root>,\n React.ComponentProps<typeof TabsPrimitive.Root>\n>(({ className, ...props }, ref) => (\n <TabsPrimitive.Root\n ref={ref}\n data-slot=\"tabs\"\n className={cn(styles.root, className)}\n {...props}\n />\n))\nTabs.displayName = \"Tabs\"\n\nconst tabsListVariants = cva(styles.list, {\n variants: {\n variant: {\n default: styles.listVariantDefault,\n line: styles.listVariantLine,\n },\n },\n defaultVariants: {\n variant: \"default\",\n },\n})\n\nexport interface TabsListProps\n extends React.ComponentProps<typeof TabsPrimitive.List>,\n VariantProps<typeof tabsListVariants> {}\n\nconst TabsList = React.forwardRef<\n React.ComponentRef<typeof TabsPrimitive.List>,\n TabsListProps\n>(({ className, variant = \"default\", children, ...props }, ref) => {\n const internalRef = React.useRef<HTMLDivElement>(null)\n const [indicatorStyle, setIndicatorStyle] = React.useState<{\n left: number\n width: number\n } | null>(null)\n\n // Merge forwarded ref with internal ref\n const mergedRef = React.useCallback(\n (node: HTMLDivElement | null) => {\n internalRef.current = node\n if (typeof ref === \"function\") {\n ref(node)\n } else if (ref) {\n ref.current = node\n }\n },\n [ref]\n )\n\n const updateIndicator = React.useCallback(() => {\n if (variant !== \"line\" || !internalRef.current) return\n const activeTab = internalRef.current.querySelector<HTMLElement>(\n '[data-state=\"active\"]'\n )\n if (activeTab) {\n setIndicatorStyle({\n left: activeTab.offsetLeft,\n width: activeTab.offsetWidth,\n })\n }\n }, [variant])\n\n React.useEffect(() => {\n if (variant !== \"line\" || !internalRef.current) return\n updateIndicator()\n\n const observer = new MutationObserver(updateIndicator)\n observer.observe(internalRef.current, {\n attributes: true,\n attributeFilter: [\"data-state\"],\n subtree: true,\n })\n\n window.addEventListener(\"resize\", updateIndicator)\n return () => {\n observer.disconnect()\n window.removeEventListener(\"resize\", updateIndicator)\n }\n }, [variant, updateIndicator])\n\n return (\n <TabsPrimitive.List\n ref={mergedRef}\n data-slot=\"tabs-list\"\n data-variant={variant}\n className={cn(tabsListVariants({ variant }), className)}\n {...props}\n >\n {children}\n {variant === \"line\" && indicatorStyle && (\n <span\n className={styles.indicator}\n style={{\n left: indicatorStyle.left,\n width: indicatorStyle.width,\n }}\n />\n )}\n </TabsPrimitive.List>\n )\n})\nTabsList.displayName = \"TabsList\"\n\nexport interface TabsTriggerProps\n extends React.ComponentProps<typeof TabsPrimitive.Trigger> {\n /** Inline count pill rendered after the label. Accepts strings, numbers, or elements. */\n count?: React.ReactNode\n /** Visual tone of the count pill. Defaults to \"neutral\". Active state re-tones automatically. */\n countTone?: \"primary\" | \"neutral\"\n}\n\nconst TabsTrigger = React.forwardRef<\n React.ComponentRef<typeof TabsPrimitive.Trigger>,\n TabsTriggerProps\n>(({ className, children, count, countTone = \"neutral\", ...props }, ref) => (\n <TabsPrimitive.Trigger\n ref={ref}\n data-slot=\"tabs-trigger\"\n className={cn(styles.trigger, className)}\n {...props}\n >\n <span className={styles.label}>{children}</span>\n {count != null && (\n <span\n className={cn(\n styles.count,\n countTone === \"primary\" ? styles.countPrimary : styles.countNeutral,\n )}\n data-slot=\"tabs-trigger-count\"\n data-tone={countTone}\n aria-hidden=\"false\"\n >\n {count}\n </span>\n )}\n </TabsPrimitive.Trigger>\n))\nTabsTrigger.displayName = \"TabsTrigger\"\n\nconst TabsContent = React.forwardRef<\n React.ComponentRef<typeof TabsPrimitive.Content>,\n React.ComponentProps<typeof TabsPrimitive.Content>\n>(({ className, ...props }, ref) => (\n <TabsPrimitive.Content\n ref={ref}\n data-slot=\"tabs-content\"\n className={cn(styles.content, className)}\n {...props}\n />\n))\nTabsContent.displayName = \"TabsContent\"\n\nexport { Tabs, TabsList, TabsTrigger, TabsContent, tabsListVariants }\n"
701
706
  },
702
707
  {
703
708
  "path": "components/ui/tabs/tabs.module.css",
704
709
  "type": "registry:ui",
705
- "content": "/* Tabs root */\n.root {\n display: flex;\n flex-direction: column;\n gap: var(--spacing-2, 0.5rem);\n}\n\n/* Tabs list */\n.list {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n border-radius: var(--radius-full, 9999px);\n padding: calc(var(--spacing-1, 0.25rem) * 0.75);\n color: var(--text-secondary, #6b7280);\n height: 2.25rem;\n width: fit-content;\n}\n\n.listVariantDefault {\n background-color: var(--surface-muted, #f3f4f6);\n}\n\n.listVariantLine {\n position: relative;\n gap: var(--spacing-1, 0.25rem);\n background-color: transparent;\n border-radius: 0;\n border-bottom: 1px solid var(--border-default, #e5e7eb);\n height: auto;\n padding-bottom: 0;\n}\n\n/* Tabs trigger */\n.trigger {\n position: relative;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n gap: calc(var(--spacing-1, 0.25rem) * 1.5);\n border-radius: var(--radius-md, 0.375rem);\n border: 1px solid transparent;\n padding: var(--spacing-1, 0.25rem) var(--spacing-2, 0.5rem);\n font-size: var(--font-size-sm, 0.875rem);\n font-weight: var(--font-weight-medium, 500);\n white-space: nowrap;\n color: var(--text-secondary, #6b7280);\n background: transparent;\n cursor: pointer;\n transition: color var(--motion-duration-150, 150ms) var(--motion-easing-default, ease-in-out), background-color var(--motion-duration-150, 150ms) var(--motion-easing-default, ease-in-out), border-color var(--motion-duration-150, 150ms) var(--motion-easing-default, ease-in-out), transform var(--motion-duration-150, 150ms) var(--motion-easing-default, ease-in-out);\n outline: none;\n flex: 1;\n height: calc(100% - 2px);\n}\n\n.trigger:active:not(:disabled) {\n transform: translateY(1px);\n transition: none;\n}\n\n@media (hover: hover) {\n .trigger:hover {\n color: var(--text-primary, #111827);\n }\n}\n\n.trigger:focus-visible {\n outline: var(--focus-ring-width, 2px) solid var(--border-focus, currentColor);\n outline-offset: var(--focus-ring-offset, 2px);\n}\n\n.trigger:disabled {\n pointer-events: none;\n opacity: 0.5;\n}\n\n.trigger[data-state=\"active\"] {\n background-color: var(--surface-page, #ffffff);\n color: var(--text-primary, #111827);\n box-shadow: var(--shadow-sm);\n}\n\n/* Tabs content */\n.content {\n flex: 1;\n font-size: var(--font-size-sm, 0.875rem);\n outline: none;\n}\n\n.content:focus-visible {\n outline: var(--focus-ring-width, 2px) solid var(--border-focus, currentColor);\n outline-offset: var(--focus-ring-offset, 2px);\n}\n\n/* Line variant: active trigger loses shadow/bg, just text color */\n.listVariantLine .trigger[data-state=\"active\"] {\n background-color: transparent;\n box-shadow: none;\n}\n\n/* Animated sliding indicator for line variant */\n.indicator {\n position: absolute;\n bottom: -1px;\n height: 2px;\n background-color: var(--tabs-indicator-color, var(--text-primary, #111827));\n border-radius: var(--radius-full, 9999px);\n transition: left var(--motion-duration-normal, 200ms) var(--motion-easing-default, ease-in-out),\n width var(--motion-duration-normal, 200ms) var(--motion-easing-default, ease-in-out);\n}\n"
710
+ "content": "/* Tabs root */\n.root {\n display: flex;\n flex-direction: column;\n gap: var(--spacing-2, 0.5rem);\n}\n\n/* Tabs list */\n.list {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n border-radius: var(--radius-full, 9999px);\n padding: calc(var(--spacing-1, 0.25rem) * 0.75);\n color: var(--text-secondary, #6b7280);\n height: 2.25rem;\n width: fit-content;\n}\n\n.listVariantDefault {\n background-color: var(--surface-muted, #f3f4f6);\n}\n\n.listVariantLine {\n position: relative;\n gap: var(--spacing-1, 0.25rem);\n background-color: transparent;\n border-radius: 0;\n border-bottom: 1px solid var(--border-default, #e5e7eb);\n height: auto;\n padding-bottom: 0;\n}\n\n/* Tabs trigger */\n.trigger {\n position: relative;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n gap: calc(var(--spacing-1, 0.25rem) * 1.5);\n border-radius: var(--radius-md, 0.375rem);\n border: 1px solid transparent;\n padding: var(--spacing-1, 0.25rem) var(--spacing-2, 0.5rem);\n font-size: var(--font-size-sm, 0.875rem);\n font-weight: var(--font-weight-medium, 500);\n white-space: nowrap;\n color: var(--text-secondary, #6b7280);\n background: transparent;\n cursor: pointer;\n transition: color var(--motion-duration-150, 150ms) var(--motion-easing-default, ease-in-out), background-color var(--motion-duration-150, 150ms) var(--motion-easing-default, ease-in-out), border-color var(--motion-duration-150, 150ms) var(--motion-easing-default, ease-in-out), transform var(--motion-duration-150, 150ms) var(--motion-easing-default, ease-in-out);\n outline: none;\n flex: 1;\n height: calc(100% - 2px);\n}\n\n.trigger:active:not(:disabled) {\n transform: translateY(1px);\n transition: none;\n}\n\n@media (hover: hover) {\n .trigger:hover {\n color: var(--text-primary, #111827);\n }\n}\n\n.trigger:focus-visible {\n outline: var(--focus-ring-width, 2px) solid var(--border-focus, currentColor);\n outline-offset: var(--focus-ring-offset, 2px);\n}\n\n.trigger:disabled {\n pointer-events: none;\n opacity: 0.5;\n}\n\n.trigger[data-state=\"active\"] {\n background-color: var(--surface-page, #ffffff);\n color: var(--text-primary, #111827);\n box-shadow: var(--shadow-sm);\n}\n\n/* Trigger label — wraps children to allow count pill alongside */\n.label {\n flex: 1 1 auto;\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n/* Count pill */\n.count {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n border-radius: var(--radius-full, 9999px);\n padding: 0 var(--spacing-2, 0.5rem);\n font-size: var(--font-size-xs, 0.75rem);\n font-weight: var(--font-weight-medium, 500);\n font-variant-numeric: tabular-nums;\n line-height: 1.5;\n vertical-align: baseline;\n}\n\n.countNeutral {\n background-color: var(--surface-muted, #f3f4f6);\n color: var(--text-secondary, #6b7280);\n}\n\n.countPrimary {\n background-color: var(--surface-accent-subtle, #eff6ff);\n color: var(--text-link, #2563eb);\n}\n\n/* Active-state re-tone: regardless of countTone, re-tone to primary on active */\n.trigger[data-state=\"active\"] .count {\n background-color: var(--surface-accent-subtle, #eff6ff);\n color: var(--text-link, #2563eb);\n}\n\n/* Tabs content */\n.content {\n flex: 1;\n font-size: var(--font-size-sm, 0.875rem);\n outline: none;\n}\n\n.content:focus-visible {\n outline: var(--focus-ring-width, 2px) solid var(--border-focus, currentColor);\n outline-offset: var(--focus-ring-offset, 2px);\n}\n\n/* Line variant: active trigger loses shadow/bg, just text color */\n.listVariantLine .trigger[data-state=\"active\"] {\n background-color: transparent;\n box-shadow: none;\n}\n\n/* Animated sliding indicator for line variant */\n.indicator {\n position: absolute;\n bottom: -1px;\n height: 2px;\n background-color: var(--tabs-indicator-color, var(--text-primary, #111827));\n border-radius: var(--radius-full, 9999px);\n transition: left var(--motion-duration-normal, 200ms) var(--motion-easing-default, ease-in-out),\n width var(--motion-duration-normal, 200ms) var(--motion-easing-default, ease-in-out);\n}\n"
706
711
  }
707
712
  ]
708
713
  },
@@ -840,6 +845,7 @@
840
845
  "category": "feedback",
841
846
  "dependencies": [
842
847
  "@radix-ui/react-popover",
848
+ "@phosphor-icons/react",
843
849
  "@loworbitstudio/visor-core"
844
850
  ],
845
851
  "registryDependencies": [
@@ -849,12 +855,12 @@
849
855
  {
850
856
  "path": "components/ui/popover/popover.tsx",
851
857
  "type": "registry:ui",
852
- "content": "\"use client\"\n\nimport * as React from \"react\"\nimport * as PopoverPrimitive from \"@radix-ui/react-popover\"\nimport { cn } from \"../../../lib/utils\"\nimport styles from \"./popover.module.css\"\n\nfunction Popover({ ...props }: React.ComponentProps<typeof PopoverPrimitive.Root>) {\n return <PopoverPrimitive.Root data-slot=\"popover\" {...props} />\n}\nPopover.displayName = \"Popover\"\n\nfunction PopoverTrigger({ ...props }: React.ComponentProps<typeof PopoverPrimitive.Trigger>) {\n return <PopoverPrimitive.Trigger data-slot=\"popover-trigger\" {...props} />\n}\nPopoverTrigger.displayName = \"PopoverTrigger\"\n\nfunction PopoverAnchor({ ...props }: React.ComponentProps<typeof PopoverPrimitive.Anchor>) {\n return <PopoverPrimitive.Anchor data-slot=\"popover-anchor\" {...props} />\n}\nPopoverAnchor.displayName = \"PopoverAnchor\"\n\nconst PopoverContent = React.forwardRef<\n React.ComponentRef<typeof PopoverPrimitive.Content>,\n React.ComponentProps<typeof PopoverPrimitive.Content>\n>(({ className, align = \"center\", sideOffset = 4, ...props }, ref) => (\n <PopoverPrimitive.Portal>\n <PopoverPrimitive.Content\n ref={ref}\n data-slot=\"popover-content\"\n align={align}\n sideOffset={sideOffset}\n className={cn(styles.content, className)}\n {...props}\n />\n </PopoverPrimitive.Portal>\n))\nPopoverContent.displayName = \"PopoverContent\"\n\nexport { Popover, PopoverTrigger, PopoverContent, PopoverAnchor }\n"
858
+ "content": "\"use client\"\n\nimport * as React from \"react\"\nimport * as PopoverPrimitive from \"@radix-ui/react-popover\"\nimport { CheckIcon } from \"@phosphor-icons/react\"\nimport { cn } from \"../../../lib/utils\"\nimport styles from \"./popover.module.css\"\n\nfunction Popover({ ...props }: React.ComponentProps<typeof PopoverPrimitive.Root>) {\n return <PopoverPrimitive.Root data-slot=\"popover\" {...props} />\n}\nPopover.displayName = \"Popover\"\n\nfunction PopoverTrigger({ ...props }: React.ComponentProps<typeof PopoverPrimitive.Trigger>) {\n return <PopoverPrimitive.Trigger data-slot=\"popover-trigger\" {...props} />\n}\nPopoverTrigger.displayName = \"PopoverTrigger\"\n\nfunction PopoverAnchor({ ...props }: React.ComponentProps<typeof PopoverPrimitive.Anchor>) {\n return <PopoverPrimitive.Anchor data-slot=\"popover-anchor\" {...props} />\n}\nPopoverAnchor.displayName = \"PopoverAnchor\"\n\nconst PopoverContent = React.forwardRef<\n React.ComponentRef<typeof PopoverPrimitive.Content>,\n React.ComponentProps<typeof PopoverPrimitive.Content>\n>(({ className, align = \"center\", sideOffset = 4, ...props }, ref) => (\n <PopoverPrimitive.Portal>\n <PopoverPrimitive.Content\n ref={ref}\n data-slot=\"popover-content\"\n align={align}\n sideOffset={sideOffset}\n className={cn(styles.content, className)}\n {...props}\n />\n </PopoverPrimitive.Portal>\n))\nPopoverContent.displayName = \"PopoverContent\"\n\nfunction PopoverFooter({ className, ...props }: React.ComponentProps<\"div\">) {\n return <div data-slot=\"popover-footer\" className={cn(styles.footer, className)} {...props} />\n}\nPopoverFooter.displayName = \"PopoverFooter\"\n\n// ─── SelectionList Context ───────────────────────────────────────────────────\n\ninterface SelectionListContextValue {\n mode: \"checkbox\" | \"radio\"\n itemRefs: React.MutableRefObject<(HTMLDivElement | null)[]>\n registerItem: (index: number, el: HTMLDivElement | null) => void\n focusedIndex: number\n setFocusedIndex: (index: number) => void\n itemCount: React.MutableRefObject<number>\n}\n\nconst SelectionListContext = React.createContext<SelectionListContextValue | null>(null)\n\nfunction useSelectionList() {\n const ctx = React.useContext(SelectionListContext)\n if (!ctx) throw new Error(\"PopoverSelectionItem must be used inside PopoverSelectionList\")\n return ctx\n}\n\n// ─── PopoverSelectionLabel ───────────────────────────────────────────────────\n\nexport type PopoverSelectionLabelProps = React.ComponentProps<\"div\">\n\nfunction PopoverSelectionLabel({ className, ...props }: PopoverSelectionLabelProps) {\n return (\n <div\n data-slot=\"popover-selection-label\"\n className={cn(styles.selectionLabel, className)}\n {...props}\n />\n )\n}\nPopoverSelectionLabel.displayName = \"PopoverSelectionLabel\"\n\n// ─── PopoverSelectionList ────────────────────────────────────────────────────\n\nexport interface PopoverSelectionListProps extends React.ComponentProps<\"div\"> {\n mode?: \"checkbox\" | \"radio\"\n \"aria-label\"?: string\n}\n\nfunction PopoverSelectionList({\n mode = \"checkbox\",\n className,\n children,\n \"aria-label\": ariaLabel,\n ...props\n}: PopoverSelectionListProps) {\n const itemRefs = React.useRef<(HTMLDivElement | null)[]>([])\n const itemCount = React.useRef(0)\n const [focusedIndex, setFocusedIndex] = React.useState(0)\n // Mirror focusedIndex in a ref so keyDown handler always reads the latest value\n const focusedIndexRef = React.useRef(0)\n\n const setFocusedIndexBoth = React.useCallback((index: number) => {\n focusedIndexRef.current = index\n setFocusedIndex(index)\n }, [])\n\n const registerItem = React.useCallback((index: number, el: HTMLDivElement | null) => {\n itemRefs.current[index] = el\n }, [])\n\n const handleKeyDown = React.useCallback(\n (e: React.KeyboardEvent<HTMLDivElement>) => {\n const total = itemCount.current\n if (total === 0) return\n\n const enabledIndices = itemRefs.current\n .slice(0, total)\n .map((el, i) => (el && el.getAttribute(\"aria-disabled\") !== \"true\" ? i : -1))\n .filter((i) => i !== -1)\n\n // Use ref for synchronous latest value\n const currentFocused = focusedIndexRef.current\n const currentEnabledPos = enabledIndices.indexOf(currentFocused)\n\n let nextIndex: number | null = null\n\n if (e.key === \"ArrowDown\") {\n e.preventDefault()\n const next = enabledIndices[(currentEnabledPos + 1) % enabledIndices.length]\n nextIndex = next ?? enabledIndices[0]\n } else if (e.key === \"ArrowUp\") {\n e.preventDefault()\n const prev =\n enabledIndices[(currentEnabledPos - 1 + enabledIndices.length) % enabledIndices.length]\n nextIndex = prev ?? enabledIndices[enabledIndices.length - 1]\n } else if (e.key === \"Home\") {\n e.preventDefault()\n nextIndex = enabledIndices[0]\n } else if (e.key === \"End\") {\n e.preventDefault()\n nextIndex = enabledIndices[enabledIndices.length - 1]\n } else if (e.key === \"Enter\" || e.key === \" \") {\n e.preventDefault()\n const el = itemRefs.current[currentFocused]\n if (el && el.getAttribute(\"aria-disabled\") !== \"true\") {\n el.click()\n }\n }\n\n if (nextIndex !== null) {\n setFocusedIndexBoth(nextIndex)\n itemRefs.current[nextIndex]?.focus()\n }\n },\n [setFocusedIndexBoth]\n )\n\n const ctxValue = React.useMemo(\n () => ({ mode, itemRefs, registerItem, focusedIndex, setFocusedIndex: setFocusedIndexBoth, itemCount }),\n [mode, registerItem, focusedIndex, setFocusedIndexBoth]\n )\n\n return (\n <SelectionListContext.Provider value={ctxValue}>\n <div\n data-slot=\"popover-selection-list\"\n role=\"listbox\"\n aria-label={ariaLabel}\n aria-multiselectable={mode === \"checkbox\" ? true : undefined}\n className={cn(styles.selectionList, className)}\n onKeyDown={handleKeyDown}\n {...props}\n >\n {children}\n </div>\n </SelectionListContext.Provider>\n )\n}\nPopoverSelectionList.displayName = \"PopoverSelectionList\"\n\n// ─── PopoverSelectionItem ────────────────────────────────────────────────────\n\nexport interface PopoverSelectionItemProps extends Omit<React.ComponentProps<\"div\">, \"onSelect\"> {\n selected?: boolean\n onSelect?: (next: boolean) => void\n disabled?: boolean\n count?: number | string\n leadingIcon?: React.ReactNode\n}\n\nconst PopoverSelectionItem = React.forwardRef<HTMLDivElement, PopoverSelectionItemProps>(\n (\n { selected = false, onSelect, disabled = false, count, leadingIcon, className, children, ...props },\n forwardedRef\n ) => {\n const { mode, registerItem, setFocusedIndex, itemCount, focusedIndex } = useSelectionList()\n\n // Assign a stable index per item via a ref\n const indexRef = React.useRef<number>(-1)\n const localRef = React.useRef<HTMLDivElement | null>(null)\n\n // Combine forwarded ref + local ref\n const ref = React.useCallback(\n (el: HTMLDivElement | null) => {\n localRef.current = el\n if (typeof forwardedRef === \"function\") forwardedRef(el)\n else if (forwardedRef) forwardedRef.current = el\n },\n [forwardedRef]\n )\n\n // Register on mount — assign next available index\n React.useLayoutEffect(() => {\n const index = itemCount.current++\n indexRef.current = index\n registerItem(index, localRef.current)\n return () => {\n registerItem(index, null)\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [])\n\n // Keep registration in sync when el changes\n React.useLayoutEffect(() => {\n if (indexRef.current >= 0) {\n registerItem(indexRef.current, localRef.current)\n }\n })\n\n const isTabStop = !disabled && indexRef.current === focusedIndex\n\n function handleClick() {\n if (disabled) return\n setFocusedIndex(indexRef.current)\n onSelect?.(!selected)\n }\n\n function handleFocus() {\n if (!disabled) setFocusedIndex(indexRef.current)\n }\n\n return (\n <div\n ref={ref}\n data-slot=\"popover-selection-item\"\n role=\"option\"\n aria-selected={selected}\n aria-disabled={disabled || undefined}\n tabIndex={isTabStop ? 0 : -1}\n className={cn(\n styles.selectionItem,\n selected && styles.selectionItemSelected,\n disabled && styles.selectionItemDisabled,\n className\n )}\n onClick={handleClick}\n onFocus={handleFocus}\n {...props}\n >\n {leadingIcon && (\n <span className={styles.selectionItemLeadingIcon} aria-hidden=\"true\">\n {leadingIcon}\n </span>\n )}\n <span\n className={cn(\n styles.selectionIndicator,\n mode === \"radio\" ? styles.selectionIndicatorRadio : styles.selectionIndicatorCheckbox,\n selected && styles.selectionIndicatorSelected\n )}\n aria-hidden=\"true\"\n >\n {mode === \"checkbox\" && selected && <CheckIcon weight=\"bold\" />}\n {mode === \"radio\" && selected && <span className={styles.selectionRadioDot} />}\n </span>\n <span className={styles.selectionItemLabel}>{children}</span>\n {count !== undefined && (\n <span className={styles.selectionCount} aria-hidden=\"true\">\n {count}\n </span>\n )}\n </div>\n )\n }\n)\nPopoverSelectionItem.displayName = \"PopoverSelectionItem\"\n\nexport {\n Popover,\n PopoverTrigger,\n PopoverContent,\n PopoverAnchor,\n PopoverFooter,\n PopoverSelectionList,\n PopoverSelectionItem,\n PopoverSelectionLabel,\n}\n"
853
859
  },
854
860
  {
855
861
  "path": "components/ui/popover/popover.module.css",
856
862
  "type": "registry:ui",
857
- "content": "/* Popover content */\n.content {\n z-index: 50;\n min-width: 12rem;\n overflow: hidden;\n border-radius: var(--radius-lg, 0.5rem);\n background-color: var(--surface-popover, var(--surface-card, #ffffff));\n color: var(--text-primary, #111827);\n padding: var(--spacing-4, 1rem);\n box-shadow: var(--shadow-lg);\n}\n\n.content[data-state=\"open\"] {\n animation: contentShow var(--motion-duration-fast, 100ms) var(--motion-easing-enter, ease-out);\n}\n\n.content[data-state=\"closed\"] {\n animation: contentHide var(--motion-duration-fast, 100ms) var(--motion-easing-exit, ease-in);\n}\n\n@keyframes contentShow {\n from {\n opacity: 0;\n transform: scale(0.95);\n }\n to {\n opacity: 1;\n transform: scale(1);\n }\n}\n\n@keyframes contentHide {\n from {\n opacity: 1;\n transform: scale(1);\n }\n to {\n opacity: 0;\n transform: scale(0.95);\n }\n}\n"
863
+ "content": "/* Popover content */\n.content {\n z-index: 50;\n min-width: 12rem;\n overflow: hidden;\n border-radius: var(--radius-lg, 0.5rem);\n background-color: var(--surface-popover, var(--surface-card, #ffffff));\n color: var(--text-primary, #111827);\n padding: var(--spacing-4, 1rem);\n box-shadow: var(--shadow-lg);\n}\n\n/* Footer — right-aligned action row separated from the body by a top border.\n Negative horizontal margins let the border span the full popover width while\n the action row stays aligned with body content (offsets PopoverContent's\n padding: var(--spacing-4)). */\n.footer {\n display: flex;\n flex-direction: row;\n justify-content: flex-end;\n gap: var(--spacing-2, 0.5rem);\n margin-top: var(--spacing-3, 0.75rem);\n padding-top: var(--spacing-3, 0.75rem);\n margin-inline: calc(-1 * var(--spacing-4, 1rem));\n padding-inline: var(--spacing-4, 1rem);\n border-top: 1px solid var(--border-default, #e5e7eb);\n}\n\n.content[data-state=\"open\"] {\n animation: contentShow var(--motion-duration-fast, 100ms) var(--motion-easing-enter, ease-out);\n}\n\n.content[data-state=\"closed\"] {\n animation: contentHide var(--motion-duration-fast, 100ms) var(--motion-easing-exit, ease-in);\n}\n\n@keyframes contentShow {\n from {\n opacity: 0;\n transform: scale(0.95);\n }\n to {\n opacity: 1;\n transform: scale(1);\n }\n}\n\n@keyframes contentHide {\n from {\n opacity: 1;\n transform: scale(1);\n }\n to {\n opacity: 0;\n transform: scale(0.95);\n }\n}\n\n/* ─── SelectionList ─────────────────────────────────────────────────── */\n\n.selectionLabel {\n padding: var(--spacing-1, 0.25rem) var(--spacing-3, 0.75rem);\n padding-bottom: var(--spacing-2, 0.5rem);\n font-size: var(--font-size-xs, 0.75rem);\n font-weight: 600;\n letter-spacing: 0.05em;\n text-transform: uppercase;\n color: var(--text-secondary, #6b7280);\n}\n\n.selectionList {\n display: flex;\n flex-direction: column;\n gap: var(--spacing-1, 0.25rem);\n outline: none;\n}\n\n.selectionItem {\n position: relative;\n display: flex;\n align-items: center;\n gap: var(--spacing-2, 0.5rem);\n padding: var(--spacing-2, 0.5rem) var(--spacing-3, 0.75rem);\n border-radius: var(--radius-md, 0.375rem);\n font-size: var(--font-size-sm, 0.875rem);\n color: var(--text-primary, #111827);\n cursor: pointer;\n outline: none;\n user-select: none;\n transition: background-color var(--motion-duration-fast, 100ms) var(--motion-easing-default, ease-in-out);\n}\n\n.selectionItem:hover {\n background-color: var(--surface-interactive-hover, #f3f4f6);\n}\n\n.selectionItem:focus-visible {\n outline: var(--focus-ring-width, 2px) solid var(--primary, #6366f1);\n outline-offset: var(--focus-ring-offset, 2px);\n}\n\n.selectionItemSelected {\n background-color: var(--surface-subtle, #f9fafb);\n}\n\n.selectionItemSelected:hover {\n background-color: var(--surface-interactive-hover, #f3f4f6);\n}\n\n.selectionItemDisabled {\n opacity: var(--opacity-40, 0.4);\n pointer-events: none;\n cursor: default;\n}\n\n.selectionItemLeadingIcon {\n display: flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n width: 1rem;\n height: 1rem;\n color: var(--text-secondary, #6b7280);\n}\n\n/* Indicator plate — always rendered for stable row geometry */\n.selectionIndicator {\n display: flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n width: 1rem; /* 16px */\n height: 1rem; /* 16px */\n transition:\n background-color var(--motion-duration-fast, 100ms) var(--motion-easing-default, ease-in-out),\n border-color var(--motion-duration-fast, 100ms) var(--motion-easing-default, ease-in-out);\n}\n\n/* Checkbox: rounded-4px plate */\n.selectionIndicatorCheckbox {\n border-radius: 4px;\n border: var(--stroke-width-thin, 1px) solid var(--hairline-strong, #d1d5db);\n background-color: var(--surface-card, #ffffff);\n color: transparent;\n}\n\n.selectionIndicatorCheckbox.selectionIndicatorSelected {\n background-color: var(--primary, #6366f1);\n border-color: var(--primary, #6366f1);\n color: var(--interactive-primary-text, #f9fafb);\n}\n\n.selectionIndicatorCheckbox svg {\n width: 0.625rem; /* 10px */\n height: 0.625rem;\n}\n\n/* Radio: circular plate with ring */\n.selectionIndicatorRadio {\n border-radius: 9999px;\n border: var(--stroke-width-thin, 1px) solid var(--hairline-strong, #d1d5db);\n background-color: var(--surface-card, #ffffff);\n}\n\n.selectionIndicatorRadio.selectionIndicatorSelected {\n border: 1.5px solid var(--primary, #6366f1);\n}\n\n/* Radio filled dot when selected */\n.selectionRadioDot {\n display: block;\n width: 0.5rem; /* 8px */\n height: 0.5rem;\n border-radius: 9999px;\n background-color: var(--primary, #6366f1);\n}\n\n.selectionItemLabel {\n flex: 1;\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n/* Count badge — right-aligned, tabular numerals, muted */\n.selectionCount {\n margin-left: auto;\n flex-shrink: 0;\n font-size: var(--font-size-xs, 0.75rem);\n font-variant-numeric: tabular-nums;\n color: var(--text-secondary, #6b7280);\n}\n"
858
864
  }
859
865
  ]
860
866
  },
@@ -914,7 +920,7 @@
914
920
  {
915
921
  "path": "components/ui/banner/banner.module.css",
916
922
  "type": "registry:ui",
917
- "content": "/* Banner base */\n.base {\n width: 100%;\n display: flex;\n align-items: center;\n gap: var(--spacing-3, 0.75rem);\n padding: var(--spacing-3, 0.75rem) var(--spacing-4, 1rem);\n font-size: var(--font-size-sm, 0.875rem);\n border-bottom: 1px solid;\n box-shadow: var(--shadow-sm);\n}\n\n/* Intent variants */\n.intentInfo {\n background-color: var(--surface-info-subtle, #f0f9ff);\n color: var(--text-info, #0369a1);\n border-color: var(--border-info, #0ea5e9);\n}\n\n.intentWarning {\n background-color: var(--surface-warning-subtle, #fffbeb);\n color: var(--text-warning, #b45309);\n border-color: var(--border-warning, #f59e0b);\n}\n\n.intentError {\n background-color: var(--surface-error-subtle, #fef2f2);\n color: var(--text-error, #b91c1c);\n border-color: var(--border-error, #ef4444);\n}\n\n.intentSuccess {\n background-color: var(--surface-success-subtle, #f0fdf4);\n color: var(--text-success, #15803d);\n border-color: var(--border-success, #22c55e);\n}\n\n/* Position variants */\n.positionInline {\n /* Default — no extra styles */\n}\n\n.positionSticky {\n position: sticky;\n top: 0;\n z-index: 40;\n}\n\n/* Banner content wrapper */\n.content {\n flex: 1;\n display: flex;\n flex-direction: column;\n gap: calc(var(--spacing-1, 0.25rem) / 2);\n}\n\n/* BannerTitle */\n.title {\n font-weight: var(--font-weight-semibold, 600);\n line-height: 1.5;\n color: inherit;\n}\n\n/* BannerDescription */\n.description {\n font-size: var(--font-size-sm, 0.875rem);\n color: var(--text-secondary, #6b7280);\n line-height: 1.5;\n}\n\n.intentInfo .description {\n color: color-mix(in srgb, var(--text-info, #0369a1) 90%, transparent);\n}\n\n.intentWarning .description {\n color: color-mix(in srgb, var(--text-warning, #b45309) 90%, transparent);\n}\n\n.intentError .description {\n color: color-mix(in srgb, var(--text-error, #b91c1c) 90%, transparent);\n}\n\n.intentSuccess .description {\n color: color-mix(in srgb, var(--text-success, #15803d) 90%, transparent);\n}\n\n/* BannerAction */\n.action {\n margin-left: auto;\n display: flex;\n align-items: center;\n gap: var(--spacing-2, 0.5rem);\n}\n"
923
+ "content": "/* Banner base */\n.base {\n width: 100%;\n display: flex;\n align-items: center;\n gap: var(--spacing-3, 0.75rem);\n padding: var(--spacing-3, 0.75rem) var(--spacing-4, 1rem);\n font-size: var(--font-size-sm, 0.875rem);\n border-bottom: 1px solid;\n box-shadow: var(--shadow-sm);\n}\n\n/* Intent variants */\n.intentInfo {\n background-color: var(--surface-info-subtle, transparent);\n color: var(--text-info, currentColor);\n border-color: var(--border-info, currentColor);\n}\n\n.intentWarning {\n background-color: var(--surface-warning-subtle, transparent);\n color: var(--text-warning, currentColor);\n border-color: var(--border-warning, currentColor);\n}\n\n.intentError {\n background-color: var(--surface-error-subtle, transparent);\n color: var(--text-error, currentColor);\n border-color: var(--border-error, currentColor);\n}\n\n.intentSuccess {\n background-color: var(--surface-success-subtle, transparent);\n color: var(--text-success, currentColor);\n border-color: var(--border-success, currentColor);\n}\n\n/* Position variants */\n.positionInline {\n /* Default — no extra styles */\n}\n\n.positionSticky {\n position: sticky;\n top: 0;\n z-index: 40;\n}\n\n/* Banner content wrapper */\n.content {\n flex: 1;\n display: flex;\n flex-direction: column;\n gap: calc(var(--spacing-1, 0.25rem) / 2);\n}\n\n/* BannerTitle */\n.title {\n font-weight: var(--font-weight-semibold, 600);\n line-height: 1.5;\n color: inherit;\n}\n\n/* BannerDescription */\n.description {\n font-size: var(--font-size-sm, 0.875rem);\n color: var(--text-secondary, currentColor);\n line-height: 1.5;\n}\n\n.intentInfo .description {\n color: color-mix(in srgb, var(--text-info, currentColor) 90%, transparent);\n}\n\n.intentWarning .description {\n color: color-mix(in srgb, var(--text-warning, currentColor) 90%, transparent);\n}\n\n.intentError .description {\n color: color-mix(in srgb, var(--text-error, currentColor) 90%, transparent);\n}\n\n.intentSuccess .description {\n color: color-mix(in srgb, var(--text-success, currentColor) 90%, transparent);\n}\n\n/* BannerAction */\n.action {\n margin-left: auto;\n display: flex;\n align-items: center;\n gap: var(--spacing-2, 0.5rem);\n}\n"
918
924
  }
919
925
  ]
920
926
  },
@@ -939,7 +945,7 @@
939
945
  {
940
946
  "path": "components/ui/toast/toast.module.css",
941
947
  "type": "registry:ui",
942
- "content": "/* Toaster container */\n.toaster {\n /* Container styling if needed */\n}\n\n/* Individual toast — :global() selectors nested under .toaster for CSS Modules purity.\n Sonner renders toasts as children of its container element. */\n.toaster :global([data-sonner-toast]) {\n font-family: var(--font-family-sans, system-ui, sans-serif);\n background-color: var(--surface-popover, var(--surface-card, #ffffff));\n color: var(--text-primary, #111827);\n border-radius: var(--radius-lg, 0.5rem);\n box-shadow: var(--shadow-lg);\n padding: var(--spacing-3, 0.75rem) var(--spacing-4, 1rem);\n gap: var(--spacing-2, 0.5rem);\n /* Override Sonner's default 400ms transitions with Visor motion tokens */\n transition:\n transform var(--motion-duration-normal, 200ms) var(--motion-easing-enter, ease-out),\n opacity var(--motion-duration-normal, 200ms) var(--motion-easing-enter, ease-out),\n height var(--motion-duration-normal, 200ms) !important;\n}\n\n/* Faster exit animation for dismissed toasts */\n.toaster :global([data-sonner-toast][data-removed=\"true\"]) {\n transition:\n transform var(--motion-duration-150, 150ms) var(--motion-easing-exit, ease-in),\n opacity var(--motion-duration-150, 150ms) var(--motion-easing-exit, ease-in) !important;\n}\n\n/* Toast title */\n.toaster :global([data-sonner-toast] [data-title]) {\n font-weight: var(--font-weight-semibold, 600);\n font-size: var(--font-size-sm, 0.875rem);\n color: var(--text-primary, #111827);\n}\n\n/* Toast description */\n.toaster :global([data-sonner-toast] [data-description]) {\n font-size: var(--font-size-sm, 0.875rem);\n color: var(--text-secondary, #6b7280);\n}\n\n/* Type-specific colors — subtle bg fill + left accent border */\n.toaster :global([data-sonner-toast][data-type=\"success\"]) {\n background-color: var(--surface-success-subtle, #f0fdf4);\n border-left: 3px solid var(--border-success, #22c55e);\n}\n\n.toaster :global([data-sonner-toast][data-type=\"error\"]) {\n background-color: var(--surface-error-subtle, #fef2f2);\n border-left: 3px solid var(--border-error, #ef4444);\n}\n\n.toaster :global([data-sonner-toast][data-type=\"warning\"]) {\n background-color: var(--surface-warning-subtle, #fffbeb);\n border-left: 3px solid var(--border-warning, #f59e0b);\n}\n\n.toaster :global([data-sonner-toast][data-type=\"info\"]) {\n background-color: var(--surface-info-subtle, #f0f9ff);\n border-left: 3px solid var(--border-info, #0ea5e9);\n}\n\n/* Action button */\n.toaster :global([data-sonner-toast] [data-button]) {\n background-color: var(--interactive-primary-bg, #111827);\n color: var(--interactive-primary-text, #ffffff);\n border-radius: var(--radius-md, 0.375rem);\n font-size: var(--font-size-xs, 0.75rem);\n font-weight: var(--font-weight-medium, 500);\n padding: var(--spacing-1, 0.25rem) var(--spacing-2, 0.5rem);\n}\n\n/* Cancel button */\n.toaster :global([data-sonner-toast] [data-cancel]) {\n background-color: transparent;\n color: var(--text-secondary, #6b7280);\n font-size: var(--font-size-xs, 0.75rem);\n}\n\n/* Close button */\n.toaster :global([data-sonner-toast] [data-close-button]) {\n background-color: var(--surface-card, #ffffff);\n border: 1px solid var(--border-default, #e5e7eb);\n color: var(--text-secondary, #6b7280);\n}\n\n/* Dark mode support — :where() keeps specificity low so type-specific selectors above win */\n:global(:where(.dark)) .toaster :global([data-sonner-toast]),\n:global(:where([data-theme=\"dark\"])) .toaster :global([data-sonner-toast]) {\n background-color: var(--surface-card, #1f2937);\n color: var(--text-primary, #f9fafb);\n}\n\n/* Class-based styles applied via Sonner's classNames option */\n.toast {\n /* Specificity boost layer — matches :global styles above */\n}\n\n.title {\n font-weight: var(--font-weight-semibold, 600);\n}\n\n.description {\n color: var(--text-secondary, #6b7280);\n}\n\n.actionButton {\n background-color: var(--interactive-primary-bg, #111827);\n color: var(--interactive-primary-text, #ffffff);\n border-radius: var(--radius-md, 0.375rem);\n font-size: var(--font-size-xs, 0.75rem);\n font-weight: var(--font-weight-medium, 500);\n padding: var(--spacing-1, 0.25rem) var(--spacing-2, 0.5rem);\n}\n\n.cancelButton {\n background-color: transparent;\n color: var(--text-secondary, #6b7280);\n font-size: var(--font-size-xs, 0.75rem);\n}\n\n.closeButton {\n background-color: var(--surface-card, #ffffff);\n border: 1px solid var(--border-default, #e5e7eb);\n color: var(--text-secondary, #6b7280);\n}\n"
948
+ "content": "/* Toaster container */\n.toaster {\n /* Container styling if needed */\n}\n\n/* Individual toast — :global() selectors nested under .toaster for CSS Modules purity.\n Sonner renders toasts as children of its container element. */\n.toaster :global([data-sonner-toast]) {\n font-family: var(--font-family-sans, system-ui, sans-serif);\n background-color: var(--surface-popover, var(--surface-card, #ffffff));\n color: var(--text-primary, #111827);\n border-radius: var(--radius-lg, 0.5rem);\n box-shadow: var(--shadow-lg);\n padding: var(--spacing-3, 0.75rem) var(--spacing-4, 1rem);\n gap: var(--spacing-2, 0.5rem);\n /* Override Sonner's default 400ms transitions with Visor motion tokens */\n transition:\n transform var(--motion-duration-normal, 200ms) var(--motion-easing-enter, ease-out),\n opacity var(--motion-duration-normal, 200ms) var(--motion-easing-enter, ease-out),\n height var(--motion-duration-normal, 200ms) !important;\n}\n\n/* Faster exit animation for dismissed toasts */\n.toaster :global([data-sonner-toast][data-removed=\"true\"]) {\n transition:\n transform var(--motion-duration-150, 150ms) var(--motion-easing-exit, ease-in),\n opacity var(--motion-duration-150, 150ms) var(--motion-easing-exit, ease-in) !important;\n}\n\n/* Toast title */\n.toaster :global([data-sonner-toast] [data-title]) {\n font-weight: var(--font-weight-semibold, 600);\n font-size: var(--font-size-sm, 0.875rem);\n color: var(--text-primary, #111827);\n}\n\n/* Toast description */\n.toaster :global([data-sonner-toast] [data-description]) {\n font-size: var(--font-size-sm, 0.875rem);\n color: var(--text-secondary, #6b7280);\n}\n\n/* Type-specific colors — subtle bg fill + left accent border */\n.toaster :global([data-sonner-toast][data-type=\"success\"]) {\n background-color: var(--surface-success-subtle, #f0fdf4);\n border-left: 3px solid var(--border-success, #22c55e);\n}\n\n.toaster :global([data-sonner-toast][data-type=\"error\"]) {\n background-color: var(--surface-error-subtle, #fef2f2);\n border-left: 3px solid var(--border-error, #ef4444);\n}\n\n.toaster :global([data-sonner-toast][data-type=\"warning\"]) {\n background-color: var(--surface-warning-subtle, #fffbeb);\n border-left: 3px solid var(--border-warning, #f59e0b);\n}\n\n.toaster :global([data-sonner-toast][data-type=\"info\"]) {\n background-color: var(--surface-info-subtle, #f0f9ff);\n border-left: 3px solid var(--border-info, #0ea5e9);\n}\n\n/* Action button */\n.toaster :global([data-sonner-toast] [data-button]) {\n background-color: var(--interactive-primary-bg, var(--primary, #111827));\n color: var(--interactive-primary-text, #ffffff);\n border-radius: var(--radius-md, 0.375rem);\n font-size: var(--font-size-xs, 0.75rem);\n font-weight: var(--font-weight-medium, 500);\n padding: var(--spacing-1, 0.25rem) var(--spacing-2, 0.5rem);\n}\n\n/* Cancel button */\n.toaster :global([data-sonner-toast] [data-cancel]) {\n background-color: transparent;\n color: var(--text-secondary, #6b7280);\n font-size: var(--font-size-xs, 0.75rem);\n}\n\n/* Close button */\n.toaster :global([data-sonner-toast] [data-close-button]) {\n background-color: var(--surface-card, #ffffff);\n border: 1px solid var(--border-default, #e5e7eb);\n color: var(--text-secondary, #6b7280);\n}\n\n/* Dark mode support — :where() keeps specificity low so type-specific selectors above win */\n:global(:where(.dark)) .toaster :global([data-sonner-toast]),\n:global(:where([data-theme=\"dark\"])) .toaster :global([data-sonner-toast]) {\n background-color: var(--surface-card, #1f2937);\n color: var(--text-primary, #f9fafb);\n}\n\n/* Class-based styles applied via Sonner's classNames option */\n.toast {\n /* Specificity boost layer — matches :global styles above */\n}\n\n.title {\n font-weight: var(--font-weight-semibold, 600);\n}\n\n.description {\n color: var(--text-secondary, #6b7280);\n}\n\n.actionButton {\n background-color: var(--interactive-primary-bg, var(--primary, #111827));\n color: var(--interactive-primary-text, #ffffff);\n border-radius: var(--radius-md, 0.375rem);\n font-size: var(--font-size-xs, 0.75rem);\n font-weight: var(--font-weight-medium, 500);\n padding: var(--spacing-1, 0.25rem) var(--spacing-2, 0.5rem);\n}\n\n.cancelButton {\n background-color: transparent;\n color: var(--text-secondary, #6b7280);\n font-size: var(--font-size-xs, 0.75rem);\n}\n\n.closeButton {\n background-color: var(--surface-card, #ffffff);\n border: 1px solid var(--border-default, #e5e7eb);\n color: var(--text-secondary, #6b7280);\n}\n"
943
949
  }
944
950
  ]
945
951
  },
@@ -1040,7 +1046,7 @@
1040
1046
  {
1041
1047
  "path": "components/ui/radio-group/radio-group.module.css",
1042
1048
  "type": "registry:ui",
1043
- "content": "/* RadioGroup root */\n.root {\n display: flex;\n flex-direction: column;\n gap: var(--spacing-2, 0.5rem);\n}\n\n/* RadioGroup item (the button) */\n.item {\n position: relative;\n display: flex;\n width: 1rem;\n height: 1rem;\n flex-shrink: 0;\n align-items: center;\n justify-content: center;\n border-radius: 9999px;\n border: 1px solid var(--border-default, #e5e7eb);\n background-color: transparent;\n transition: border-color var(--motion-duration-150, 150ms) var(--motion-easing-default, ease-in-out),\n background-color var(--motion-duration-150, 150ms) var(--motion-easing-default, ease-in-out),\n box-shadow var(--motion-duration-150, 150ms) var(--motion-easing-default, ease-in-out);\n outline: none;\n cursor: pointer;\n}\n\n@media (hover: hover) {\n .item:hover:not(:focus-visible):not(:disabled) {\n border-color: var(--border-strong, #d1d5db);\n }\n}\n\n.item:focus-visible {\n border-color: var(--border-focus, #111827);\n box-shadow: 0 0 0 var(--focus-ring-width, 2px) color-mix(in srgb, var(--border-focus, #111827) 15%, transparent);\n}\n\n.item:disabled {\n cursor: not-allowed;\n opacity: 0.5;\n}\n\n.item[data-state=\"checked\"] {\n border-color: var(--interactive-primary-bg, #111827);\n background-color: var(--interactive-primary-bg, #111827);\n color: var(--interactive-primary-text, #f9fafb);\n}\n\n/* Indicator */\n.indicator {\n display: grid;\n place-content: center;\n color: currentColor;\n}\n\n.icon {\n width: 0.5rem;\n height: 0.5rem;\n}\n"
1049
+ "content": "/* RadioGroup root */\n.root {\n display: flex;\n flex-direction: column;\n gap: var(--spacing-2, 0.5rem);\n}\n\n/* RadioGroup item (the button) */\n.item {\n position: relative;\n display: flex;\n width: 1rem;\n height: 1rem;\n flex-shrink: 0;\n align-items: center;\n justify-content: center;\n border-radius: 9999px;\n border: 1px solid var(--radio-border, var(--border-default, #e5e7eb));\n background-color: transparent;\n transition: border-color var(--motion-duration-150, 150ms) var(--motion-easing-default, ease-in-out),\n background-color var(--motion-duration-150, 150ms) var(--motion-easing-default, ease-in-out),\n box-shadow var(--motion-duration-150, 150ms) var(--motion-easing-default, ease-in-out);\n outline: none;\n cursor: pointer;\n}\n\n@media (hover: hover) {\n .item:hover:not(:focus-visible):not(:disabled) {\n border-color: var(--border-strong, #d1d5db);\n }\n}\n\n.item:focus-visible {\n border-color: var(--border-focus, #111827);\n box-shadow: 0 0 0 var(--focus-ring-width, 2px) color-mix(in srgb, var(--border-focus, #111827) 15%, transparent);\n}\n\n.item:disabled {\n cursor: not-allowed;\n opacity: 0.5;\n}\n\n.item[data-state=\"checked\"] {\n border-color: var(--interactive-primary-bg, var(--primary, #111827));\n background-color: var(--interactive-primary-bg, var(--primary, #111827));\n color: var(--interactive-primary-text, #f9fafb);\n}\n\n/* Indicator */\n.indicator {\n display: grid;\n place-content: center;\n color: currentColor;\n}\n\n.icon {\n width: 0.5rem;\n height: 0.5rem;\n}\n"
1044
1050
  }
1045
1051
  ]
1046
1052
  },
@@ -1065,7 +1071,7 @@
1065
1071
  {
1066
1072
  "path": "components/ui/slider/slider.module.css",
1067
1073
  "type": "registry:ui",
1068
- "content": "/* Slider root */\n.root {\n position: relative;\n display: flex;\n width: 100%;\n touch-action: none;\n user-select: none;\n align-items: center;\n cursor: pointer;\n}\n\n.root[data-disabled] {\n cursor: not-allowed;\n opacity: 0.5;\n}\n\n/* Track */\n.track {\n position: relative;\n flex-grow: 1;\n overflow: hidden;\n height: 0.375rem;\n border-radius: 9999px;\n background-color: var(--surface-interactive-default, #f3f4f6);\n}\n\n/* Range (filled portion) */\n.range {\n position: absolute;\n height: 100%;\n background-color: var(--interactive-primary-bg, #111827);\n border-radius: 9999px;\n transition: background-color var(--motion-duration-150, 150ms) var(--motion-easing-default, ease-in-out);\n}\n\n/* Thumb */\n.thumb {\n display: block;\n width: 1.25rem;\n height: 1.25rem;\n border-radius: 9999px;\n border: 2px solid var(--interactive-primary-bg, #111827);\n background-color: var(--surface-popover, var(--surface-card, #ffffff));\n box-shadow: var(--shadow-sm);\n transition: border-color var(--motion-duration-150, 150ms) var(--motion-easing-default, ease-in-out),\n box-shadow var(--motion-duration-150, 150ms) var(--motion-easing-default, ease-in-out);\n outline: none;\n cursor: grab;\n}\n\n@media (hover: hover) {\n .thumb:hover:not(:focus-visible) {\n border-color: var(--interactive-primary-bg-hover, #1d4ed8);\n }\n}\n\n.thumb:active {\n cursor: grabbing;\n}\n\n.thumb:focus-visible {\n box-shadow: 0 0 0 var(--focus-ring-width, 2px) color-mix(in srgb, var(--border-focus, #111827) 15%, transparent),\n var(--shadow-sm);\n}\n\n.root[data-disabled] .thumb {\n cursor: not-allowed;\n}\n"
1074
+ "content": "/* Slider root */\n.root {\n position: relative;\n display: flex;\n width: 100%;\n touch-action: none;\n user-select: none;\n align-items: center;\n cursor: pointer;\n}\n\n.root[data-disabled] {\n cursor: not-allowed;\n opacity: 0.5;\n}\n\n/* Track */\n.track {\n position: relative;\n flex-grow: 1;\n overflow: hidden;\n height: 0.375rem;\n border-radius: 9999px;\n background-color: var(--surface-interactive-default, #f3f4f6);\n}\n\n/* Range (filled portion) */\n.range {\n position: absolute;\n height: 100%;\n background-color: var(--interactive-primary-bg, var(--primary, #111827));\n border-radius: 9999px;\n transition: background-color var(--motion-duration-150, 150ms) var(--motion-easing-default, ease-in-out);\n}\n\n/* Thumb */\n.thumb {\n display: block;\n width: 1.25rem;\n height: 1.25rem;\n border-radius: 9999px;\n border: 2px solid var(--interactive-primary-bg, var(--primary, #111827));\n background-color: var(--surface-popover, var(--surface-card, #ffffff));\n box-shadow: var(--shadow-sm);\n transition: border-color var(--motion-duration-150, 150ms) var(--motion-easing-default, ease-in-out),\n box-shadow var(--motion-duration-150, 150ms) var(--motion-easing-default, ease-in-out);\n outline: none;\n cursor: grab;\n}\n\n@media (hover: hover) {\n .thumb:hover:not(:focus-visible) {\n border-color: var(--interactive-primary-bg-hover, #1d4ed8);\n }\n}\n\n.thumb:active {\n cursor: grabbing;\n}\n\n.thumb:focus-visible {\n box-shadow: 0 0 0 var(--focus-ring-width, 2px) color-mix(in srgb, var(--border-focus, #111827) 15%, transparent),\n var(--shadow-sm);\n}\n\n.root[data-disabled] .thumb {\n cursor: not-allowed;\n}\n"
1069
1075
  }
1070
1076
  ]
1071
1077
  },
@@ -1116,7 +1122,7 @@
1116
1122
  {
1117
1123
  "path": "components/ui/toggle-group/toggle-group.module.css",
1118
1124
  "type": "registry:ui",
1119
- "content": "/* ToggleGroup root */\n.root {\n display: inline-flex;\n align-items: center;\n gap: var(--spacing-1, 0.25rem);\n}\n\n.variantDefault {\n /* items have no outer border, rely on item bg */\n}\n\n.variantOutline {\n position: relative;\n border: 1px solid var(--border-default, #e5e7eb);\n gap: 0;\n}\n\n/* Sliding indicator pill */\n.indicator {\n position: absolute;\n top: 0;\n left: 0;\n background-color: var(--interactive-primary-bg, #111827);\n border-radius: var(--radius-md, 0.375rem);\n opacity: 0;\n pointer-events: none;\n z-index: 0;\n transition:\n transform var(--motion-duration-200, 200ms) var(--motion-easing-default, ease-in-out),\n width var(--motion-duration-200, 200ms) var(--motion-easing-default, ease-in-out),\n opacity var(--motion-duration-150, 150ms) var(--motion-easing-default, ease-in-out);\n}\n\n/* Match indicator radius to item radius per size */\n.sizeXs .indicator { border-radius: var(--radius-sm, 0.25rem); }\n.sizeSm .indicator { border-radius: var(--radius-md, 0.375rem); }\n.sizeMd .indicator { border-radius: var(--radius-md, 0.375rem); }\n.sizeLg .indicator { border-radius: var(--radius-lg, 0.5rem); }\n\n.sizeXs {\n /* inherited by items */\n}\n\n.variantOutline.sizeXs {\n padding: calc(var(--spacing-1, 0.25rem) / 2);\n border-radius: var(--radius-md, 0.375rem);\n}\n\n.sizeSm {\n /* inherited by items */\n}\n\n.variantOutline.sizeSm {\n padding: var(--spacing-1, 0.25rem);\n border-radius: var(--radius-lg, 0.5rem);\n}\n\n.sizeMd {\n /* inherited by items */\n}\n\n.variantOutline.sizeMd {\n padding: var(--spacing-1, 0.25rem);\n border-radius: var(--radius-lg, 0.5rem);\n}\n\n.sizeLg {\n /* inherited by items */\n}\n\n.variantOutline.sizeLg {\n padding: var(--spacing-1, 0.25rem);\n border-radius: var(--radius-xl, 0.75rem);\n}\n\n/* ToggleGroup item */\n.item {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n font-size: var(--font-size-sm, 0.875rem);\n font-weight: var(--font-weight-medium, 500);\n color: var(--text-primary, #111827);\n background-color: transparent;\n border: none;\n cursor: pointer;\n transition: background-color var(--motion-duration-150, 150ms) var(--motion-easing-default, ease-in-out),\n color var(--motion-duration-150, 150ms) var(--motion-easing-default, ease-in-out),\n box-shadow var(--motion-duration-150, 150ms) var(--motion-easing-default, ease-in-out);\n outline: none;\n user-select: none;\n white-space: nowrap;\n}\n\n.item:active:not(:disabled) {\n transform: translateY(1px);\n transition: none;\n}\n\n.item:focus-visible {\n box-shadow: 0 0 0 var(--focus-ring-width, 2px) color-mix(in srgb, var(--border-focus, #111827) 15%, transparent);\n}\n\n.item:disabled {\n cursor: not-allowed;\n opacity: 0.5;\n}\n\n/* Default variant items */\n@media (hover: hover) {\n .itemVariantDefault:hover:not(:disabled) {\n background-color: var(--surface-interactive-hover, #f3f4f6);\n }\n}\n\n.itemVariantDefault[data-state=\"on\"] {\n background-color: var(--interactive-primary-bg, #111827);\n color: var(--interactive-primary-text, #f9fafb);\n}\n\n/* Outline variant items — indicator provides the active background */\n.itemVariantOutline {\n position: relative;\n z-index: 1;\n}\n\n@media (hover: hover) {\n .itemVariantOutline:hover:not(:disabled):not([data-state=\"on\"]) {\n background-color: color-mix(in srgb, var(--surface-interactive-hover, #f3f4f6) 40%, transparent);\n }\n}\n\n.itemVariantOutline[data-state=\"on\"] {\n background-color: transparent;\n color: var(--interactive-primary-text, #f9fafb);\n}\n\n/* Multiple-select outline — items need their own active bg (no sliding indicator) */\n:global([data-type=\"multiple\"]) .itemVariantOutline[data-state=\"on\"] {\n background-color: var(--interactive-primary-bg, #111827);\n}\n\n/* Sizes */\n.itemSizeXs {\n height: 1.5rem;\n padding: 0 var(--spacing-2, 0.5rem);\n border-radius: var(--radius-sm, 0.25rem);\n font-size: var(--font-size-xs, 0.75rem);\n gap: var(--spacing-1, 0.25rem);\n}\n\n.itemSizeSm {\n height: 1.75rem;\n padding: 0 var(--spacing-2, 0.5rem);\n border-radius: var(--radius-md, 0.375rem);\n font-size: var(--font-size-xs, 0.75rem);\n gap: var(--spacing-1, 0.25rem);\n}\n\n.itemSizeMd {\n height: 2.25rem;\n padding: 0 var(--spacing-3, 0.75rem);\n border-radius: var(--radius-md, 0.375rem);\n font-size: var(--font-size-sm, 0.875rem);\n gap: var(--spacing-2, 0.5rem);\n}\n\n.itemSizeLg {\n height: 2.75rem;\n padding: 0 var(--spacing-4, 1rem);\n border-radius: var(--radius-lg, 0.5rem);\n font-size: var(--font-size-base, 1rem);\n gap: var(--spacing-2, 0.5rem);\n}\n"
1125
+ "content": "/* ToggleGroup root */\n.root {\n display: inline-flex;\n align-items: center;\n gap: var(--spacing-1, 0.25rem);\n}\n\n.variantDefault {\n /* items have no outer border, rely on item bg */\n}\n\n.variantOutline {\n position: relative;\n border: 1px solid var(--border-default, #e5e7eb);\n gap: 0;\n}\n\n/* Sliding indicator pill */\n.indicator {\n position: absolute;\n top: 0;\n left: 0;\n background-color: var(--interactive-primary-bg, var(--primary, #111827));\n border-radius: var(--radius-md, 0.375rem);\n opacity: 0;\n pointer-events: none;\n z-index: 0;\n transition:\n transform var(--motion-duration-200, 200ms) var(--motion-easing-default, ease-in-out),\n width var(--motion-duration-200, 200ms) var(--motion-easing-default, ease-in-out),\n opacity var(--motion-duration-150, 150ms) var(--motion-easing-default, ease-in-out);\n}\n\n/* Match indicator radius to item radius per size */\n.sizeXs .indicator { border-radius: var(--radius-sm, 0.25rem); }\n.sizeSm .indicator { border-radius: var(--radius-md, 0.375rem); }\n.sizeMd .indicator { border-radius: var(--radius-md, 0.375rem); }\n.sizeLg .indicator { border-radius: var(--radius-lg, 0.5rem); }\n\n.sizeXs {\n /* inherited by items */\n}\n\n.variantOutline.sizeXs {\n padding: calc(var(--spacing-1, 0.25rem) / 2);\n border-radius: var(--radius-md, 0.375rem);\n}\n\n.sizeSm {\n /* inherited by items */\n}\n\n.variantOutline.sizeSm {\n padding: var(--spacing-1, 0.25rem);\n border-radius: var(--radius-lg, 0.5rem);\n}\n\n.sizeMd {\n /* inherited by items */\n}\n\n.variantOutline.sizeMd {\n padding: var(--spacing-1, 0.25rem);\n border-radius: var(--radius-lg, 0.5rem);\n}\n\n.sizeLg {\n /* inherited by items */\n}\n\n.variantOutline.sizeLg {\n padding: var(--spacing-1, 0.25rem);\n border-radius: var(--radius-xl, 0.75rem);\n}\n\n/* ToggleGroup item */\n.item {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n font-size: var(--font-size-sm, 0.875rem);\n font-weight: var(--font-weight-medium, 500);\n color: var(--text-primary, #111827);\n background-color: transparent;\n border: none;\n cursor: pointer;\n transition: background-color var(--motion-duration-150, 150ms) var(--motion-easing-default, ease-in-out),\n color var(--motion-duration-150, 150ms) var(--motion-easing-default, ease-in-out),\n box-shadow var(--motion-duration-150, 150ms) var(--motion-easing-default, ease-in-out);\n outline: none;\n user-select: none;\n white-space: nowrap;\n}\n\n.item:active:not(:disabled) {\n transform: translateY(1px);\n transition: none;\n}\n\n.item:focus-visible {\n box-shadow: 0 0 0 var(--focus-ring-width, 2px) color-mix(in srgb, var(--border-focus, #111827) 15%, transparent);\n}\n\n.item:disabled {\n cursor: not-allowed;\n opacity: 0.5;\n}\n\n/* Default variant items */\n@media (hover: hover) {\n .itemVariantDefault:hover:not(:disabled) {\n background-color: var(--surface-interactive-hover, #f3f4f6);\n }\n}\n\n.itemVariantDefault[data-state=\"on\"] {\n background-color: var(--interactive-primary-bg, var(--primary, #111827));\n color: var(--interactive-primary-text, #f9fafb);\n}\n\n/* Outline variant items — indicator provides the active background */\n.itemVariantOutline {\n position: relative;\n z-index: 1;\n}\n\n@media (hover: hover) {\n .itemVariantOutline:hover:not(:disabled):not([data-state=\"on\"]) {\n background-color: color-mix(in srgb, var(--surface-interactive-hover, #f3f4f6) 40%, transparent);\n }\n}\n\n.itemVariantOutline[data-state=\"on\"] {\n background-color: transparent;\n color: var(--interactive-primary-text, #f9fafb);\n}\n\n/* Multiple-select outline — items need their own active bg (no sliding indicator) */\n:global([data-type=\"multiple\"]) .itemVariantOutline[data-state=\"on\"] {\n background-color: var(--interactive-primary-bg, var(--primary, #111827));\n}\n\n/* Sizes */\n.itemSizeXs {\n height: 1.5rem;\n padding: 0 var(--spacing-2, 0.5rem);\n border-radius: var(--radius-sm, 0.25rem);\n font-size: var(--font-size-xs, 0.75rem);\n gap: var(--spacing-1, 0.25rem);\n}\n\n.itemSizeSm {\n height: 1.75rem;\n padding: 0 var(--spacing-2, 0.5rem);\n border-radius: var(--radius-md, 0.375rem);\n font-size: var(--font-size-xs, 0.75rem);\n gap: var(--spacing-1, 0.25rem);\n}\n\n.itemSizeMd {\n height: 2.25rem;\n padding: 0 var(--spacing-3, 0.75rem);\n border-radius: var(--radius-md, 0.375rem);\n font-size: var(--font-size-sm, 0.875rem);\n gap: var(--spacing-2, 0.5rem);\n}\n\n.itemSizeLg {\n height: 2.75rem;\n padding: 0 var(--spacing-4, 1rem);\n border-radius: var(--radius-lg, 0.5rem);\n font-size: var(--font-size-base, 1rem);\n gap: var(--spacing-2, 0.5rem);\n}\n"
1120
1126
  }
1121
1127
  ]
1122
1128
  },
@@ -1142,7 +1148,7 @@
1142
1148
  {
1143
1149
  "path": "components/ui/combobox/combobox.module.css",
1144
1150
  "type": "registry:ui",
1145
- "content": "/* Combobox root */\n.root {\n position: relative;\n display: inline-flex;\n flex-direction: column;\n width: fit-content;\n}\n\n/* Input wrapper */\n.inputWrapper {\n position: relative;\n display: flex;\n align-items: center;\n}\n\n/* Input */\n.input {\n width: 100%;\n height: 2.25rem;\n padding: var(--spacing-2, 0.5rem) calc(var(--spacing-8, 2rem) + var(--spacing-1, 0.25rem)) var(--spacing-2, 0.5rem) var(--spacing-3, 0.75rem);\n border-radius: var(--radius-md, 0.375rem);\n border: 1px solid var(--border-default, #e5e7eb);\n background-color: var(--surface-interactive-default, #f9fafb);\n font-size: var(--font-size-sm, 0.875rem);\n color: var(--text-primary, #111827);\n transition: border-color var(--motion-duration-150, 150ms) var(--motion-easing-default, ease-in-out),\n box-shadow var(--motion-duration-150, 150ms) var(--motion-easing-default, ease-in-out);\n outline: none;\n}\n\n.input::placeholder {\n color: var(--text-secondary, #9ca3af);\n}\n\n@media (hover: hover) {\n .input:hover:not(:focus-visible):not(:disabled) {\n border-color: var(--border-strong, #d1d5db);\n }\n}\n\n.input:focus-visible {\n border-color: var(--border-focus, #111827);\n box-shadow: 0 0 0 var(--focus-ring-width, 2px) color-mix(in srgb, var(--border-focus, #111827) 15%, transparent);\n}\n\n.input:disabled {\n cursor: not-allowed;\n opacity: 0.5;\n}\n\n/* Caret icon */\n.icon {\n position: absolute;\n right: var(--spacing-3, 0.75rem);\n top: 50%;\n transform: translateY(-50%);\n width: 1rem;\n height: 1rem;\n pointer-events: none;\n color: var(--text-secondary, #9ca3af);\n transition: transform var(--motion-duration-150, 150ms) var(--motion-easing-default, ease-in-out);\n}\n\n.iconOpen {\n transform: translateY(-50%) rotate(180deg);\n}\n\n/* Content popover */\n.content {\n z-index: 50;\n min-width: var(--radix-popover-trigger-width, 12rem);\n max-height: 18rem;\n overflow: hidden auto;\n border-radius: var(--radius-lg, 0.5rem);\n background-color: var(--surface-popover, var(--surface-card, #ffffff));\n color: var(--text-primary, #111827);\n box-shadow: var(--shadow-lg);\n padding: var(--spacing-1, 0.25rem);\n}\n\n/* Listbox */\n.listbox {\n list-style: none;\n margin: 0;\n padding: 0;\n}\n\n/* Item */\n.item {\n position: relative;\n display: flex;\n align-items: center;\n gap: var(--spacing-2, 0.5rem);\n padding: var(--spacing-2, 0.5rem) var(--spacing-3, 0.75rem);\n border-radius: var(--radius-sm, 0.25rem);\n font-size: var(--font-size-sm, 0.875rem);\n cursor: default;\n outline: none;\n user-select: none;\n}\n\n.item:focus:not([data-disabled]) {\n background-color: var(--surface-interactive-hover, #f3f4f6);\n cursor: pointer;\n}\n\n@media (hover: hover) {\n .item:hover:not([data-disabled]) {\n background-color: var(--surface-interactive-hover, #f3f4f6);\n cursor: pointer;\n }\n}\n\n.item[data-disabled] {\n opacity: 0.5;\n cursor: not-allowed;\n}\n\n.item[data-selected] {\n background-color: var(--surface-interactive-hover, #f3f4f6);\n font-weight: var(--font-weight-medium, 500);\n}\n\n.itemCheck {\n display: inline-flex;\n width: 1rem;\n height: 1rem;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n}\n\n.itemCheckIcon {\n width: 0.875rem;\n height: 0.875rem;\n color: var(--interactive-primary-bg, #111827);\n}\n\n/* Empty */\n.empty {\n list-style: none;\n padding: var(--spacing-4, 1rem) var(--spacing-3, 0.75rem);\n text-align: center;\n font-size: var(--font-size-sm, 0.875rem);\n color: var(--text-secondary, #9ca3af);\n}\n\n/* Group */\n.group {\n list-style: none;\n}\n\n.group ul {\n list-style: none;\n margin: 0;\n padding: 0;\n}\n\n.groupHeading {\n padding: var(--spacing-1, 0.25rem) var(--spacing-3, 0.75rem) var(--spacing-1, 0.25rem);\n font-size: var(--font-size-xs, 0.75rem);\n font-weight: var(--font-weight-medium, 500);\n color: var(--text-secondary, #9ca3af);\n text-transform: uppercase;\n letter-spacing: 0.05em;\n}\n\n/* Separator */\n.separator {\n list-style: none;\n height: 1px;\n margin: var(--spacing-1, 0.25rem) calc(-1 * var(--spacing-1, 0.25rem));\n background-color: var(--border-default, #e5e7eb);\n}\n"
1151
+ "content": "/* Combobox root */\n.root {\n position: relative;\n display: inline-flex;\n flex-direction: column;\n width: fit-content;\n}\n\n/* Input wrapper */\n.inputWrapper {\n position: relative;\n display: flex;\n align-items: center;\n}\n\n/* Input */\n.input {\n width: 100%;\n height: 2.25rem;\n padding: var(--spacing-2, 0.5rem) calc(var(--spacing-8, 2rem) + var(--spacing-1, 0.25rem)) var(--spacing-2, 0.5rem) var(--spacing-3, 0.75rem);\n border-radius: var(--radius-md, 0.375rem);\n border: 1px solid var(--combobox-border, var(--border-default, #e5e7eb));\n background-color: var(--combobox-bg, var(--surface-interactive-default, #f9fafb));\n font-size: var(--font-size-sm, 0.875rem);\n color: var(--text-primary, #111827);\n transition: border-color var(--motion-duration-150, 150ms) var(--motion-easing-default, ease-in-out),\n box-shadow var(--motion-duration-150, 150ms) var(--motion-easing-default, ease-in-out);\n outline: none;\n}\n\n.input::placeholder {\n color: var(--text-secondary, #9ca3af);\n}\n\n@media (hover: hover) {\n .input:hover:not(:focus-visible):not(:disabled) {\n border-color: var(--border-strong, #d1d5db);\n }\n}\n\n.input:focus-visible {\n border-color: var(--border-focus, #111827);\n box-shadow: 0 0 0 var(--focus-ring-width, 2px) color-mix(in srgb, var(--border-focus, #111827) 15%, transparent);\n}\n\n.input:disabled {\n cursor: not-allowed;\n opacity: 0.5;\n}\n\n/* Caret icon */\n.icon {\n position: absolute;\n right: var(--spacing-3, 0.75rem);\n top: 50%;\n transform: translateY(-50%);\n width: 1rem;\n height: 1rem;\n pointer-events: none;\n color: var(--text-secondary, #9ca3af);\n transition: transform var(--motion-duration-150, 150ms) var(--motion-easing-default, ease-in-out);\n}\n\n.iconOpen {\n transform: translateY(-50%) rotate(180deg);\n}\n\n/* Content popover */\n.content {\n z-index: 50;\n min-width: var(--radix-popover-trigger-width, 12rem);\n max-height: 18rem;\n overflow: hidden auto;\n border-radius: var(--radius-lg, 0.5rem);\n background-color: var(--field-menu-bg, var(--surface-popover, var(--surface-card, #ffffff)));\n color: var(--text-primary, #111827);\n box-shadow: var(--shadow-lg);\n padding: var(--spacing-1, 0.25rem);\n}\n\n/* Listbox */\n.listbox {\n list-style: none;\n margin: 0;\n padding: 0;\n}\n\n/* Item */\n.item {\n position: relative;\n display: flex;\n align-items: center;\n gap: var(--spacing-2, 0.5rem);\n padding: var(--spacing-2, 0.5rem) var(--spacing-3, 0.75rem);\n border-radius: var(--radius-sm, 0.25rem);\n font-size: var(--font-size-sm, 0.875rem);\n cursor: default;\n outline: none;\n user-select: none;\n}\n\n.item:focus:not([data-disabled]) {\n background-color: var(--surface-interactive-hover, #f3f4f6);\n cursor: pointer;\n}\n\n@media (hover: hover) {\n .item:hover:not([data-disabled]) {\n background-color: var(--surface-interactive-hover, #f3f4f6);\n cursor: pointer;\n }\n}\n\n.item[data-disabled] {\n opacity: 0.5;\n cursor: not-allowed;\n}\n\n.item[data-selected] {\n background-color: var(--surface-interactive-hover, #f3f4f6);\n font-weight: var(--font-weight-medium, 500);\n}\n\n.itemCheck {\n display: inline-flex;\n width: 1rem;\n height: 1rem;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n}\n\n.itemCheckIcon {\n width: 0.875rem;\n height: 0.875rem;\n color: var(--interactive-primary-bg, var(--primary, #111827));\n}\n\n/* Empty */\n.empty {\n list-style: none;\n padding: var(--spacing-4, 1rem) var(--spacing-3, 0.75rem);\n text-align: center;\n font-size: var(--font-size-sm, 0.875rem);\n color: var(--text-secondary, #9ca3af);\n}\n\n/* Group */\n.group {\n list-style: none;\n}\n\n.group ul {\n list-style: none;\n margin: 0;\n padding: 0;\n}\n\n.groupHeading {\n padding: var(--spacing-1, 0.25rem) var(--spacing-3, 0.75rem) var(--spacing-1, 0.25rem);\n font-size: var(--font-size-xs, 0.75rem);\n font-weight: var(--font-weight-medium, 500);\n color: var(--text-secondary, #9ca3af);\n text-transform: uppercase;\n letter-spacing: 0.05em;\n}\n\n/* Separator */\n.separator {\n list-style: none;\n height: 1px;\n margin: var(--spacing-1, 0.25rem) calc(-1 * var(--spacing-1, 0.25rem));\n background-color: var(--border-default, #e5e7eb);\n}\n"
1146
1152
  }
1147
1153
  ]
1148
1154
  },
@@ -1327,7 +1333,7 @@
1327
1333
  {
1328
1334
  "path": "components/ui/date-picker/date-picker.module.css",
1329
1335
  "type": "registry:ui",
1330
- "content": "/* Date Picker Trigger */\n.trigger {\n display: inline-flex;\n align-items: center;\n gap: var(--spacing-2, 0.5rem);\n height: 2.25rem;\n padding: 0 var(--spacing-3, 0.75rem);\n border: 1px solid var(--border-default, #e5e7eb);\n border-radius: var(--radius-md, 0.375rem);\n background-color: var(--surface-card, #ffffff);\n color: var(--text-primary, #111827);\n font-size: var(--font-size-sm, 0.875rem);\n cursor: pointer;\n transition: border-color var(--motion-duration-fast, 150ms)\n var(--motion-easing-default, ease);\n white-space: nowrap;\n}\n\n@media (hover: hover) {\n .trigger:hover:not(.disabled) {\n border-color: var(--border-strong, #d1d5db);\n }\n}\n\n.trigger:focus-visible {\n outline: var(--focus-ring-width, 2px) solid var(--border-focus, #3b82f6);\n outline-offset: var(--focus-ring-offset, 2px);\n}\n\n.placeholder {\n color: var(--text-tertiary, #9ca3af);\n}\n\n.disabled {\n opacity: 0.5;\n cursor: not-allowed;\n}\n\n.icon {\n color: var(--text-tertiary, #9ca3af);\n flex-shrink: 0;\n}\n\n/* Popover Content */\n.content {\n z-index: 50;\n background-color: var(--surface-popover, var(--surface-card, #ffffff));\n border: 1px solid var(--border-default, #e5e7eb);\n border-radius: var(--radius-lg, 0.5rem);\n box-shadow: var(\n --shadow-md,\n 0 4px 6px -1px rgba(0, 0, 0, 0.1),\n 0 2px 4px -2px rgba(0, 0, 0, 0.1)\n );\n}\n"
1336
+ "content": "/* Date Picker Trigger */\n.trigger {\n display: inline-flex;\n align-items: center;\n gap: var(--spacing-2, 0.5rem);\n height: 2.25rem;\n padding: 0 var(--spacing-3, 0.75rem);\n border: 1px solid var(--border-default, #e5e7eb);\n border-radius: var(--radius-md, 0.375rem);\n background-color: var(--surface-card, #ffffff);\n color: var(--text-primary, #111827);\n font-size: var(--font-size-sm, 0.875rem);\n cursor: pointer;\n transition: border-color var(--motion-duration-fast, 150ms)\n var(--motion-easing-default, ease);\n white-space: nowrap;\n}\n\n@media (hover: hover) {\n .trigger:hover:not(.disabled) {\n border-color: var(--border-strong, #d1d5db);\n }\n}\n\n.trigger:focus-visible {\n outline: var(--focus-ring-width, 2px) solid var(--border-focus, #3b82f6);\n outline-offset: var(--focus-ring-offset, 2px);\n}\n\n.placeholder {\n color: var(--text-tertiary, #9ca3af);\n}\n\n.disabled {\n opacity: 0.5;\n cursor: not-allowed;\n}\n\n.icon {\n color: var(--text-tertiary, #9ca3af);\n flex-shrink: 0;\n}\n\n/* Popover Content */\n.content {\n z-index: 50;\n background-color: var(--field-menu-bg, var(--surface-popover, var(--surface-card, #ffffff)));\n border: 1px solid var(--border-default, #e5e7eb);\n border-radius: var(--radius-lg, 0.5rem);\n box-shadow: var(\n --shadow-md,\n 0 4px 6px -1px rgba(0, 0, 0, 0.1),\n 0 2px 4px -2px rgba(0, 0, 0, 0.1)\n );\n}\n"
1331
1337
  }
1332
1338
  ]
1333
1339
  },
@@ -1355,7 +1361,7 @@
1355
1361
  {
1356
1362
  "path": "components/ui/date-range-picker/date-range-picker.module.css",
1357
1363
  "type": "registry:ui",
1358
- "content": "/* Date Range Picker Trigger */\n.trigger {\n display: inline-flex;\n align-items: center;\n gap: var(--spacing-2, 0.5rem);\n height: 2.25rem;\n /* 7 day columns × 2.25rem + calendar's left+right padding + popover border */\n min-width: calc(7 * 2.25rem + 2 * var(--spacing-3, 0.75rem) + 2px);\n padding: 0 var(--spacing-3, 0.75rem);\n border: 1px solid var(--border-default, #e5e7eb);\n border-radius: var(--radius-md, 0.375rem);\n background-color: var(--surface-card, #ffffff);\n color: var(--text-primary, #111827);\n font-size: var(--font-size-sm, 0.875rem);\n cursor: pointer;\n transition: border-color var(--motion-duration-fast, 150ms)\n var(--motion-easing-default, ease);\n white-space: nowrap;\n}\n\n@media (hover: hover) {\n .trigger:hover:not(.disabled) {\n border-color: var(--border-strong, #d1d5db);\n }\n}\n\n.trigger:focus-visible {\n outline: var(--focus-ring-width, 2px) solid var(--border-focus, #3b82f6);\n outline-offset: var(--focus-ring-offset, 2px);\n}\n\n.placeholder {\n color: var(--text-tertiary, #9ca3af);\n}\n\n.disabled {\n opacity: 0.5;\n cursor: not-allowed;\n}\n\n.icon {\n color: var(--text-tertiary, #9ca3af);\n flex-shrink: 0;\n}\n\n/* Popover Content */\n.content {\n z-index: 50;\n width: max-content; /* two-month calendar needs room to expand */\n /* --surface-popover, not --surface-card: glass themes (Blackout) make surface-card ~4% alpha */\n background-color: var(--surface-popover, var(--surface-card, #ffffff));\n border: 1px solid var(--border-default, #e5e7eb);\n border-radius: var(--radius-lg, 0.5rem);\n box-shadow: var(\n --shadow-md,\n 0 4px 6px -1px rgba(0, 0, 0, 0.1),\n 0 2px 4px -2px rgba(0, 0, 0, 0.1)\n );\n}\n"
1364
+ "content": "/* Date Range Picker Trigger */\n.trigger {\n display: inline-flex;\n align-items: center;\n gap: var(--spacing-2, 0.5rem);\n height: 2.25rem;\n /* 7 day columns × 2.25rem + calendar's left+right padding + popover border */\n min-width: calc(7 * 2.25rem + 2 * var(--spacing-3, 0.75rem) + 2px);\n padding: 0 var(--spacing-3, 0.75rem);\n border: 1px solid var(--border-default, #e5e7eb);\n border-radius: var(--radius-md, 0.375rem);\n background-color: var(--surface-card, #ffffff);\n color: var(--text-primary, #111827);\n font-size: var(--font-size-sm, 0.875rem);\n cursor: pointer;\n transition: border-color var(--motion-duration-fast, 150ms)\n var(--motion-easing-default, ease);\n white-space: nowrap;\n}\n\n@media (hover: hover) {\n .trigger:hover:not(.disabled) {\n border-color: var(--border-strong, #d1d5db);\n }\n}\n\n.trigger:focus-visible {\n outline: var(--focus-ring-width, 2px) solid var(--border-focus, #3b82f6);\n outline-offset: var(--focus-ring-offset, 2px);\n}\n\n.placeholder {\n color: var(--text-tertiary, #9ca3af);\n}\n\n.disabled {\n opacity: 0.5;\n cursor: not-allowed;\n}\n\n.icon {\n color: var(--text-tertiary, #9ca3af);\n flex-shrink: 0;\n}\n\n/* Popover Content */\n.content {\n z-index: 50;\n width: max-content; /* two-month calendar needs room to expand */\n /* --field-menu-bg tracks the field fill; falls back to --surface-popover, then --surface-card.\n Note: glass themes (Blackout) make --surface-card ~4% alpha, so the --surface-popover fallback is important. */\n background-color: var(--field-menu-bg, var(--surface-popover, var(--surface-card, #ffffff)));\n border: 1px solid var(--border-default, #e5e7eb);\n border-radius: var(--radius-lg, 0.5rem);\n box-shadow: var(\n --shadow-md,\n 0 4px 6px -1px rgba(0, 0, 0, 0.1),\n 0 2px 4px -2px rgba(0, 0, 0, 0.1)\n );\n}\n"
1359
1365
  }
1360
1366
  ]
1361
1367
  },
@@ -1643,7 +1649,7 @@
1643
1649
  {
1644
1650
  "path": "components/ui/number-input/number-input.module.css",
1645
1651
  "type": "registry:ui",
1646
- "content": "/* Number input wrapper */\n.wrapper {\n display: inline-flex;\n align-items: center;\n border: 1px solid var(--border-default, #e5e7eb);\n border-radius: var(--radius-md, 0.375rem);\n background-color: var(--surface-interactive-default, #f9fafb);\n overflow: hidden;\n transition: border-color var(--motion-duration-150, 150ms) var(--motion-easing-default, ease-in-out),\n box-shadow var(--motion-duration-150, 150ms) var(--motion-easing-default, ease-in-out);\n}\n\n@media (hover: hover) {\n .button:hover {\n color: var(--text-primary, #111827);\n background-color: var(--surface-muted, #f3f4f6);\n }\n}\n\n.wrapper:focus-within {\n border-color: var(--border-focus, #111827);\n box-shadow: 0 0 0 var(--focus-ring-width, 2px) color-mix(in srgb, var(--border-focus, #111827) 15%, transparent);\n}\n\n.wrapperDisabled {\n opacity: 0.5;\n pointer-events: none;\n}\n\n/* Stepper buttons */\n.button {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 2.25rem;\n height: 2.25rem;\n padding: 0;\n border: none;\n background: transparent;\n color: var(--text-secondary, #9ca3af);\n cursor: pointer;\n flex-shrink: 0;\n transition: color var(--motion-duration-150, 150ms) var(--motion-easing-default, ease-in-out),\n background-color var(--motion-duration-150, 150ms) var(--motion-easing-default, ease-in-out);\n}\n\n.button:active {\n background-color: var(--surface-interactive-hover, #e5e7eb);\n transition: none;\n}\n\n.button:focus-visible {\n outline: var(--focus-ring-width, 2px) solid var(--border-focus, currentColor);\n outline-offset: var(--focus-ring-offset, -2px);\n}\n\n.button:disabled {\n cursor: not-allowed;\n opacity: 0.5;\n}\n\n.buttonIcon {\n width: 0.875rem;\n height: 0.875rem;\n}\n\n/* Input */\n.input {\n width: 4rem;\n height: 2.25rem;\n padding: 0;\n border: none;\n background: transparent;\n text-align: center;\n font-size: var(--font-size-sm, 0.875rem);\n color: var(--text-primary, #111827);\n outline: none;\n}\n\n.input::placeholder {\n color: var(--text-secondary, #9ca3af);\n}\n"
1652
+ "content": "/* Number input wrapper */\n.wrapper {\n display: inline-flex;\n align-items: center;\n border: 1px solid var(--number-input-border, var(--border-default, #e5e7eb));\n border-radius: var(--radius-md, 0.375rem);\n background-color: var(--number-input-bg, var(--surface-interactive-default, #f9fafb));\n overflow: hidden;\n transition: border-color var(--motion-duration-150, 150ms) var(--motion-easing-default, ease-in-out),\n box-shadow var(--motion-duration-150, 150ms) var(--motion-easing-default, ease-in-out);\n}\n\n@media (hover: hover) {\n .button:hover {\n color: var(--text-primary, #111827);\n background-color: var(--surface-muted, #f3f4f6);\n }\n}\n\n.wrapper:focus-within {\n border-color: var(--border-focus, #111827);\n box-shadow: 0 0 0 var(--focus-ring-width, 2px) color-mix(in srgb, var(--border-focus, #111827) 15%, transparent);\n}\n\n.wrapperDisabled {\n opacity: 0.5;\n pointer-events: none;\n}\n\n/* Stepper buttons */\n.button {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 2.25rem;\n height: 2.25rem;\n padding: 0;\n border: none;\n background: transparent;\n color: var(--text-secondary, #9ca3af);\n cursor: pointer;\n flex-shrink: 0;\n transition: color var(--motion-duration-150, 150ms) var(--motion-easing-default, ease-in-out),\n background-color var(--motion-duration-150, 150ms) var(--motion-easing-default, ease-in-out);\n}\n\n.button:active {\n background-color: var(--surface-interactive-hover, #e5e7eb);\n transition: none;\n}\n\n.button:focus-visible {\n outline: var(--focus-ring-width, 2px) solid var(--border-focus, currentColor);\n outline-offset: var(--focus-ring-offset, -2px);\n}\n\n.button:disabled {\n cursor: not-allowed;\n opacity: 0.5;\n}\n\n.buttonIcon {\n width: 0.875rem;\n height: 0.875rem;\n}\n\n/* Input */\n.input {\n width: 4rem;\n height: 2.25rem;\n padding: 0;\n border: none;\n background: transparent;\n text-align: center;\n font-size: var(--font-size-sm, 0.875rem);\n color: var(--text-primary, #111827);\n outline: none;\n}\n\n.input::placeholder {\n color: var(--text-secondary, #9ca3af);\n}\n"
1647
1653
  }
1648
1654
  ]
1649
1655
  },
@@ -1668,7 +1674,7 @@
1668
1674
  {
1669
1675
  "path": "components/ui/phone-input/phone-input.css",
1670
1676
  "type": "registry:ui",
1671
- "content": "/* intl-tel-input theme overrides — Visor design tokens\n *\n * Global (not CSS Module) because intl-tel-input renders DOM outside React\n * and appends the dropdown to document.body. All overrides need !important\n * to beat the library's shipped styles loaded via dynamic import.\n *\n * Token mapping from Blacklight --theme-* → Visor semantic tokens:\n * --theme-background → --surface-interactive-default (inputs)\n * --theme-muted → --surface-card (dropdown surfaces)\n * --theme-border → --border-default\n * --theme-foreground → --text-primary\n * --theme-muted-foreground → --text-secondary\n * --theme-accent → --interactive-primary-bg (selected state)\n * --theme-accent-foreground → --text-inverse (text on accent)\n */\n\n/* Container fills available width */\n.iti {\n display: block !important;\n width: 100% !important;\n}\n\n/* The input element itself — match Visor Input component (input.module.css) */\n.iti input.iti__tel-input {\n width: 100% !important;\n min-width: 0 !important;\n border: 1px solid var(--border-default, #e5e7eb) !important;\n background-color: var(--surface-interactive-default, #f9fafb) !important;\n /* padding-left is set dynamically by intl-tel-input to fit the flag + dial code */\n color: var(--text-primary, #111827) !important;\n line-height: 1.5 !important;\n transition: border-color var(--motion-duration-150, 150ms) var(--motion-easing-default, ease-in-out),\n box-shadow var(--motion-duration-150, 150ms) var(--motion-easing-default, ease-in-out) !important;\n outline: none !important;\n}\n\n/* Size: sm — compact (default for backwards compat) */\n[data-size=\"sm\"] .iti input.iti__tel-input {\n height: 2.25rem !important;\n padding-top: var(--spacing-1, 0.25rem) !important;\n padding-bottom: var(--spacing-1, 0.25rem) !important;\n padding-right: var(--spacing-3, 0.75rem) !important;\n font-size: var(--font-size-sm, 0.875rem) !important;\n border-radius: var(--radius-sm, 0.25rem) !important;\n}\n\n/* Size: md (default) */\n[data-size=\"md\"] .iti input.iti__tel-input {\n height: auto !important;\n padding-top: 0.875rem !important;\n padding-bottom: 0.875rem !important;\n padding-right: 1rem !important;\n font-size: var(--font-size-sm, 0.875rem) !important;\n border-radius: var(--radius-sm, 0.5rem) !important;\n}\n\n/* Size: lg */\n[data-size=\"lg\"] .iti input.iti__tel-input {\n height: auto !important;\n padding-top: 1.125rem !important;\n padding-bottom: 1.125rem !important;\n padding-right: 1.25rem !important;\n font-size: var(--font-size-base, 1rem) !important;\n border-radius: var(--radius-sm, 0.5rem) !important;\n}\n\n.iti input.iti__tel-input::placeholder {\n color: var(--text-secondary, #9ca3af) !important;\n}\n\n.iti input.iti__tel-input:focus {\n border-color: var(--border-focus, #111827) !important;\n box-shadow: 0 0 0 var(--focus-ring-width, 2px) color-mix(in srgb, var(--border-focus, #111827) 15%, transparent) !important;\n}\n\n.iti input.iti__tel-input:disabled {\n pointer-events: none !important;\n cursor: not-allowed !important;\n opacity: 0.5 !important;\n}\n\n/* Dropdown content (search + country list container) — must be opaque since\n intl-tel-input renders on document.body, potentially outside theme wrappers */\n.iti__dropdown-content {\n background-color: var(--surface-card, #ffffff) !important;\n border: 1px solid var(--border-default, #e5e7eb) !important;\n border-radius: var(--radius-lg, 0.5rem) !important;\n box-shadow: var(--shadow-md) !important;\n z-index: var(--z-index-dropdown, 1000) !important;\n min-width: 18rem !important;\n}\n\n/* Search input inside dropdown — match Visor Input base */\n.iti__search-input {\n background-color: var(--surface-interactive-default, #f9fafb) !important;\n border: 1px solid var(--border-default, #e5e7eb) !important;\n color: var(--text-primary, #111827) !important;\n border-radius: var(--radius-md, 0.375rem) !important;\n padding: var(--spacing-2, 0.5rem) var(--spacing-2, 0.5rem) var(--spacing-2, 0.5rem) 2rem !important;\n font-size: var(--font-size-sm, 0.875rem) !important;\n outline: none !important;\n transition: border-color var(--motion-duration-150, 150ms) var(--motion-easing-default, ease-in-out) !important;\n}\n\n.iti__search-input:focus {\n border-color: var(--border-focus, #111827) !important;\n box-shadow: 0 0 0 var(--focus-ring-width, 2px) color-mix(in srgb, var(--border-focus, #111827) 15%, transparent) !important;\n}\n\n.iti__search-input::placeholder {\n color: var(--text-secondary, #9ca3af) !important;\n}\n\n/* Divider between search and country list */\n.iti__search-input-wrapper {\n border-bottom: 1px solid var(--border-default, #e5e7eb) !important;\n}\n\n/* Country list background — matches dropdown content */\n.iti__country-list {\n background-color: var(--surface-card, #ffffff) !important;\n}\n\n/* Individual country items — match Select .item */\n.iti__country {\n color: var(--text-primary, #111827) !important;\n padding: var(--spacing-2, 0.5rem) var(--spacing-3, 0.75rem) !important;\n font-size: var(--font-size-sm, 0.875rem) !important;\n line-height: 1.4 !important;\n white-space: nowrap !important;\n gap: var(--spacing-2, 0.5rem) !important;\n}\n\n/* Hover and keyboard highlight — match Select .item:focus */\n.iti__country:hover,\n.iti__country.iti__highlight {\n background-color: var(--surface-interactive-hover, #f3f4f6) !important;\n}\n\n/* Selected/active country — match interactive primary */\n.iti__country.iti__active {\n background-color: var(--interactive-primary-bg, #111827) !important;\n color: var(--text-inverse, #ffffff) !important;\n}\n\n/* Dial code in country list */\n.iti__dial-code {\n color: var(--text-secondary, #9ca3af) !important;\n}\n\n/* Inherit color for active state (overrides dial-code muted color) */\n.iti__country-name,\n.iti__country.iti__active .iti__country-name,\n.iti__country.iti__active .iti__dial-code {\n color: inherit !important;\n}\n\n/* Selected country button (dropdown trigger in the input) */\n.iti__selected-country {\n background-color: transparent !important;\n border-radius: var(--radius-md, 0.375rem) 0 0 var(--radius-md, 0.375rem) !important;\n transition: background-color var(--motion-duration-150, 150ms) var(--motion-easing-default, ease-in-out) !important;\n}\n\n.iti__selected-country:hover,\n.iti__selected-country:focus {\n background-color: var(--surface-interactive-hover, #f3f4f6) !important;\n}\n\n/* Arrow/chevron */\n.iti__arrow {\n border-top-color: var(--text-secondary, #9ca3af) !important;\n}\n\n.iti__arrow--up {\n border-bottom-color: var(--text-secondary, #9ca3af) !important;\n}\n\n/* Selected dial code text */\n.iti__selected-dial-code {\n color: var(--text-primary, #111827) !important;\n margin-right: var(--spacing-2, 0.5rem) !important;\n}\n"
1677
+ "content": "/* intl-tel-input theme overrides — Visor design tokens\n *\n * Global (not CSS Module) because intl-tel-input renders DOM outside React\n * and appends the dropdown to document.body. All overrides need !important\n * to beat the library's shipped styles loaded via dynamic import.\n *\n * Token mapping from Blacklight --theme-* → Visor semantic tokens:\n * --theme-background → --surface-interactive-default (inputs)\n * --theme-muted → --surface-card (dropdown surfaces)\n * --theme-border → --border-default\n * --theme-foreground → --text-primary\n * --theme-muted-foreground → --text-secondary\n * --theme-accent → --interactive-primary-bg (selected state)\n * --theme-accent-foreground → --text-inverse (text on accent)\n */\n\n/* Container fills available width */\n.iti {\n display: block !important;\n width: 100% !important;\n}\n\n/* The input element itself — match Visor Input component (input.module.css) */\n.iti input.iti__tel-input {\n width: 100% !important;\n min-width: 0 !important;\n border: 1px solid var(--border-default, #e5e7eb) !important;\n background-color: var(--surface-interactive-default, #f9fafb) !important;\n /* padding-left is set dynamically by intl-tel-input to fit the flag + dial code */\n color: var(--text-primary, #111827) !important;\n line-height: 1.5 !important;\n transition: border-color var(--motion-duration-150, 150ms) var(--motion-easing-default, ease-in-out),\n box-shadow var(--motion-duration-150, 150ms) var(--motion-easing-default, ease-in-out) !important;\n outline: none !important;\n}\n\n/* Size: sm — compact (default for backwards compat) */\n[data-size=\"sm\"] .iti input.iti__tel-input {\n height: 2.25rem !important;\n padding-top: var(--spacing-1, 0.25rem) !important;\n padding-bottom: var(--spacing-1, 0.25rem) !important;\n padding-right: var(--spacing-3, 0.75rem) !important;\n font-size: var(--font-size-sm, 0.875rem) !important;\n border-radius: var(--radius-sm, 0.25rem) !important;\n}\n\n/* Size: md (default) */\n[data-size=\"md\"] .iti input.iti__tel-input {\n height: auto !important;\n padding-top: 0.875rem !important;\n padding-bottom: 0.875rem !important;\n padding-right: 1rem !important;\n font-size: var(--font-size-sm, 0.875rem) !important;\n border-radius: var(--radius-sm, 0.5rem) !important;\n}\n\n/* Size: lg */\n[data-size=\"lg\"] .iti input.iti__tel-input {\n height: auto !important;\n padding-top: 1.125rem !important;\n padding-bottom: 1.125rem !important;\n padding-right: 1.25rem !important;\n font-size: var(--font-size-base, 1rem) !important;\n border-radius: var(--radius-sm, 0.5rem) !important;\n}\n\n.iti input.iti__tel-input::placeholder {\n color: var(--text-secondary, #9ca3af) !important;\n}\n\n.iti input.iti__tel-input:focus {\n border-color: var(--border-focus, #111827) !important;\n box-shadow: 0 0 0 var(--focus-ring-width, 2px) color-mix(in srgb, var(--border-focus, #111827) 15%, transparent) !important;\n}\n\n.iti input.iti__tel-input:disabled {\n pointer-events: none !important;\n cursor: not-allowed !important;\n opacity: 0.5 !important;\n}\n\n/* Dropdown content (search + country list container) — must be opaque since\n intl-tel-input renders on document.body, potentially outside theme wrappers */\n.iti__dropdown-content {\n background-color: var(--surface-card, #ffffff) !important;\n border: 1px solid var(--border-default, #e5e7eb) !important;\n border-radius: var(--radius-lg, 0.5rem) !important;\n box-shadow: var(--shadow-md) !important;\n z-index: var(--z-index-dropdown, 1000) !important;\n min-width: 18rem !important;\n}\n\n/* Search input inside dropdown — match Visor Input base */\n.iti__search-input {\n background-color: var(--surface-interactive-default, #f9fafb) !important;\n border: 1px solid var(--border-default, #e5e7eb) !important;\n color: var(--text-primary, #111827) !important;\n border-radius: var(--radius-md, 0.375rem) !important;\n padding: var(--spacing-2, 0.5rem) var(--spacing-2, 0.5rem) var(--spacing-2, 0.5rem) 2rem !important;\n font-size: var(--font-size-sm, 0.875rem) !important;\n outline: none !important;\n transition: border-color var(--motion-duration-150, 150ms) var(--motion-easing-default, ease-in-out) !important;\n}\n\n.iti__search-input:focus {\n border-color: var(--border-focus, #111827) !important;\n box-shadow: 0 0 0 var(--focus-ring-width, 2px) color-mix(in srgb, var(--border-focus, #111827) 15%, transparent) !important;\n}\n\n.iti__search-input::placeholder {\n color: var(--text-secondary, #9ca3af) !important;\n}\n\n/* Divider between search and country list */\n.iti__search-input-wrapper {\n border-bottom: 1px solid var(--border-default, #e5e7eb) !important;\n}\n\n/* Country list background — matches dropdown content */\n.iti__country-list {\n background-color: var(--surface-card, #ffffff) !important;\n}\n\n/* Individual country items — match Select .item */\n.iti__country {\n color: var(--text-primary, #111827) !important;\n padding: var(--spacing-2, 0.5rem) var(--spacing-3, 0.75rem) !important;\n font-size: var(--font-size-sm, 0.875rem) !important;\n line-height: 1.4 !important;\n white-space: nowrap !important;\n gap: var(--spacing-2, 0.5rem) !important;\n}\n\n/* Hover and keyboard highlight — match Select .item:focus */\n.iti__country:hover,\n.iti__country.iti__highlight {\n background-color: var(--surface-interactive-hover, #f3f4f6) !important;\n}\n\n/* Selected/active country — match interactive primary */\n.iti__country.iti__active {\n background-color: var(--interactive-primary-bg, var(--primary, #111827)) !important;\n color: var(--text-inverse, #ffffff) !important;\n}\n\n/* Dial code in country list */\n.iti__dial-code {\n color: var(--text-secondary, #9ca3af) !important;\n}\n\n/* Inherit color for active state (overrides dial-code muted color) */\n.iti__country-name,\n.iti__country.iti__active .iti__country-name,\n.iti__country.iti__active .iti__dial-code {\n color: inherit !important;\n}\n\n/* Selected country button (dropdown trigger in the input) */\n.iti__selected-country {\n background-color: transparent !important;\n border-radius: var(--radius-md, 0.375rem) 0 0 var(--radius-md, 0.375rem) !important;\n transition: background-color var(--motion-duration-150, 150ms) var(--motion-easing-default, ease-in-out) !important;\n}\n\n.iti__selected-country:hover,\n.iti__selected-country:focus {\n background-color: var(--surface-interactive-hover, #f3f4f6) !important;\n}\n\n/* Arrow/chevron */\n.iti__arrow {\n border-top-color: var(--text-secondary, #9ca3af) !important;\n}\n\n.iti__arrow--up {\n border-bottom-color: var(--text-secondary, #9ca3af) !important;\n}\n\n/* Selected dial code text */\n.iti__selected-dial-code {\n color: var(--text-primary, #111827) !important;\n margin-right: var(--spacing-2, 0.5rem) !important;\n}\n"
1672
1678
  },
1673
1679
  {
1674
1680
  "path": "components/ui/phone-input/phone-input.module.css",
@@ -1697,7 +1703,7 @@
1697
1703
  {
1698
1704
  "path": "components/ui/otp-input/otp-input.module.css",
1699
1705
  "type": "registry:ui",
1700
- "content": "/* OTP input wrapper */\n.wrapper {\n display: inline-flex;\n gap: var(--spacing-2, 0.5rem);\n}\n\n/* Individual digit cell */\n.cell {\n width: 2.5rem;\n height: 2.75rem;\n border: 1px solid var(--border-default, #e5e7eb);\n border-radius: var(--radius-md, 0.375rem);\n background-color: var(--surface-interactive-default, #f9fafb);\n text-align: center;\n font-size: var(--font-size-lg, 1.125rem);\n font-weight: var(--font-weight-medium, 500);\n color: var(--text-primary, #111827);\n outline: none;\n transition: border-color var(--motion-duration-150, 150ms) var(--motion-easing-default, ease-in-out),\n box-shadow var(--motion-duration-150, 150ms) var(--motion-easing-default, ease-in-out);\n}\n\n.cell::placeholder {\n color: var(--text-secondary, #9ca3af);\n}\n\n@media (hover: hover) {\n .cell:hover:not(:focus-visible):not(:disabled) {\n border-color: var(--border-strong, #d1d5db);\n }\n}\n\n.cell:focus-visible {\n border-color: var(--border-focus, #111827);\n box-shadow: 0 0 0 var(--focus-ring-width, 2px) color-mix(in srgb, var(--border-focus, #111827) 15%, transparent);\n}\n\n.cell:disabled {\n pointer-events: none;\n cursor: not-allowed;\n opacity: 0.5;\n}\n\n.cellFilled {\n border-color: var(--border-focus, #111827);\n}\n"
1706
+ "content": "/* OTP input wrapper */\n.wrapper {\n display: inline-flex;\n gap: var(--spacing-2, 0.5rem);\n}\n\n/* Individual digit cell */\n.cell {\n width: 2.5rem;\n height: 2.75rem;\n border: 1px solid var(--otp-border, var(--border-default, #e5e7eb));\n border-radius: var(--radius-md, 0.375rem);\n background-color: var(--otp-bg, var(--surface-interactive-default, #f9fafb));\n text-align: center;\n font-size: var(--font-size-lg, 1.125rem);\n font-weight: var(--font-weight-medium, 500);\n color: var(--text-primary, #111827);\n outline: none;\n transition: border-color var(--motion-duration-150, 150ms) var(--motion-easing-default, ease-in-out),\n box-shadow var(--motion-duration-150, 150ms) var(--motion-easing-default, ease-in-out);\n}\n\n.cell::placeholder {\n color: var(--text-secondary, #9ca3af);\n}\n\n@media (hover: hover) {\n .cell:hover:not(:focus-visible):not(:disabled) {\n border-color: var(--border-strong, #d1d5db);\n }\n}\n\n.cell:focus-visible {\n border-color: var(--border-focus, #111827);\n box-shadow: 0 0 0 var(--focus-ring-width, 2px) color-mix(in srgb, var(--border-focus, #111827) 15%, transparent);\n}\n\n.cell:disabled {\n pointer-events: none;\n cursor: not-allowed;\n opacity: 0.5;\n}\n\n.cellFilled {\n border-color: var(--border-focus, #111827);\n}\n"
1701
1707
  }
1702
1708
  ]
1703
1709
  },
@@ -1722,7 +1728,7 @@
1722
1728
  {
1723
1729
  "path": "components/ui/tag-input/tag-input.module.css",
1724
1730
  "type": "registry:ui",
1725
- "content": "/* Tag input wrapper — styled like an Input */\n.wrapper {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: var(--spacing-1, 0.25rem);\n min-height: 2.25rem;\n width: 100%;\n border-radius: var(--radius-md, 0.375rem);\n border: 1px solid var(--border-default, #e5e7eb);\n background-color: var(--surface-interactive-default, #f9fafb);\n padding: var(--spacing-1, 0.25rem) var(--spacing-2, 0.5rem);\n cursor: text;\n transition: border-color var(--motion-duration-150, 150ms) var(--motion-easing-default, ease-in-out),\n box-shadow var(--motion-duration-150, 150ms) var(--motion-easing-default, ease-in-out);\n}\n\n@media (hover: hover) {\n .wrapper:hover:not(.wrapperFocused):not(.wrapperDisabled) {\n border-color: var(--border-strong, #d1d5db);\n }\n}\n\n.wrapperFocused {\n border-color: var(--border-focus, #111827);\n box-shadow: 0 0 0 var(--focus-ring-width, 2px) color-mix(in srgb, var(--border-focus, #111827) 15%, transparent);\n}\n\n.wrapperDisabled {\n pointer-events: none;\n cursor: not-allowed;\n opacity: 0.5;\n}\n\n/* Individual tag chip */\n.tag {\n display: inline-flex;\n align-items: center;\n gap: var(--spacing-1, 0.25rem);\n padding: calc(var(--spacing-1, 0.25rem) / 4) var(--spacing-2, 0.5rem);\n border-radius: var(--radius-full, 9999px);\n background-color: var(--surface-muted, #f3f4f6);\n border: 1px solid var(--border-default, #e5e7eb);\n font-size: var(--font-size-xs, 0.75rem);\n line-height: 1.5;\n color: var(--text-primary, #111827);\n}\n\n.tagLabel {\n white-space: nowrap;\n}\n\n.tagRemove {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 0.875rem;\n height: 0.875rem;\n padding: 0;\n border: none;\n background: transparent;\n color: var(--text-secondary, #9ca3af);\n cursor: pointer;\n border-radius: var(--radius-full, 9999px);\n transition: color var(--motion-duration-150, 150ms) var(--motion-easing-default, ease-in-out);\n}\n\n@media (hover: hover) {\n .tagRemove:hover {\n color: var(--text-primary, #111827);\n }\n}\n\n.tagRemove svg {\n width: 0.625rem;\n height: 0.625rem;\n}\n\n/* Inline text input */\n.input {\n flex: 1;\n min-width: 4rem;\n height: 1.5rem;\n padding: 0;\n border: none;\n background: transparent;\n font-size: var(--font-size-sm, 0.875rem);\n color: var(--text-primary, #111827);\n outline: none;\n}\n\n.input::placeholder {\n color: var(--text-secondary, #9ca3af);\n}\n"
1731
+ "content": "/* Tag input wrapper — styled like an Input */\n.wrapper {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: var(--spacing-1, 0.25rem);\n min-height: 2.25rem;\n width: 100%;\n border-radius: var(--radius-md, 0.375rem);\n border: 1px solid var(--tag-input-border, var(--border-default, #e5e7eb));\n background-color: var(--tag-input-bg, var(--surface-interactive-default, #f9fafb));\n padding: var(--spacing-1, 0.25rem) var(--spacing-2, 0.5rem);\n cursor: text;\n transition: border-color var(--motion-duration-150, 150ms) var(--motion-easing-default, ease-in-out),\n box-shadow var(--motion-duration-150, 150ms) var(--motion-easing-default, ease-in-out);\n}\n\n@media (hover: hover) {\n .wrapper:hover:not(.wrapperFocused):not(.wrapperDisabled) {\n border-color: var(--border-strong, #d1d5db);\n }\n}\n\n.wrapperFocused {\n border-color: var(--border-focus, #111827);\n box-shadow: 0 0 0 var(--focus-ring-width, 2px) color-mix(in srgb, var(--border-focus, #111827) 15%, transparent);\n}\n\n.wrapperDisabled {\n pointer-events: none;\n cursor: not-allowed;\n opacity: 0.5;\n}\n\n/* Individual tag chip */\n.tag {\n display: inline-flex;\n align-items: center;\n gap: var(--spacing-1, 0.25rem);\n padding: calc(var(--spacing-1, 0.25rem) / 4) var(--spacing-2, 0.5rem);\n border-radius: var(--radius-full, 9999px);\n background-color: var(--surface-muted, #f3f4f6);\n border: 1px solid var(--border-default, #e5e7eb);\n font-size: var(--font-size-xs, 0.75rem);\n line-height: 1.5;\n color: var(--text-primary, #111827);\n}\n\n.tagLabel {\n white-space: nowrap;\n}\n\n.tagRemove {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 0.875rem;\n height: 0.875rem;\n padding: 0;\n border: none;\n background: transparent;\n color: var(--text-secondary, #9ca3af);\n cursor: pointer;\n border-radius: var(--radius-full, 9999px);\n transition: color var(--motion-duration-150, 150ms) var(--motion-easing-default, ease-in-out);\n}\n\n@media (hover: hover) {\n .tagRemove:hover {\n color: var(--text-primary, #111827);\n }\n}\n\n.tagRemove svg {\n width: 0.625rem;\n height: 0.625rem;\n}\n\n/* Inline text input */\n.input {\n flex: 1;\n min-width: 4rem;\n height: 1.5rem;\n padding: 0;\n border: none;\n background: transparent;\n font-size: var(--font-size-sm, 0.875rem);\n color: var(--text-primary, #111827);\n outline: none;\n}\n\n.input::placeholder {\n color: var(--text-secondary, #9ca3af);\n}\n"
1726
1732
  }
1727
1733
  ]
1728
1734
  },
@@ -2098,7 +2104,7 @@
2098
2104
  {
2099
2105
  "path": "components/ui/chrome-button/chrome-button.module.css",
2100
2106
  "type": "registry:ui",
2101
- "content": "/* ChromeButton — 28px topbar/chrome button primitive.\n *\n * Compact dimensions for admin chrome contexts (topbar, toolbar). Composes a\n * leading icon, a label, and a trailing Kbd hint at chrome density. Fully\n * theme-portable — all colors, motion, and radius bind to Visor tokens.\n */\n.root {\n display: inline-flex;\n align-items: center;\n gap: var(--spacing-2, 0.5rem);\n height: 1.75rem; /* 28px */\n padding: 0 var(--spacing-3, 0.75rem);\n border-radius: var(--radius-md, 0.375rem);\n border: 1px solid transparent;\n font-size: var(--font-size-sm, 0.875rem);\n font-weight: var(--font-weight-medium, 500);\n line-height: 1;\n cursor: pointer;\n outline: none;\n white-space: nowrap;\n transition:\n background-color var(--motion-duration-150, 150ms)\n var(--motion-easing-default, ease-in-out),\n color var(--motion-duration-150, 150ms)\n var(--motion-easing-default, ease-in-out),\n border-color var(--motion-duration-150, 150ms)\n var(--motion-easing-default, ease-in-out),\n opacity var(--motion-duration-150, 150ms)\n var(--motion-easing-default, ease-in-out);\n}\n\n.root:focus-visible {\n outline: var(--focus-ring-width, 2px) solid\n var(--border-focus, currentColor);\n outline-offset: var(--focus-ring-offset, 2px);\n}\n\n.root:active:not(:disabled) {\n transform: translateY(1px);\n transition: none;\n}\n\n.root:disabled {\n pointer-events: none;\n opacity: var(--opacity-50, 0.5);\n}\n\n/* Variants */\n.variantDefault {\n background-color: var(--surface-interactive-default, #f3f4f6);\n color: var(--text-primary, #111827);\n}\n\n.variantPrimary {\n background-color: var(--interactive-primary-bg, var(--accent-primary, #111827));\n color: var(--interactive-primary-text, var(--text-inverse, #f9fafb));\n font-weight: var(--font-weight-semibold, 600);\n}\n\n@media (hover: hover) {\n .variantDefault:hover {\n background-color: var(--surface-interactive-hover, #e5e7eb);\n }\n\n .variantPrimary:hover {\n background-color: var(--interactive-primary-bg-hover, color-mix(in srgb, var(--accent-primary, #111827) 85%, white));\n }\n}\n\n/* Slots */\n.icon {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n font-size: var(--font-size-sm, 0.875rem);\n line-height: 1;\n}\n\n.icon svg {\n display: block;\n}\n\n.label {\n display: inline-flex;\n align-items: center;\n line-height: 1;\n}\n\n.keys {\n display: inline-flex;\n align-items: center;\n margin-left: calc(var(--spacing-1, 0.25rem) / 2);\n}\n"
2107
+ "content": "/* ChromeButton — 28px topbar/chrome button primitive.\n *\n * Compact dimensions for admin chrome contexts (topbar, toolbar). Composes a\n * leading icon, a label, and a trailing Kbd hint at chrome density. Fully\n * theme-portable — all colors, motion, and radius bind to Visor tokens.\n */\n.root {\n display: inline-flex;\n align-items: center;\n gap: var(--spacing-2, 0.5rem);\n height: 1.75rem; /* 28px */\n padding: 0 var(--spacing-3, 0.75rem);\n border-radius: var(--radius-md, 0.375rem);\n border: 1px solid transparent;\n font-size: var(--font-size-sm, 0.875rem);\n font-weight: var(--font-weight-medium, 500);\n line-height: 1;\n cursor: pointer;\n outline: none;\n white-space: nowrap;\n transition:\n background-color var(--motion-duration-150, 150ms)\n var(--motion-easing-default, ease-in-out),\n color var(--motion-duration-150, 150ms)\n var(--motion-easing-default, ease-in-out),\n border-color var(--motion-duration-150, 150ms)\n var(--motion-easing-default, ease-in-out),\n opacity var(--motion-duration-150, 150ms)\n var(--motion-easing-default, ease-in-out);\n}\n\n.root:focus-visible {\n outline: var(--focus-ring-width, 2px) solid\n var(--border-focus, currentColor);\n outline-offset: var(--focus-ring-offset, 2px);\n}\n\n.root:active:not(:disabled) {\n transform: translateY(1px);\n transition: none;\n}\n\n.root:disabled {\n pointer-events: none;\n opacity: var(--opacity-50, 0.5);\n}\n\n/* Variants */\n.variantDefault {\n background-color: var(--surface-interactive-default, #f3f4f6);\n color: var(--text-primary, #111827);\n}\n\n.variantPrimary {\n background-color: var(--interactive-primary-bg, var(--primary, #111827));\n color: var(--interactive-primary-text, var(--text-inverse, #f9fafb));\n font-weight: var(--font-weight-semibold, 600);\n}\n\n@media (hover: hover) {\n .variantDefault:hover {\n background-color: var(--surface-interactive-hover, #e5e7eb);\n }\n\n .variantPrimary:hover {\n background-color: var(--interactive-primary-bg-hover, color-mix(in srgb, var(--primary, #111827) 85%, white));\n }\n}\n\n/* Slots */\n.icon {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n font-size: var(--font-size-sm, 0.875rem);\n line-height: 1;\n}\n\n.icon svg {\n display: block;\n}\n\n.label {\n display: inline-flex;\n align-items: center;\n line-height: 1;\n}\n\n.keys {\n display: inline-flex;\n align-items: center;\n margin-left: calc(var(--spacing-1, 0.25rem) / 2);\n}\n"
2102
2108
  }
2103
2109
  ]
2104
2110
  },
@@ -2121,12 +2127,12 @@
2121
2127
  {
2122
2128
  "path": "components/ui/confirm-dialog/confirm-dialog.tsx",
2123
2129
  "type": "registry:ui",
2124
- "content": "\"use client\"\n\nimport * as React from \"react\"\nimport {\n InfoIcon,\n WarningIcon,\n WarningOctagonIcon,\n} from \"@phosphor-icons/react\"\nimport { cn } from \"../../../lib/utils\"\nimport {\n Dialog,\n DialogContent,\n DialogDescription,\n DialogHeader,\n DialogTitle,\n DialogTrigger,\n} from \"../dialog/dialog\"\nimport { Button } from \"../button/button\"\nimport styles from \"./confirm-dialog.module.css\"\n\nexport type ConfirmDialogSeverity = \"info\" | \"warning\" | \"danger\"\n\nexport interface ConfirmDialogProps {\n /** Controlled open state. */\n open?: boolean\n /** Uncontrolled initial open state. */\n defaultOpen?: boolean\n /** Called when open state changes. */\n onOpenChange?: (open: boolean) => void\n\n /** Optional trigger — wrapped in DialogTrigger. Omit for fully-controlled usage. */\n trigger?: React.ReactNode\n\n /** Dialog title — rendered in DialogTitle next to the severity icon. */\n title: React.ReactNode\n /** Short body above the action row. Used as DialogDescription. */\n description?: React.ReactNode\n /** Richer body slot — overrides description when provided. */\n children?: React.ReactNode\n\n /** Severity — drives icon color, confirm button variant. Default \"warning\". */\n severity?: ConfirmDialogSeverity\n\n /** Confirm button label. Defaults: \"Delete\" for danger, \"Confirm\" otherwise. */\n confirmLabel?: React.ReactNode\n /** Cancel button label. Default \"Cancel\". */\n cancelLabel?: React.ReactNode\n\n /** If set, user must type this exact string to enable the confirm button. */\n confirmText?: string\n /** Label for the confirm-text input. Default: `Type ${confirmText} to confirm`. */\n confirmTextLabel?: React.ReactNode\n\n /** Confirm handler. Async-aware: returning a Promise puts the dialog into pending state. */\n onConfirm?: () => void | Promise<void>\n /** Cancel handler. */\n onCancel?: () => void\n\n /** Externally-controlled busy state — overrides internal async pending detection. */\n busy?: boolean\n\n /** Additional className on DialogContent. */\n className?: string\n}\n\nfunction getSeverityIcon(severity: ConfirmDialogSeverity): React.ReactNode {\n switch (severity) {\n case \"info\":\n return <InfoIcon weight=\"fill\" aria-hidden=\"true\" />\n case \"danger\":\n return <WarningOctagonIcon weight=\"fill\" aria-hidden=\"true\" />\n case \"warning\":\n default:\n return <WarningIcon weight=\"fill\" aria-hidden=\"true\" />\n }\n}\n\nfunction getSeverityIconClass(severity: ConfirmDialogSeverity): string {\n switch (severity) {\n case \"info\":\n return styles.iconInfo\n case \"danger\":\n return styles.iconDanger\n case \"warning\":\n default:\n return styles.iconWarning\n }\n}\n\nfunction getConfirmButtonVariant(\n severity: ConfirmDialogSeverity\n): \"default\" | \"destructive\" {\n return severity === \"danger\" ? \"destructive\" : \"default\"\n}\n\nfunction getDefaultConfirmLabel(severity: ConfirmDialogSeverity): string {\n return severity === \"danger\" ? \"Delete\" : \"Confirm\"\n}\n\nconst ConfirmDialog = React.forwardRef<\n React.ComponentRef<typeof DialogContent>,\n ConfirmDialogProps\n>(\n (\n {\n open: openProp,\n defaultOpen,\n onOpenChange,\n trigger,\n title,\n description,\n children,\n severity = \"warning\",\n confirmLabel,\n cancelLabel = \"Cancel\",\n confirmText,\n confirmTextLabel,\n onConfirm,\n onCancel,\n busy,\n className,\n },\n ref\n ) => {\n const isControlled = openProp !== undefined\n const [internalOpen, setInternalOpen] = React.useState<boolean>(\n defaultOpen ?? false\n )\n const actualOpen = isControlled ? (openProp as boolean) : internalOpen\n\n const [isPending, setIsPending] = React.useState<boolean>(false)\n const [typed, setTyped] = React.useState<string>(\"\")\n\n const cancelButtonRef = React.useRef<HTMLButtonElement | null>(null)\n\n const handleOpenChange = React.useCallback(\n (next: boolean) => {\n if (!isControlled) {\n setInternalOpen(next)\n }\n onOpenChange?.(next)\n if (!next) {\n // Clear gate typing on close\n setTyped(\"\")\n }\n },\n [isControlled, onOpenChange]\n )\n\n const resolvedConfirmLabel =\n confirmLabel ?? getDefaultConfirmLabel(severity)\n const effectiveBusy = busy ?? isPending\n const gateSatisfied =\n confirmText == null || confirmText.length === 0 || typed === confirmText\n const confirmDisabled = effectiveBusy || !gateSatisfied\n const cancelDisabled = effectiveBusy\n\n const handleConfirmClick = React.useCallback(async () => {\n if (!onConfirm) {\n handleOpenChange(false)\n return\n }\n // Any synchronous throw propagates naturally to React's error boundary.\n const result = onConfirm()\n if (result && typeof (result as Promise<void>).then === \"function\") {\n setIsPending(true)\n try {\n await result\n setIsPending(false)\n handleOpenChange(false)\n } catch (err) {\n // Async rejection — clear pending state, keep dialog open, re-throw\n // so the consumer's error handling (error boundary, onUnhandledRejection)\n // can react to it.\n setIsPending(false)\n throw err\n }\n } else {\n handleOpenChange(false)\n }\n }, [onConfirm, handleOpenChange])\n\n const handleCancelClick = React.useCallback(() => {\n onCancel?.()\n handleOpenChange(false)\n }, [onCancel, handleOpenChange])\n\n const handleOpenAutoFocus = React.useCallback(\n (event: Event) => {\n if (severity === \"danger\" && cancelButtonRef.current) {\n event.preventDefault()\n cancelButtonRef.current.focus()\n }\n },\n [severity]\n )\n\n const severityIcon = getSeverityIcon(severity)\n const severityIconClass = getSeverityIconClass(severity)\n const confirmVariant = getConfirmButtonVariant(severity)\n\n // Generate stable id for confirm gate input\n const generatedId = React.useId()\n const confirmGateInputId = `${generatedId}-confirm-input`\n\n const hasDescriptionForAria =\n description != null && description !== false && !children\n\n return (\n <Dialog\n open={actualOpen}\n defaultOpen={defaultOpen}\n onOpenChange={handleOpenChange}\n >\n {trigger ? <DialogTrigger asChild>{trigger}</DialogTrigger> : null}\n <DialogContent\n ref={ref}\n data-slot=\"confirm-dialog\"\n data-severity={severity}\n className={cn(styles.root, className)}\n onOpenAutoFocus={handleOpenAutoFocus}\n >\n <DialogHeader>\n <div className={styles.titleRow}>\n <span\n data-slot=\"confirm-dialog-icon\"\n aria-hidden=\"true\"\n className={cn(styles.icon, severityIconClass)}\n >\n {severityIcon}\n </span>\n <DialogTitle>{title}</DialogTitle>\n </div>\n {hasDescriptionForAria ? (\n <DialogDescription>{description}</DialogDescription>\n ) : null}\n </DialogHeader>\n\n {children ? (\n <div data-slot=\"confirm-dialog-body\" className={styles.body}>\n {children}\n </div>\n ) : null}\n\n {confirmText ? (\n <div className={styles.confirmGate}>\n <label\n htmlFor={confirmGateInputId}\n className={styles.confirmGateLabel}\n >\n {confirmTextLabel ?? `Type ${confirmText} to confirm`}\n </label>\n <input\n id={confirmGateInputId}\n type=\"text\"\n autoComplete=\"off\"\n spellCheck={false}\n value={typed}\n onChange={(e) => setTyped(e.target.value)}\n disabled={effectiveBusy}\n className={styles.confirmGateInput}\n data-slot=\"confirm-dialog-gate-input\"\n />\n </div>\n ) : null}\n\n <div\n data-slot=\"confirm-dialog-actions\"\n className={styles.actions}\n role=\"group\"\n >\n <div className={styles.action}>\n <Button\n ref={cancelButtonRef}\n type=\"button\"\n variant=\"outline\"\n onClick={handleCancelClick}\n disabled={cancelDisabled}\n data-slot=\"confirm-dialog-cancel\"\n >\n {cancelLabel}\n </Button>\n </div>\n <div className={styles.action}>\n <Button\n type=\"button\"\n variant={confirmVariant}\n onClick={handleConfirmClick}\n disabled={confirmDisabled}\n aria-busy={effectiveBusy || undefined}\n data-slot=\"confirm-dialog-confirm\"\n >\n {resolvedConfirmLabel}\n </Button>\n </div>\n </div>\n </DialogContent>\n </Dialog>\n )\n }\n)\nConfirmDialog.displayName = \"ConfirmDialog\"\n\nexport { ConfirmDialog }\n"
2130
+ "content": "\"use client\"\n\nimport * as React from \"react\"\nimport {\n InfoIcon,\n WarningIcon,\n WarningOctagonIcon,\n} from \"@phosphor-icons/react\"\nimport { cn } from \"../../../lib/utils\"\nimport {\n Dialog,\n DialogContent,\n DialogDescription,\n DialogHeader,\n DialogTitle,\n DialogTrigger,\n} from \"../dialog/dialog\"\nimport { Button } from \"../button/button\"\nimport styles from \"./confirm-dialog.module.css\"\n\nexport type ConfirmDialogSeverity =\n | \"info\"\n | \"warning\"\n | \"destructive\"\n /**\n * @deprecated Use `\"destructive\"` instead. `\"danger\"` will be removed in the next major version.\n */\n | \"danger\"\n\n/** Internal normalized severity — `\"danger\"` is collapsed to `\"destructive\"`. */\ntype NormalizedSeverity = \"info\" | \"warning\" | \"destructive\"\n\nfunction normalizeSeverity(s: ConfirmDialogSeverity): NormalizedSeverity {\n return s === \"danger\" ? \"destructive\" : s\n}\n\nexport interface ConfirmDialogProps {\n /** Controlled open state. */\n open?: boolean\n /** Uncontrolled initial open state. */\n defaultOpen?: boolean\n /** Called when open state changes. */\n onOpenChange?: (open: boolean) => void\n\n /** Optional trigger — wrapped in DialogTrigger. Omit for fully-controlled usage. */\n trigger?: React.ReactNode\n\n /** Dialog title — rendered in DialogTitle next to the severity icon. */\n title: React.ReactNode\n /** Short body above the action row. Used as DialogDescription. */\n description?: React.ReactNode\n /** Richer body slot — overrides description when provided. */\n children?: React.ReactNode\n\n /** Severity — drives icon color, confirm button variant. Default \"warning\". */\n severity?: ConfirmDialogSeverity\n\n /** Confirm button label. Defaults: \"Delete\" for danger, \"Confirm\" otherwise. */\n confirmLabel?: React.ReactNode\n /** Cancel button label. Default \"Cancel\". */\n cancelLabel?: React.ReactNode\n\n /** If set, user must type this exact string to enable the confirm button. */\n confirmText?: string\n /** Label for the confirm-text input. Default: `Type ${confirmText} to confirm`. */\n confirmTextLabel?: React.ReactNode\n\n /** Confirm handler. Async-aware: returning a Promise puts the dialog into pending state. */\n onConfirm?: () => void | Promise<void>\n /** Cancel handler. */\n onCancel?: () => void\n\n /** Externally-controlled busy state — overrides internal async pending detection. */\n busy?: boolean\n\n /** Additional className on DialogContent. */\n className?: string\n}\n\nfunction getSeverityIcon(severity: NormalizedSeverity): React.ReactNode {\n switch (severity) {\n case \"info\":\n return <InfoIcon weight=\"fill\" aria-hidden=\"true\" />\n case \"destructive\":\n return <WarningOctagonIcon weight=\"fill\" aria-hidden=\"true\" />\n case \"warning\":\n default:\n return <WarningIcon weight=\"fill\" aria-hidden=\"true\" />\n }\n}\n\nfunction getSeverityPlateClass(severity: NormalizedSeverity): string {\n switch (severity) {\n case \"info\":\n return styles.plateInfo\n case \"destructive\":\n return styles.plateDestructive\n case \"warning\":\n default:\n return styles.plateWarning\n }\n}\n\nfunction getConfirmButtonVariant(\n severity: NormalizedSeverity\n): \"default\" | \"destructive\" {\n return severity === \"destructive\" ? \"destructive\" : \"default\"\n}\n\nfunction getDefaultConfirmLabel(severity: NormalizedSeverity): string {\n return severity === \"destructive\" ? \"Delete\" : \"Confirm\"\n}\n\nconst ConfirmDialog = React.forwardRef<\n React.ComponentRef<typeof DialogContent>,\n ConfirmDialogProps\n>(\n (\n {\n open: openProp,\n defaultOpen,\n onOpenChange,\n trigger,\n title,\n description,\n children,\n severity = \"warning\",\n confirmLabel,\n cancelLabel = \"Cancel\",\n confirmText,\n confirmTextLabel,\n onConfirm,\n onCancel,\n busy,\n className,\n },\n ref\n ) => {\n const isControlled = openProp !== undefined\n const [internalOpen, setInternalOpen] = React.useState<boolean>(\n defaultOpen ?? false\n )\n const actualOpen = isControlled ? (openProp as boolean) : internalOpen\n\n const [isPending, setIsPending] = React.useState<boolean>(false)\n const [typed, setTyped] = React.useState<string>(\"\")\n\n const cancelButtonRef = React.useRef<HTMLButtonElement | null>(null)\n\n const normalizedSeverity = normalizeSeverity(severity)\n\n const handleOpenChange = React.useCallback(\n (next: boolean) => {\n if (!isControlled) {\n setInternalOpen(next)\n }\n onOpenChange?.(next)\n if (!next) {\n // Clear gate typing on close\n setTyped(\"\")\n }\n },\n [isControlled, onOpenChange]\n )\n\n const resolvedConfirmLabel =\n confirmLabel ?? getDefaultConfirmLabel(normalizedSeverity)\n const effectiveBusy = busy ?? isPending\n const gateSatisfied =\n confirmText == null || confirmText.length === 0 || typed === confirmText\n const confirmDisabled = effectiveBusy || !gateSatisfied\n const cancelDisabled = effectiveBusy\n\n const handleConfirmClick = React.useCallback(async () => {\n if (!onConfirm) {\n handleOpenChange(false)\n return\n }\n // Any synchronous throw propagates naturally to React's error boundary.\n const result = onConfirm()\n if (result && typeof (result as Promise<void>).then === \"function\") {\n setIsPending(true)\n try {\n await result\n setIsPending(false)\n handleOpenChange(false)\n } catch (err) {\n // Async rejection — clear pending state, keep dialog open, re-throw\n // so the consumer's error handling (error boundary, onUnhandledRejection)\n // can react to it.\n setIsPending(false)\n throw err\n }\n } else {\n handleOpenChange(false)\n }\n }, [onConfirm, handleOpenChange])\n\n const handleCancelClick = React.useCallback(() => {\n onCancel?.()\n handleOpenChange(false)\n }, [onCancel, handleOpenChange])\n\n const handleOpenAutoFocus = React.useCallback(\n (event: Event) => {\n if (normalizedSeverity === \"destructive\" && cancelButtonRef.current) {\n event.preventDefault()\n cancelButtonRef.current.focus()\n }\n },\n [normalizedSeverity]\n )\n\n const severityIcon = getSeverityIcon(normalizedSeverity)\n const severityPlateClass = getSeverityPlateClass(normalizedSeverity)\n const confirmVariant = getConfirmButtonVariant(normalizedSeverity)\n\n // Generate stable id for confirm gate input\n const generatedId = React.useId()\n const confirmGateInputId = `${generatedId}-confirm-input`\n\n const hasDescriptionForAria =\n description != null && description !== false && !children\n\n return (\n <Dialog\n open={actualOpen}\n defaultOpen={defaultOpen}\n onOpenChange={handleOpenChange}\n >\n {trigger ? <DialogTrigger asChild>{trigger}</DialogTrigger> : null}\n <DialogContent\n ref={ref}\n data-slot=\"confirm-dialog\"\n data-severity={normalizedSeverity}\n className={cn(styles.root, className)}\n onOpenAutoFocus={handleOpenAutoFocus}\n >\n <DialogHeader>\n <div className={styles.headerStack}>\n <span\n data-slot=\"confirm-dialog-icon-plate\"\n aria-hidden=\"true\"\n className={cn(styles.iconPlate, severityPlateClass)}\n >\n {severityIcon}\n </span>\n <DialogTitle>{title}</DialogTitle>\n {hasDescriptionForAria ? (\n <DialogDescription>{description}</DialogDescription>\n ) : null}\n </div>\n </DialogHeader>\n\n {children ? (\n <div data-slot=\"confirm-dialog-body\" className={styles.body}>\n {children}\n </div>\n ) : null}\n\n {confirmText ? (\n <div className={styles.confirmGate}>\n <label\n htmlFor={confirmGateInputId}\n className={styles.confirmGateLabel}\n >\n {confirmTextLabel ?? `Type ${confirmText} to confirm`}\n </label>\n <input\n id={confirmGateInputId}\n type=\"text\"\n autoComplete=\"off\"\n spellCheck={false}\n value={typed}\n onChange={(e) => setTyped(e.target.value)}\n disabled={effectiveBusy}\n className={styles.confirmGateInput}\n data-slot=\"confirm-dialog-gate-input\"\n />\n </div>\n ) : null}\n\n <div\n data-slot=\"confirm-dialog-actions\"\n className={styles.actions}\n role=\"group\"\n >\n <div className={styles.action}>\n <Button\n ref={cancelButtonRef}\n type=\"button\"\n variant=\"outline\"\n onClick={handleCancelClick}\n disabled={cancelDisabled}\n data-slot=\"confirm-dialog-cancel\"\n >\n {cancelLabel}\n </Button>\n </div>\n <div className={styles.action}>\n <Button\n type=\"button\"\n variant={confirmVariant}\n onClick={handleConfirmClick}\n disabled={confirmDisabled}\n aria-busy={effectiveBusy || undefined}\n data-slot=\"confirm-dialog-confirm\"\n >\n {resolvedConfirmLabel}\n </Button>\n </div>\n </div>\n </DialogContent>\n </Dialog>\n )\n }\n)\nConfirmDialog.displayName = \"ConfirmDialog\"\n\nexport { ConfirmDialog }\n"
2125
2131
  },
2126
2132
  {
2127
2133
  "path": "components/ui/confirm-dialog/confirm-dialog.module.css",
2128
2134
  "type": "registry:ui",
2129
- "content": "/* ConfirmDialog — destructive-action confirmation compound wrapping Dialog. */\n\n.root {\n width: 100%;\n min-width: 0;\n container-type: inline-size;\n container-name: confirm-dialog;\n}\n\n/* Title row with leading severity icon */\n.titleRow {\n display: flex;\n align-items: center;\n gap: var(--spacing-2, 0.5rem);\n}\n\n/* Severity icon sized via svg to respect Phosphor sizing contract */\n.icon {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n line-height: 1;\n}\n\n.icon svg {\n width: var(--spacing-5, 1.25rem);\n height: var(--spacing-5, 1.25rem);\n}\n\n.iconInfo {\n color: var(--text-info, #0369a1);\n}\n\n.iconWarning {\n color: var(--text-warning, #b45309);\n}\n\n.iconDanger {\n color: var(--text-error, #b91c1c);\n}\n\n/* Body slot — description paragraph or richer children */\n.body {\n margin-top: var(--spacing-2, 0.5rem);\n font-size: var(--font-size-sm, 0.875rem);\n color: var(--text-secondary, #6b7280);\n line-height: var(--line-height-relaxed, 1.6);\n}\n\n.body > :first-child {\n margin-top: 0;\n}\n\n.body > :last-child {\n margin-bottom: 0;\n}\n\n/* Confirm-text gate — labeled text input between body and actions */\n.confirmGate {\n display: flex;\n flex-direction: column;\n gap: var(--spacing-1, 0.25rem);\n margin-top: var(--spacing-4, 1rem);\n}\n\n.confirmGateLabel {\n font-size: var(--font-size-sm, 0.875rem);\n color: var(--text-primary, #111827);\n font-weight: var(--font-weight-medium, 500);\n}\n\n.confirmGateInput {\n width: 100%;\n padding: var(--spacing-2, 0.5rem) var(--spacing-3, 0.75rem);\n border-radius: var(--radius-md, 0.5rem);\n border: 1px solid var(--border-default, #e5e7eb);\n background-color: var(--surface-page, #ffffff);\n color: var(--text-primary, #111827);\n font-size: var(--font-size-sm, 0.875rem);\n font-family: inherit;\n line-height: var(--line-height-normal, 1.5);\n transition: border-color var(--motion-duration-150, 150ms) var(--motion-easing-default, ease-in-out);\n}\n\n.confirmGateInput:focus-visible {\n outline: var(--focus-ring-width, 2px) solid var(--border-focus, currentColor);\n outline-offset: var(--focus-ring-offset, 2px);\n border-color: var(--border-focus, currentColor);\n}\n\n.confirmGateInput:disabled {\n opacity: 0.6;\n cursor: not-allowed;\n}\n\n/* Action row — cancel + confirm, right-aligned on wide, stacked on narrow */\n.actions {\n display: flex;\n flex-direction: row;\n justify-content: flex-end;\n align-items: center;\n gap: var(--spacing-2, 0.5rem);\n margin-top: var(--spacing-6, 1.5rem);\n}\n\n.action {\n display: inline-flex;\n}\n\n/* Container query: stack actions vertically on narrow dialog widths */\n@container confirm-dialog (max-width: 360px) {\n .actions {\n flex-direction: column-reverse;\n align-items: stretch;\n width: 100%;\n }\n\n .actions .action {\n width: 100%;\n }\n\n .actions .action > * {\n width: 100%;\n justify-content: center;\n }\n}\n"
2135
+ "content": "/* ConfirmDialog — destructive-action confirmation compound wrapping Dialog. */\n\n.root {\n width: 100%;\n min-width: 0;\n container-type: inline-size;\n container-name: confirm-dialog;\n}\n\n/* Header layout plate stacked above title/description */\n.headerStack {\n display: flex;\n flex-direction: column;\n align-items: flex-start;\n gap: var(--spacing-3, 0.75rem);\n}\n\n/* Tinted circular icon plate (~2.5rem) stacked above the dialog title */\n.iconPlate {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n width: var(--spacing-10, 2.5rem);\n height: var(--spacing-10, 2.5rem);\n border-radius: 9999px;\n}\n\n.iconPlate svg {\n width: var(--spacing-5, 1.25rem);\n height: var(--spacing-5, 1.25rem);\n}\n\n.plateInfo {\n background: var(--surface-info-subtle, #f0f9ff);\n color: var(--text-info, #0369a1);\n}\n\n.plateWarning {\n background: var(--surface-warning-subtle, #fffbeb);\n color: var(--text-warning, #b45309);\n}\n\n.plateDestructive {\n background: var(--surface-error-subtle, #fef2f2);\n color: var(--text-error, #b91c1c);\n}\n\n/* Legacy aliases — kept for theme overrides targeting the old class names */\n.iconInfo { color: var(--text-info, #0369a1); }\n.iconWarning { color: var(--text-warning, #b45309); }\n.iconDanger { color: var(--text-error, #b91c1c); }\n\n/* Body slot — description paragraph or richer children */\n.body {\n margin-top: var(--spacing-2, 0.5rem);\n font-size: var(--font-size-sm, 0.875rem);\n color: var(--text-secondary, #6b7280);\n line-height: var(--line-height-relaxed, 1.6);\n}\n\n.body > :first-child {\n margin-top: 0;\n}\n\n.body > :last-child {\n margin-bottom: 0;\n}\n\n/* Confirm-text gate — labeled text input between body and actions */\n.confirmGate {\n display: flex;\n flex-direction: column;\n gap: var(--spacing-1, 0.25rem);\n margin-top: var(--spacing-4, 1rem);\n}\n\n.confirmGateLabel {\n font-size: var(--font-size-sm, 0.875rem);\n color: var(--text-primary, #111827);\n font-weight: var(--font-weight-medium, 500);\n}\n\n.confirmGateInput {\n width: 100%;\n padding: var(--spacing-2, 0.5rem) var(--spacing-3, 0.75rem);\n border-radius: var(--radius-md, 0.5rem);\n border: 1px solid var(--border-default, #e5e7eb);\n background-color: var(--surface-page, #ffffff);\n color: var(--text-primary, #111827);\n font-size: var(--font-size-sm, 0.875rem);\n font-family: inherit;\n line-height: var(--line-height-normal, 1.5);\n transition: border-color var(--motion-duration-150, 150ms) var(--motion-easing-default, ease-in-out);\n}\n\n.confirmGateInput:focus-visible {\n outline: var(--focus-ring-width, 2px) solid var(--border-focus, currentColor);\n outline-offset: var(--focus-ring-offset, 2px);\n border-color: var(--border-focus, currentColor);\n}\n\n.confirmGateInput:disabled {\n opacity: 0.6;\n cursor: not-allowed;\n}\n\n/* Action row — cancel + confirm, right-aligned on wide, stacked on narrow */\n.actions {\n display: flex;\n flex-direction: row;\n justify-content: flex-end;\n align-items: center;\n gap: var(--spacing-2, 0.5rem);\n margin-top: var(--spacing-6, 1.5rem);\n}\n\n.action {\n display: inline-flex;\n}\n\n/* Container query: stack actions vertically on narrow dialog widths */\n@container confirm-dialog (max-width: 360px) {\n .actions {\n flex-direction: column-reverse;\n align-items: stretch;\n width: 100%;\n }\n\n .actions .action {\n width: 100%;\n }\n\n .actions .action > * {\n width: 100%;\n justify-content: center;\n }\n}\n"
2130
2136
  }
2131
2137
  ]
2132
2138
  },
@@ -2315,6 +2321,30 @@
2315
2321
  }
2316
2322
  ]
2317
2323
  },
2324
+ {
2325
+ "name": "key-value-list",
2326
+ "type": "registry:ui",
2327
+ "description": "Definition-list display primitive for one record's attributes — label/value pairs in a responsive grid. Values accept any node (Badge, AvatarStack, StatHero, ScoreIndicator, text); stacked or horizontal orientation, 1–4 columns, three densities.",
2328
+ "category": "data-display",
2329
+ "dependencies": [
2330
+ "@loworbitstudio/visor-core"
2331
+ ],
2332
+ "registryDependencies": [
2333
+ "utils"
2334
+ ],
2335
+ "files": [
2336
+ {
2337
+ "path": "components/ui/key-value-list/key-value-list.tsx",
2338
+ "type": "registry:ui",
2339
+ "content": "import * as React from \"react\"\nimport { cn } from \"../../../lib/utils\"\nimport styles from \"./key-value-list.module.css\"\n\n// ─── Types ──────────────────────────────────────────────────────────────────\n\nexport interface KeyValueItem {\n /** The term — rendered as `<dt>`. */\n label: React.ReactNode\n /** The value — rendered as `<dd>`. Accepts any node: Badge, AvatarStack,\n * StatHero, ScoreIndicator, or plain text. */\n value: React.ReactNode\n /** Optional secondary text trailing the value (e.g. \"/ 100\", \"142 total\"). */\n hint?: React.ReactNode\n}\n\nexport interface KeyValueListProps\n extends Omit<React.HTMLAttributes<HTMLElement>, \"title\"> {\n /** The label/value pairs to render. */\n items: KeyValueItem[]\n /** Grid column count. Collapses responsively on narrow viewports. */\n columns?: 1 | 2 | 3 | 4\n /** `stacked` = label above value (facts panel); `horizontal` = label beside\n * value (inspector). */\n orientation?: \"horizontal\" | \"stacked\"\n /** Row density. `editorial` is the admin-ui default. */\n density?: \"compact\" | \"default\" | \"editorial\"\n /** Root element. `dl` (default) renders semantic `<dl>`/`<dt>`/`<dd>`; `div`\n * opts out of definition-list semantics. */\n as?: \"dl\" | \"div\"\n}\n\n// ─── KeyValueList ─────────────────────────────────────────────────────────────\n\nconst KeyValueList = React.forwardRef<HTMLElement, KeyValueListProps>(\n (\n {\n items,\n columns = 1,\n orientation = \"stacked\",\n density = \"editorial\",\n as = \"dl\",\n className,\n ...props\n },\n ref\n ) => {\n const isDl = as === \"dl\"\n const Root = (isDl ? \"dl\" : \"div\") as React.ElementType\n const Term = (isDl ? \"dt\" : \"div\") as React.ElementType\n const Desc = (isDl ? \"dd\" : \"div\") as React.ElementType\n\n return (\n <Root\n ref={ref}\n data-slot=\"key-value-list\"\n data-columns={columns}\n data-orientation={orientation}\n data-density={density}\n className={cn(styles.root, className)}\n {...props}\n >\n {items.map((item, i) => (\n <div key={i} data-slot=\"key-value-item\" className={styles.item}>\n <Term data-slot=\"key-value-label\" className={styles.label}>\n {item.label}\n </Term>\n <Desc data-slot=\"key-value-value\" className={styles.value}>\n {item.value}\n {item.hint != null ? (\n <span data-slot=\"key-value-hint\" className={styles.hint}>\n {item.hint}\n </span>\n ) : null}\n </Desc>\n </div>\n ))}\n </Root>\n )\n }\n)\nKeyValueList.displayName = \"KeyValueList\"\n\nexport { KeyValueList }\n"
2340
+ },
2341
+ {
2342
+ "path": "components/ui/key-value-list/key-value-list.module.css",
2343
+ "type": "registry:ui",
2344
+ "content": "/* Key-value list — a definition-list display primitive for one record's\n attributes (the \"key facts\" panel). Label/value pairs in a responsive grid.\n Values accept any node: Badge, AvatarStack, StatHero, ScoreIndicator, text. */\n.root {\n display: grid;\n grid-template-columns: 1fr;\n margin: 0;\n}\n\n.root[data-columns=\"2\"] {\n grid-template-columns: repeat(2, minmax(0, 1fr));\n}\n.root[data-columns=\"3\"] {\n grid-template-columns: repeat(3, minmax(0, 1fr));\n}\n.root[data-columns=\"4\"] {\n grid-template-columns: repeat(4, minmax(0, 1fr));\n}\n\n.item {\n min-width: 0;\n}\n\n/* Label — uppercase eyebrow. */\n.label {\n margin: 0;\n font-size: var(--font-size-xs, 0.6875rem);\n font-weight: var(--font-weight-medium, 500);\n letter-spacing: 0.12em;\n text-transform: uppercase;\n color: var(--text-tertiary, #6b7280);\n line-height: 1.4;\n}\n\n/* Value — primary text; resets the native <dd> indent. */\n.value {\n margin: 0;\n display: flex;\n align-items: baseline;\n flex-wrap: wrap;\n gap: var(--spacing-2, 0.5rem);\n min-width: 0;\n color: var(--text-primary, #111827);\n font-variant-numeric: tabular-nums;\n}\n\n/* Hint — secondary trailing text (\"/ 100\", \"142 total\"). */\n.hint {\n font-size: var(--font-size-sm, 0.8125rem);\n font-weight: var(--font-weight-normal, 400);\n color: var(--text-tertiary, #6b7280);\n}\n\n/* ── Orientation ──────────────────────────────────────────────── */\n/* Stacked (default) — label above value. */\n.root[data-orientation=\"stacked\"] .item {\n display: flex;\n flex-direction: column;\n}\n.root[data-orientation=\"stacked\"] .label {\n margin-bottom: var(--spacing-2, 0.5rem);\n}\n\n/* Horizontal — label beside value. */\n.root[data-orientation=\"horizontal\"] .item {\n display: grid;\n grid-template-columns: minmax(7rem, 0.4fr) 1fr;\n align-items: baseline;\n gap: var(--spacing-4, 1rem);\n}\n.root[data-orientation=\"horizontal\"] .label {\n letter-spacing: 0.06em;\n}\n\n/* ── Density ──────────────────────────────────────────────────── */\n.root[data-density=\"editorial\"] {\n column-gap: var(--spacing-8, 2rem);\n row-gap: var(--spacing-6, 1.5rem);\n}\n.root[data-density=\"editorial\"] .value {\n font-size: var(--font-size-lg, 1.125rem);\n}\n\n.root[data-density=\"default\"] {\n column-gap: var(--spacing-6, 1.5rem);\n row-gap: var(--spacing-4, 1rem);\n}\n.root[data-density=\"default\"] .value {\n font-size: var(--font-size-base, 1rem);\n}\n\n.root[data-density=\"compact\"] {\n column-gap: var(--spacing-4, 1rem);\n row-gap: var(--spacing-3, 0.75rem);\n}\n.root[data-density=\"compact\"] .value {\n font-size: var(--font-size-sm, 0.8125rem);\n}\n.root[data-density=\"compact\"][data-orientation=\"stacked\"] .label {\n margin-bottom: var(--spacing-1, 0.25rem);\n}\n\n/* ── Responsive collapse ──────────────────────────────────────── */\n@media (max-width: 900px) {\n .root[data-columns=\"3\"],\n .root[data-columns=\"4\"] {\n grid-template-columns: repeat(2, minmax(0, 1fr));\n }\n}\n@media (max-width: 560px) {\n .root[data-columns=\"2\"],\n .root[data-columns=\"3\"],\n .root[data-columns=\"4\"] {\n grid-template-columns: 1fr;\n }\n}\n"
2345
+ }
2346
+ ]
2347
+ },
2318
2348
  {
2319
2349
  "name": "score-indicator",
2320
2350
  "type": "registry:ui",
@@ -2393,7 +2423,7 @@
2393
2423
  {
2394
2424
  "name": "status-badge",
2395
2425
  "type": "registry:ui",
2396
- "description": "A semantic wrapper over Badge that maps admin status names (healthy, degraded, down, running, pending, queued, idle, failed, complete) to visual variants with an optional colored indicator dot and pulse animation.",
2426
+ "description": "A semantic wrapper over Badge that maps status names — service health (healthy, degraded, down), job lifecycle (running, pending, queued, idle, complete, failed), admin-ui events (live, warn, scheduled, sold, draft), and CRM pipeline stages (prospect, pitched, contracted, active, paused, completed, archived) — to visual variants with an optional colored indicator dot and pulse animation.",
2397
2427
  "category": "admin",
2398
2428
  "dependencies": [
2399
2429
  "class-variance-authority",
@@ -2407,12 +2437,12 @@
2407
2437
  {
2408
2438
  "path": "components/ui/status-badge/status-badge.tsx",
2409
2439
  "type": "registry:ui",
2410
- "content": "import * as React from \"react\"\nimport { cn } from \"../../../lib/utils\"\nimport { Badge } from \"../badge/badge\"\nimport type { BadgeProps } from \"../badge/badge\"\nimport styles from \"./status-badge.module.css\"\n\nexport type StatusBadgeStatus =\n | \"healthy\"\n | \"degraded\"\n | \"down\"\n | \"failed\"\n | \"running\"\n | \"pending\"\n | \"queued\"\n | \"idle\"\n | \"complete\"\n | \"live\"\n | \"warn\"\n | \"scheduled\"\n | \"sold\"\n | \"draft\"\n\nexport type StatusBadgeTone = \"subtle\" | \"filled\"\n\nexport interface StatusBadgeProps\n extends Omit<React.HTMLAttributes<HTMLSpanElement>, \"children\"> {\n /** Semantic admin status. Drives both color and default label. */\n status: StatusBadgeStatus\n /** Visible text. Defaults to the capitalized status key. */\n label?: React.ReactNode\n /** Which Badge variant family to use. Defaults to \"subtle\". */\n tone?: StatusBadgeTone\n /** Render the leading indicator dot. Defaults to true. */\n indicator?: boolean\n /** Animate the indicator dot with a soft pulse. Defaults to false. */\n pulse?: boolean\n}\n\n/**\n * Default human-readable labels for each status. Exported so consumers can\n * localize or override without reimplementing the map.\n */\nexport const statusBadgeLabels: Record<StatusBadgeStatus, string> = {\n healthy: \"Healthy\",\n degraded: \"Degraded\",\n down: \"Down\",\n failed: \"Failed\",\n running: \"Running\",\n pending: \"Pending\",\n queued: \"Queued\",\n idle: \"Idle\",\n complete: \"Complete\",\n live: \"Live\",\n warn: \"Warn\",\n scheduled: \"Scheduled\",\n sold: \"Sold\",\n draft: \"Draft\",\n}\n\ntype BadgeVariant = NonNullable<BadgeProps[\"variant\"]>\n\n/**\n * Color group keyed on the semantic status. Used to pick the indicator dot\n * class and the underlying Badge variant.\n */\ntype StatusColorGroup =\n | \"success\"\n | \"warning\"\n | \"destructive\"\n | \"info\"\n | \"neutral\"\n\nconst STATUS_COLOR_GROUP: Record<StatusBadgeStatus, StatusColorGroup> = {\n healthy: \"success\",\n complete: \"success\",\n degraded: \"warning\",\n pending: \"warning\",\n down: \"destructive\",\n failed: \"destructive\",\n running: \"info\",\n queued: \"neutral\",\n idle: \"neutral\",\n // Admin-ui event tones — map to existing semantic groups.\n // live: active/in-progress positive event → success accent\n // warn: needs attention but not failing → warning\n // scheduled: upcoming/planned, visually grouped with draft → neutral\n // sold: positive completed outcome → success\n // draft: unpublished/muted → neutral\n live: \"success\",\n warn: \"warning\",\n scheduled: \"neutral\",\n sold: \"success\",\n draft: \"neutral\",\n}\n\nconst SUBTLE_VARIANT: Record<StatusColorGroup, BadgeVariant> = {\n success: \"success\",\n warning: \"warning\",\n destructive: \"destructive\",\n info: \"info\",\n neutral: \"secondary\",\n}\n\nconst FILLED_VARIANT: Record<StatusColorGroup, BadgeVariant> = {\n success: \"filled-success\",\n warning: \"filled-warning\",\n destructive: \"filled-destructive\",\n info: \"filled-info\",\n // No `filled-secondary` exists on Badge — fall back to secondary.\n neutral: \"secondary\",\n}\n\nconst INDICATOR_CLASS: Record<StatusColorGroup, string> = {\n success: styles.indicatorSuccess,\n warning: styles.indicatorWarning,\n destructive: styles.indicatorDestructive,\n info: styles.indicatorInfo,\n neutral: styles.indicatorNeutral,\n}\n\nconst StatusBadge = React.forwardRef<HTMLSpanElement, StatusBadgeProps>(\n (\n {\n className,\n status,\n label,\n tone = \"subtle\",\n indicator = true,\n pulse = false,\n ...props\n },\n ref\n ) => {\n const group = STATUS_COLOR_GROUP[status]\n const variant: BadgeVariant =\n tone === \"filled\" ? FILLED_VARIANT[group] : SUBTLE_VARIANT[group]\n const visibleLabel = label ?? statusBadgeLabels[status]\n\n return (\n <Badge\n ref={ref}\n variant={variant}\n data-slot=\"status-badge\"\n data-status={status}\n data-tone={tone}\n className={cn(className)}\n {...props}\n >\n {indicator ? (\n <span\n data-slot=\"status-badge-indicator\"\n aria-hidden=\"true\"\n className={cn(\n styles.indicator,\n INDICATOR_CLASS[group],\n pulse && styles.pulse\n )}\n />\n ) : null}\n <span className={styles.srOnly}>Status: </span>\n <span data-slot=\"status-badge-label\">{visibleLabel}</span>\n </Badge>\n )\n }\n)\nStatusBadge.displayName = \"StatusBadge\"\n\nexport { StatusBadge }\n"
2440
+ "content": "import * as React from \"react\"\nimport { cn } from \"../../../lib/utils\"\nimport { Badge } from \"../badge/badge\"\nimport type { BadgeProps } from \"../badge/badge\"\nimport styles from \"./status-badge.module.css\"\n\nexport type StatusBadgeStatus =\n | \"healthy\"\n | \"degraded\"\n | \"down\"\n | \"failed\"\n | \"running\"\n | \"pending\"\n | \"queued\"\n | \"idle\"\n | \"complete\"\n | \"live\"\n | \"warn\"\n | \"scheduled\"\n | \"sold\"\n | \"draft\"\n | \"prospect\"\n | \"pitched\"\n | \"contracted\"\n | \"active\"\n | \"paused\"\n | \"completed\"\n | \"archived\"\n\nexport type StatusBadgeTone = \"subtle\" | \"filled\"\n\nexport interface StatusBadgeProps\n extends Omit<React.HTMLAttributes<HTMLSpanElement>, \"children\"> {\n /** Semantic admin status. Drives both color and default label. */\n status: StatusBadgeStatus\n /** Visible text. Defaults to the capitalized status key. */\n label?: React.ReactNode\n /** Which Badge variant family to use. Defaults to \"subtle\". */\n tone?: StatusBadgeTone\n /** Render the leading indicator dot. Defaults to true. */\n indicator?: boolean\n /** Animate the indicator dot with a soft pulse. Defaults to false. */\n pulse?: boolean\n}\n\n/**\n * Default human-readable labels for each status. Exported so consumers can\n * localize or override without reimplementing the map.\n */\nexport const statusBadgeLabels: Record<StatusBadgeStatus, string> = {\n healthy: \"Healthy\",\n degraded: \"Degraded\",\n down: \"Down\",\n failed: \"Failed\",\n running: \"Running\",\n pending: \"Pending\",\n queued: \"Queued\",\n idle: \"Idle\",\n complete: \"Complete\",\n live: \"Live\",\n warn: \"Warn\",\n scheduled: \"Scheduled\",\n sold: \"Sold\",\n draft: \"Draft\",\n prospect: \"Prospect\",\n pitched: \"Pitched\",\n contracted: \"Contracted\",\n active: \"Active\",\n paused: \"Paused\",\n completed: \"Completed\",\n archived: \"Archived\",\n}\n\ntype BadgeVariant = NonNullable<BadgeProps[\"variant\"]>\n\n/**\n * Color group keyed on the semantic status. Used to pick the indicator dot\n * class and the underlying Badge variant.\n */\ntype StatusColorGroup =\n | \"success\"\n | \"warning\"\n | \"destructive\"\n | \"info\"\n | \"neutral\"\n\nconst STATUS_COLOR_GROUP: Record<StatusBadgeStatus, StatusColorGroup> = {\n healthy: \"success\",\n complete: \"success\",\n degraded: \"warning\",\n pending: \"warning\",\n down: \"destructive\",\n failed: \"destructive\",\n running: \"info\",\n queued: \"neutral\",\n idle: \"neutral\",\n // Admin-ui event tones — map to existing semantic groups.\n // live: active/in-progress positive event → success accent\n // warn: needs attention but not failing → warning\n // scheduled: upcoming/planned, visually grouped with draft → neutral\n // sold: positive completed outcome → success\n // draft: unpublished/muted → neutral\n live: \"success\",\n warn: \"warning\",\n scheduled: \"neutral\",\n sold: \"success\",\n draft: \"neutral\",\n // CRM / pipeline stages (VI-492) — bind to existing semantic groups.\n // No new tokens: stages that share a meaning share a color.\n // prospect: new informational lead → info\n // pitched: awaiting response, needs attention → warning\n // contracted / active / completed: positive, in-good-standing → success\n // paused: temporarily on hold, needs attention → warning\n // archived: closed/muted, grouped with draft → neutral\n prospect: \"info\",\n pitched: \"warning\",\n contracted: \"success\",\n active: \"success\",\n paused: \"warning\",\n completed: \"success\",\n archived: \"neutral\",\n}\n\nconst SUBTLE_VARIANT: Record<StatusColorGroup, BadgeVariant> = {\n success: \"success\",\n warning: \"warning\",\n destructive: \"destructive\",\n info: \"info\",\n neutral: \"neutral\",\n}\n\nconst FILLED_VARIANT: Record<StatusColorGroup, BadgeVariant> = {\n success: \"filled-success\",\n warning: \"filled-warning\",\n destructive: \"filled-destructive\",\n info: \"filled-info\",\n neutral: \"filled-neutral\",\n}\n\nconst INDICATOR_CLASS: Record<StatusColorGroup, string> = {\n success: styles.indicatorSuccess,\n warning: styles.indicatorWarning,\n destructive: styles.indicatorDestructive,\n info: styles.indicatorInfo,\n neutral: styles.indicatorNeutral,\n}\n\nconst StatusBadge = React.forwardRef<HTMLSpanElement, StatusBadgeProps>(\n (\n {\n className,\n status,\n label,\n tone = \"subtle\",\n indicator = true,\n pulse = false,\n ...props\n },\n ref\n ) => {\n const group = STATUS_COLOR_GROUP[status]\n const variant: BadgeVariant =\n tone === \"filled\" ? FILLED_VARIANT[group] : SUBTLE_VARIANT[group]\n const visibleLabel = label ?? statusBadgeLabels[status]\n\n return (\n <Badge\n ref={ref}\n variant={variant}\n data-slot=\"status-badge\"\n data-status={status}\n data-tone={tone}\n className={cn(className)}\n {...props}\n >\n {indicator ? (\n <span\n data-slot=\"status-badge-indicator\"\n aria-hidden=\"true\"\n className={cn(\n styles.indicator,\n INDICATOR_CLASS[group],\n pulse && styles.pulse\n )}\n />\n ) : null}\n <span className={styles.srOnly}>Status: </span>\n <span data-slot=\"status-badge-label\">{visibleLabel}</span>\n </Badge>\n )\n }\n)\nStatusBadge.displayName = \"StatusBadge\"\n\nexport { StatusBadge }\n"
2411
2441
  },
2412
2442
  {
2413
2443
  "path": "components/ui/status-badge/status-badge.module.css",
2414
2444
  "type": "registry:ui",
2415
- "content": "/*\n * StatusBadge — semantic wrapper over Badge.\n *\n * These styles only cover the additions on top of Badge: the leading\n * indicator dot, its per-status color, the optional pulse animation, and\n * the visually-hidden \"Status:\" prefix. All visual chrome (padding, radius,\n * typography, background) is inherited from Badge.\n */\n\n/* Indicator dot — filled circle, 0.5rem, colored per status */\n.indicator {\n display: inline-block;\n width: 0.5rem;\n height: 0.5rem;\n flex-shrink: 0;\n border-radius: var(--radius-full, 9999px);\n background-color: currentColor;\n}\n\n/* Per-color-group fills. Use brand surface default tokens so the dot\n * reads as a saturated status color independent of the Badge subtle bg. */\n.indicatorSuccess {\n background-color: var(--surface-success-default, #22c55e);\n}\n\n.indicatorWarning {\n background-color: var(--surface-warning-default, #f59e0b);\n}\n\n.indicatorDestructive {\n background-color: var(--surface-error-default, #ef4444);\n}\n\n.indicatorInfo {\n background-color: var(--surface-info-default, #0ea5e9);\n}\n\n.indicatorNeutral {\n background-color: var(--text-tertiary, #6b7280);\n}\n\n/* In filled tone, the dot sits on top of a saturated brand fill —\n * paint it with the same inverse token the Badge uses for its text\n * so it's visible in every theme. Neutral is excluded: it maps to\n * the secondary Badge variant, which is not a saturated fill. */\n[data-tone=\"filled\"] .indicatorSuccess,\n[data-tone=\"filled\"] .indicatorWarning,\n[data-tone=\"filled\"] .indicatorDestructive,\n[data-tone=\"filled\"] .indicatorInfo {\n background-color: var(--text-inverse, #ffffff);\n}\n\n/* Pulse animation — soft opacity + scale.\n * Keyframes are defined locally to keep the component self-contained. */\n.pulse {\n /* Doubled 800ms token gives ~1.6s per cycle — slow enough to read as a\n * heartbeat without drawing focus away from content. */\n animation: status-badge-pulse\n calc(var(--motion-duration-800, 800ms) * 2)\n var(--motion-easing-standard, ease-in-out) infinite;\n transform-origin: center;\n will-change: opacity, transform;\n}\n\n@keyframes status-badge-pulse {\n 0%,\n 100% {\n opacity: 1;\n transform: scale(1);\n }\n 50% {\n opacity: 0.55;\n transform: scale(0.85);\n }\n}\n\n/* Respect reduced motion */\n@media (prefers-reduced-motion: reduce) {\n .pulse {\n animation: none;\n }\n}\n\n/* Visually hidden but announced to screen readers */\n.srOnly {\n position: absolute;\n width: 1px;\n height: 1px;\n padding: 0;\n margin: -1px;\n overflow: hidden;\n clip: rect(0, 0, 0, 0);\n white-space: nowrap;\n border: 0;\n}\n"
2445
+ "content": "/*\n * StatusBadge — semantic wrapper over Badge.\n *\n * These styles only cover the additions on top of Badge: the leading\n * indicator dot, its per-status color, the optional pulse animation, and\n * the visually-hidden \"Status:\" prefix. All visual chrome (padding, radius,\n * typography, background) is inherited from Badge.\n */\n\n/* Indicator dot — filled circle, 0.5rem, colored per status */\n.indicator {\n display: inline-block;\n width: 0.5rem;\n height: 0.5rem;\n flex-shrink: 0;\n border-radius: var(--radius-full, 9999px);\n background-color: currentColor;\n}\n\n/* Per-color-group fills. Use brand surface default tokens so the dot\n * reads as a saturated status color independent of the Badge subtle bg. */\n.indicatorSuccess {\n background-color: var(--surface-success-default, transparent);\n}\n\n.indicatorWarning {\n background-color: var(--surface-warning-default, transparent);\n}\n\n.indicatorDestructive {\n background-color: var(--surface-error-default, transparent);\n}\n\n.indicatorInfo {\n background-color: var(--surface-info-default, transparent);\n}\n\n.indicatorNeutral {\n background-color: var(--text-tertiary, currentColor);\n}\n\n/* In filled tone, the dot sits on top of a saturated brand fill —\n * paint it with the same inverse token the Badge uses for its text\n * so it's visible in every theme. */\n[data-tone=\"filled\"] .indicatorSuccess,\n[data-tone=\"filled\"] .indicatorWarning,\n[data-tone=\"filled\"] .indicatorDestructive,\n[data-tone=\"filled\"] .indicatorInfo {\n background-color: var(--text-inverse, currentColor);\n}\n\n/* Neutral's filled fill (filled-neutral) is a fixed dark gray in both modes,\n * so its dot stays white rather than following --text-inverse (which flips\n * dark in dark mode). */\n[data-tone=\"filled\"] .indicatorNeutral {\n background-color: var(--color-white, #ffffff);\n}\n\n/* Pulse animation — soft opacity + scale.\n * Keyframes are defined locally to keep the component self-contained. */\n.pulse {\n /* Doubled 800ms token gives ~1.6s per cycle — slow enough to read as a\n * heartbeat without drawing focus away from content. */\n animation: status-badge-pulse\n calc(var(--motion-duration-800, 800ms) * 2)\n var(--motion-easing-standard, ease-in-out) infinite;\n transform-origin: center;\n will-change: opacity, transform;\n}\n\n@keyframes status-badge-pulse {\n 0%,\n 100% {\n opacity: 1;\n transform: scale(1);\n }\n 50% {\n opacity: 0.55;\n transform: scale(0.85);\n }\n}\n\n/* Respect reduced motion */\n@media (prefers-reduced-motion: reduce) {\n .pulse {\n animation: none;\n }\n}\n\n/* Visually hidden but announced to screen readers */\n.srOnly {\n position: absolute;\n width: 1px;\n height: 1px;\n padding: 0;\n margin: -1px;\n overflow: hidden;\n clip: rect(0, 0, 0, 0);\n white-space: nowrap;\n border: 0;\n}\n"
2416
2446
  }
2417
2447
  ]
2418
2448
  },
@@ -3294,7 +3324,7 @@
3294
3324
  {
3295
3325
  "path": "blocks/admin-shell/admin-shell.module.css",
3296
3326
  "type": "registry:block",
3297
- "content": ".root {\n display: flex;\n min-height: 100vh;\n width: 100%;\n background: var(--surface-page, #f9fafb);\n color: var(--text-primary, #111827);\n container-type: inline-size;\n}\n\n/* Accessibility: skip link — visible only on keyboard focus */\n.skipLink {\n position: absolute;\n top: var(--spacing-2, 0.5rem);\n left: var(--spacing-2, 0.5rem);\n z-index: 100;\n padding: var(--spacing-2, 0.5rem) var(--spacing-3, 0.75rem);\n background: var(--surface-card, #ffffff);\n color: var(--text-primary, #111827);\n border: 1px solid var(--border-default, #e5e7eb);\n border-radius: var(--radius-md, 0.5rem);\n box-shadow: var(--shadow-md, 0 4px 6px -1px rgba(0, 0, 0, 0.1));\n font-size: var(--font-size-sm, 0.875rem);\n font-weight: 500;\n text-decoration: none;\n transform: translateY(-150%);\n transition:\n transform var(--motion-duration-fast, 150ms)\n var(--motion-easing-standard, ease);\n}\n\n.skipLink:focus-visible {\n transform: translateY(0);\n outline: var(--focus-ring-width, 2px) solid\n var(--focus-ring-color, var(--accent-primary, #3b82f6));\n outline-offset: var(--focus-ring-offset, 2px);\n}\n\n/* Sidebar */\n.sidebar {\n display: flex;\n flex-direction: column;\n flex-shrink: 0;\n width: var(--admin-shell-sidebar-width, 16rem);\n min-height: 100vh;\n background: var(--surface-card, #ffffff);\n border-right: 1px solid var(--border-default, #e5e7eb);\n position: sticky;\n top: 0;\n max-height: 100vh;\n}\n\n.sidebarHeader {\n display: flex;\n align-items: center;\n padding: var(--spacing-4, 1rem) var(--spacing-5, 1.25rem);\n border-bottom: 1px solid var(--border-muted, #e5e7eb);\n min-height: 3.5rem;\n flex-shrink: 0;\n}\n\n.sidebarNav {\n flex: 1 1 auto;\n overflow-y: auto;\n padding: var(--spacing-4, 1rem) var(--spacing-3, 0.75rem);\n display: flex;\n flex-direction: column;\n gap: var(--spacing-1, 0.25rem);\n}\n\n.sidebarFooter {\n flex-shrink: 0;\n padding: var(--spacing-3, 0.75rem) var(--spacing-4, 1rem);\n border-top: 1px solid var(--border-muted, #e5e7eb);\n}\n\n/* Body = topbar + main */\n.body {\n display: flex;\n flex-direction: column;\n flex: 1 1 auto;\n min-width: 0;\n min-height: 100vh;\n}\n\n/* Topbar */\n.topbar {\n display: flex;\n align-items: center;\n gap: var(--spacing-4, 1rem);\n padding: var(--spacing-3, 0.75rem) var(--spacing-6, 1.5rem);\n min-height: 3.5rem;\n background: var(--surface-card, #ffffff);\n border-bottom: 1px solid var(--border-default, #e5e7eb);\n position: sticky;\n top: 0;\n z-index: 10;\n}\n\n.topbarStart {\n display: flex;\n align-items: center;\n gap: var(--spacing-3, 0.75rem);\n flex: 1 1 auto;\n min-width: 0;\n}\n\n.topbarCenter {\n display: flex;\n align-items: center;\n justify-content: center;\n gap: var(--spacing-3, 0.75rem);\n flex: 0 1 auto;\n}\n\n.topbarEnd {\n display: flex;\n align-items: center;\n justify-content: flex-end;\n gap: var(--spacing-2, 0.5rem);\n flex: 1 1 auto;\n min-width: 0;\n}\n\n/* Main */\n.main {\n flex: 1 1 auto;\n overflow-y: auto;\n min-width: 0;\n outline: none;\n}\n\n.main:focus-visible {\n outline: var(--focus-ring-width, 2px) solid\n var(--focus-ring-color, var(--accent-primary, #3b82f6));\n outline-offset: calc(var(--focus-ring-offset, 2px) * -1);\n}\n\n.main[data-padding=\"none\"] .mainInner {\n padding: 0;\n}\n\n.main[data-padding=\"sm\"] .mainInner {\n padding: var(--spacing-4, 1rem);\n}\n\n.main[data-padding=\"md\"] .mainInner {\n padding: var(--spacing-6, 1.5rem);\n}\n\n.main[data-padding=\"lg\"] .mainInner {\n padding: var(--spacing-8, 2rem);\n}\n\n.mainInner {\n width: 100%;\n max-width: var(--admin-shell-main-max-width, none);\n margin: 0 auto;\n}\n\n/* Responsive: collapse sidebar on narrow containers */\n@container (max-width: 48rem) {\n .topbar {\n padding-left: var(--spacing-4, 1rem);\n padding-right: var(--spacing-4, 1rem);\n }\n\n .main[data-padding=\"lg\"] .mainInner {\n padding: var(--spacing-5, 1.25rem);\n }\n\n .main[data-padding=\"md\"] .mainInner {\n padding: var(--spacing-4, 1rem);\n }\n}\n"
3327
+ "content": ".root {\n display: flex;\n min-height: 100vh;\n width: 100%;\n background: var(--surface-page, #f9fafb);\n color: var(--text-primary, #111827);\n container-type: inline-size;\n}\n\n/* Accessibility: skip link — visible only on keyboard focus */\n.skipLink {\n position: absolute;\n top: var(--spacing-2, 0.5rem);\n left: var(--spacing-2, 0.5rem);\n z-index: 100;\n padding: var(--spacing-2, 0.5rem) var(--spacing-3, 0.75rem);\n background: var(--surface-card, #ffffff);\n color: var(--text-primary, #111827);\n border: 1px solid var(--border-default, #e5e7eb);\n border-radius: var(--radius-md, 0.5rem);\n box-shadow: var(--shadow-md, 0 4px 6px -1px rgba(0, 0, 0, 0.1));\n font-size: var(--font-size-sm, 0.875rem);\n font-weight: 500;\n text-decoration: none;\n transform: translateY(-150%);\n transition:\n transform var(--motion-duration-fast, 150ms)\n var(--motion-easing-standard, ease);\n}\n\n.skipLink:focus-visible {\n transform: translateY(0);\n outline: var(--focus-ring-width, 2px) solid\n var(--focus-ring-color, var(--primary, #3b82f6));\n outline-offset: var(--focus-ring-offset, 2px);\n}\n\n/* Sidebar */\n.sidebar {\n display: flex;\n flex-direction: column;\n flex-shrink: 0;\n width: var(--admin-shell-sidebar-width, 16rem);\n min-height: 100vh;\n background: var(--surface-card, #ffffff);\n border-right: 1px solid var(--border-default, #e5e7eb);\n position: sticky;\n top: 0;\n max-height: 100vh;\n}\n\n.sidebarHeader {\n display: flex;\n align-items: center;\n padding: var(--spacing-4, 1rem) var(--spacing-5, 1.25rem);\n border-bottom: 1px solid var(--border-muted, #e5e7eb);\n min-height: 3.5rem;\n flex-shrink: 0;\n}\n\n.sidebarNav {\n flex: 1 1 auto;\n overflow-y: auto;\n padding: var(--spacing-4, 1rem) var(--spacing-3, 0.75rem);\n display: flex;\n flex-direction: column;\n gap: var(--spacing-1, 0.25rem);\n}\n\n.sidebarFooter {\n flex-shrink: 0;\n padding: var(--spacing-3, 0.75rem) var(--spacing-4, 1rem);\n border-top: 1px solid var(--border-muted, #e5e7eb);\n}\n\n/* Body = topbar + main */\n.body {\n display: flex;\n flex-direction: column;\n flex: 1 1 auto;\n min-width: 0;\n min-height: 100vh;\n}\n\n/* Topbar */\n.topbar {\n display: flex;\n align-items: center;\n gap: var(--spacing-4, 1rem);\n padding: var(--spacing-3, 0.75rem) var(--spacing-6, 1.5rem);\n min-height: 3.5rem;\n background: var(--surface-card, #ffffff);\n border-bottom: 1px solid var(--border-default, #e5e7eb);\n position: sticky;\n top: 0;\n z-index: 10;\n}\n\n.topbarStart {\n display: flex;\n align-items: center;\n gap: var(--spacing-3, 0.75rem);\n flex: 1 1 auto;\n min-width: 0;\n}\n\n.topbarCenter {\n display: flex;\n align-items: center;\n justify-content: center;\n gap: var(--spacing-3, 0.75rem);\n flex: 0 1 auto;\n}\n\n.topbarEnd {\n display: flex;\n align-items: center;\n justify-content: flex-end;\n gap: var(--spacing-2, 0.5rem);\n flex: 1 1 auto;\n min-width: 0;\n}\n\n/* Main */\n.main {\n flex: 1 1 auto;\n overflow-y: auto;\n min-width: 0;\n outline: none;\n}\n\n.main:focus-visible {\n outline: var(--focus-ring-width, 2px) solid\n var(--focus-ring-color, var(--primary, #3b82f6));\n outline-offset: calc(var(--focus-ring-offset, 2px) * -1);\n}\n\n.main[data-padding=\"none\"] .mainInner {\n padding: 0;\n}\n\n.main[data-padding=\"sm\"] .mainInner {\n padding: var(--spacing-4, 1rem);\n}\n\n.main[data-padding=\"md\"] .mainInner {\n padding: var(--spacing-6, 1.5rem);\n}\n\n.main[data-padding=\"lg\"] .mainInner {\n padding: var(--spacing-8, 2rem);\n}\n\n.mainInner {\n width: 100%;\n max-width: var(--admin-shell-main-max-width, none);\n margin: 0 auto;\n}\n\n/* Responsive: collapse sidebar on narrow containers */\n@container (max-width: 48rem) {\n .topbar {\n padding-left: var(--spacing-4, 1rem);\n padding-right: var(--spacing-4, 1rem);\n }\n\n .main[data-padding=\"lg\"] .mainInner {\n padding: var(--spacing-5, 1.25rem);\n }\n\n .main[data-padding=\"md\"] .mainInner {\n padding: var(--spacing-4, 1rem);\n }\n}\n"
3298
3328
  }
3299
3329
  ]
3300
3330
  },
@@ -3322,7 +3352,7 @@
3322
3352
  {
3323
3353
  "path": "blocks/admin-dashboard/admin-dashboard.module.css",
3324
3354
  "type": "registry:block",
3325
- "content": ".root {\n /* Tunable knobs — themes (and one-off pages) can override these without\n reaching into block internals. Defaults match the r3 reference build.\n\n Note: --admin-dashboard-stack-bp is exposed as a custom property for\n theme/documentation discoverability, but CSS @container queries cannot\n dereference custom properties today, so the breakpoint below is the\n hard-coded fallback. Override the @container rule in a theme layer if\n you need a different stack point. */\n --admin-dashboard-side-col-width: 320px;\n --admin-dashboard-stack-bp: 960px;\n\n display: flex;\n flex-direction: column;\n gap: var(--spacing-8, 2rem);\n width: 100%;\n container-type: inline-size;\n container-name: admin-dashboard;\n color: var(--text-primary, #111827);\n}\n\n/* Responsive stat grid driven entirely by container queries. */\n.statGrid {\n display: grid;\n gap: var(--spacing-4, 1rem);\n grid-template-columns: 1fr;\n}\n\n@container admin-dashboard (min-width: 36rem) {\n .statGrid {\n grid-template-columns: repeat(2, minmax(0, 1fr));\n }\n}\n\n@container admin-dashboard (min-width: 56rem) {\n .statGrid {\n grid-template-columns: repeat(3, minmax(0, 1fr));\n gap: var(--spacing-5, 1.25rem);\n }\n}\n\n@container admin-dashboard (min-width: 72rem) {\n .statGrid {\n grid-template-columns: repeat(4, minmax(0, 1fr));\n gap: var(--spacing-6, 1.5rem);\n }\n}\n\n.secondaryRegion {\n display: flex;\n flex-direction: column;\n gap: var(--spacing-4, 1rem);\n min-width: 0;\n}\n\n/* ─── Split body layout ─────────────────────────────────────────────────────\n When layout=\"split\", the activity / secondaryRegion flow is replaced by a\n 2-column grid below the KPI strip. Defaults below mirror the r3 dashboard\n reference (1fr | 320px, 20px gutter). Sub-960px stacks side-col below. */\n\n.body {\n display: flex;\n flex-direction: column;\n gap: var(--spacing-5, 1.25rem);\n min-width: 0;\n}\n\n.body[data-layout=\"split\"] {\n display: grid;\n grid-template-columns: minmax(0, 1fr) var(--admin-dashboard-side-col-width);\n gap: var(--spacing-5, 1.25rem);\n}\n\n.mainCol,\n.sideCol {\n display: flex;\n flex-direction: column;\n gap: var(--spacing-5, 1.25rem);\n min-width: 0;\n}\n\n@container admin-dashboard (max-width: 60rem) {\n /* Default stack breakpoint = 960px (60rem). Override the rule in a theme\n layer if --admin-dashboard-stack-bp is retuned. */\n .body[data-layout=\"split\"] {\n grid-template-columns: minmax(0, 1fr);\n }\n}\n\n.activitySection {\n display: flex;\n flex-direction: column;\n gap: var(--spacing-4, 1rem);\n padding: var(--spacing-6, 1.5rem);\n background: var(--surface-card, #ffffff);\n border: 1px solid var(--border-default, #e5e7eb);\n border-radius: var(--radius-lg, 0.75rem);\n box-shadow: var(--shadow-xs, 0 1px 2px 0 rgb(0 0 0 / 0.05));\n min-width: 0;\n}\n\n.activityHeader {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: var(--spacing-3, 0.75rem);\n min-width: 0;\n}\n\n.activityTitle {\n margin: 0;\n font-family: var(--font-family-heading, inherit);\n font-size: var(--font-size-lg, 1.125rem);\n font-weight: var(--font-weight-semibold, 600);\n line-height: var(--line-height-tight, 1.25);\n letter-spacing: var(--letter-spacing-tight, -0.01em);\n color: var(--text-primary, #111827);\n min-width: 0;\n}\n\n.activityViewAll {\n flex-shrink: 0;\n font-size: var(--font-size-sm, 0.875rem);\n font-weight: var(--font-weight-medium, 500);\n color: var(--text-link, var(--accent-primary, #3b82f6));\n text-decoration: none;\n border-radius: var(--radius-sm, 0.25rem);\n transition:\n color var(--motion-duration-fast, 150ms)\n var(--motion-easing-standard, ease);\n}\n\n.activityViewAll:hover {\n text-decoration: underline;\n}\n\n.activityViewAll:focus-visible {\n outline: var(--focus-ring-width, 2px) solid\n var(--focus-ring-color, var(--accent-primary, #3b82f6));\n outline-offset: var(--focus-ring-offset, 2px);\n}\n\n@container admin-dashboard (max-width: 36rem) {\n .activitySection {\n padding: var(--spacing-4, 1rem);\n }\n}\n"
3355
+ "content": ".root {\n /* Tunable knobs — themes (and one-off pages) can override these without\n reaching into block internals. Defaults match the r3 reference build.\n\n Note: --admin-dashboard-stack-bp is exposed as a custom property for\n theme/documentation discoverability, but CSS @container queries cannot\n dereference custom properties today, so the breakpoint below is the\n hard-coded fallback. Override the @container rule in a theme layer if\n you need a different stack point. */\n --admin-dashboard-side-col-width: 320px;\n --admin-dashboard-stack-bp: 960px;\n\n display: flex;\n flex-direction: column;\n gap: var(--spacing-8, 2rem);\n width: 100%;\n container-type: inline-size;\n container-name: admin-dashboard;\n color: var(--text-primary, #111827);\n}\n\n/* Responsive stat grid driven entirely by container queries. */\n.statGrid {\n display: grid;\n gap: var(--spacing-4, 1rem);\n grid-template-columns: 1fr;\n}\n\n@container admin-dashboard (min-width: 36rem) {\n .statGrid {\n grid-template-columns: repeat(2, minmax(0, 1fr));\n }\n}\n\n@container admin-dashboard (min-width: 56rem) {\n .statGrid {\n grid-template-columns: repeat(3, minmax(0, 1fr));\n gap: var(--spacing-5, 1.25rem);\n }\n}\n\n@container admin-dashboard (min-width: 72rem) {\n .statGrid {\n grid-template-columns: repeat(4, minmax(0, 1fr));\n gap: var(--spacing-6, 1.5rem);\n }\n}\n\n.secondaryRegion {\n display: flex;\n flex-direction: column;\n gap: var(--spacing-4, 1rem);\n min-width: 0;\n}\n\n/* ─── Split body layout ─────────────────────────────────────────────────────\n When layout=\"split\", the activity / secondaryRegion flow is replaced by a\n 2-column grid below the KPI strip. Defaults below mirror the r3 dashboard\n reference (1fr | 320px, 20px gutter). Sub-960px stacks side-col below. */\n\n.body {\n display: flex;\n flex-direction: column;\n gap: var(--spacing-5, 1.25rem);\n min-width: 0;\n}\n\n.body[data-layout=\"split\"] {\n display: grid;\n grid-template-columns: minmax(0, 1fr) var(--admin-dashboard-side-col-width);\n gap: var(--spacing-5, 1.25rem);\n}\n\n.mainCol,\n.sideCol {\n display: flex;\n flex-direction: column;\n gap: var(--spacing-5, 1.25rem);\n min-width: 0;\n}\n\n@container admin-dashboard (max-width: 60rem) {\n /* Default stack breakpoint = 960px (60rem). Override the rule in a theme\n layer if --admin-dashboard-stack-bp is retuned. */\n .body[data-layout=\"split\"] {\n grid-template-columns: minmax(0, 1fr);\n }\n}\n\n.activitySection {\n display: flex;\n flex-direction: column;\n gap: var(--spacing-4, 1rem);\n padding: var(--spacing-6, 1.5rem);\n background: var(--surface-card, #ffffff);\n border: 1px solid var(--border-default, #e5e7eb);\n border-radius: var(--radius-lg, 0.75rem);\n box-shadow: var(--shadow-xs, 0 1px 2px 0 rgb(0 0 0 / 0.05));\n min-width: 0;\n}\n\n.activityHeader {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: var(--spacing-3, 0.75rem);\n min-width: 0;\n}\n\n.activityTitle {\n margin: 0;\n font-family: var(--font-family-heading, inherit);\n font-size: var(--font-size-lg, 1.125rem);\n font-weight: var(--font-weight-semibold, 600);\n line-height: var(--line-height-tight, 1.25);\n letter-spacing: var(--letter-spacing-tight, -0.01em);\n color: var(--text-primary, #111827);\n min-width: 0;\n}\n\n.activityViewAll {\n flex-shrink: 0;\n font-size: var(--font-size-sm, 0.875rem);\n font-weight: var(--font-weight-medium, 500);\n color: var(--text-link, var(--primary, #3b82f6));\n text-decoration: none;\n border-radius: var(--radius-sm, 0.25rem);\n transition:\n color var(--motion-duration-fast, 150ms)\n var(--motion-easing-standard, ease);\n}\n\n.activityViewAll:hover {\n text-decoration: underline;\n}\n\n.activityViewAll:focus-visible {\n outline: var(--focus-ring-width, 2px) solid\n var(--focus-ring-color, var(--primary, #3b82f6));\n outline-offset: var(--focus-ring-offset, 2px);\n}\n\n@container admin-dashboard (max-width: 36rem) {\n .activitySection {\n padding: var(--spacing-4, 1rem);\n }\n}\n"
3326
3356
  }
3327
3357
  ]
3328
3358
  },
@@ -3548,7 +3578,7 @@
3548
3578
  {
3549
3579
  "path": "blocks/workspace-switcher/workspace-switcher.module.css",
3550
3580
  "type": "registry:block",
3551
- "content": "/* Trigger button */\n.trigger {\n display: flex;\n align-items: center;\n gap: var(--spacing-2, 0.5rem);\n width: 100%;\n padding: var(--spacing-2, 0.5rem) var(--spacing-3, 0.75rem);\n background: transparent;\n color: var(--text-primary, #111827);\n border: 1px solid transparent;\n border-radius: var(--radius-md, 0.375rem);\n font-family: inherit;\n font-size: var(--font-size-sm, 0.875rem);\n text-align: start;\n cursor: pointer;\n min-width: 0;\n transition:\n background-color var(--motion-duration-fast, 150ms)\n var(--motion-easing-standard, ease),\n border-color var(--motion-duration-fast, 150ms)\n var(--motion-easing-standard, ease);\n}\n\n.trigger:hover {\n background: var(--surface-interactive-hover, var(--surface-hover, #f3f4f6));\n}\n\n.trigger:focus-visible {\n outline: var(--focus-ring-width, 2px) solid\n var(--focus-ring-color, var(--accent-primary, #3b82f6));\n outline-offset: var(--focus-ring-offset, 2px);\n}\n\n.trigger[data-state=\"open\"] {\n background: var(--surface-interactive-hover, var(--surface-hover, #f3f4f6));\n}\n\n.triggerCompact {\n width: auto;\n padding: var(--spacing-2, 0.5rem);\n}\n\n.triggerAvatar {\n flex-shrink: 0;\n}\n\n.triggerText {\n display: flex;\n flex-direction: column;\n align-items: flex-start;\n flex: 1 1 auto;\n min-width: 0;\n line-height: 1.2;\n}\n\n.triggerName {\n font-weight: var(--font-weight-semibold, 600);\n font-size: var(--font-size-sm, 0.875rem);\n color: var(--text-primary, #111827);\n width: 100%;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.triggerPlan {\n font-weight: var(--font-weight-regular, 400);\n font-size: var(--font-size-xs, 0.75rem);\n color: var(--text-tertiary, var(--text-secondary, #6b7280));\n width: 100%;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n margin-top: var(--spacing-0-5, 0.125rem);\n}\n\n.triggerCaret {\n flex-shrink: 0;\n margin-inline-start: auto;\n color: var(--text-tertiary, var(--text-secondary, #6b7280));\n}\n\n.triggerCompact .triggerCaret {\n margin-inline-start: var(--spacing-1, 0.25rem);\n}\n\n/* Menu content */\n.content {\n min-width: 14rem;\n}\n\n/* Menu item layout (composes onto DropdownMenuItem default styles) */\n.item {\n gap: var(--spacing-2, 0.5rem);\n}\n\n.itemAvatar {\n flex-shrink: 0;\n}\n\n.itemText {\n display: flex;\n flex-direction: column;\n flex: 1 1 auto;\n min-width: 0;\n line-height: 1.2;\n}\n\n.itemName {\n font-weight: var(--font-weight-medium, 500);\n font-size: var(--font-size-sm, 0.875rem);\n color: var(--text-primary, #111827);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.itemPlan {\n font-weight: var(--font-weight-regular, 400);\n font-size: var(--font-size-xs, 0.75rem);\n color: var(--text-tertiary, var(--text-secondary, #6b7280));\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n margin-top: var(--spacing-0-5, 0.125rem);\n}\n\n.itemCheck {\n flex-shrink: 0;\n margin-inline-start: auto;\n color: var(--text-secondary, #6b7280);\n}\n\n.emptyItem {\n font-size: var(--font-size-sm, 0.875rem);\n color: var(--text-tertiary, var(--text-secondary, #6b7280));\n}\n"
3581
+ "content": "/* Trigger button */\n.trigger {\n display: flex;\n align-items: center;\n gap: var(--spacing-2, 0.5rem);\n width: 100%;\n padding: var(--spacing-2, 0.5rem) var(--spacing-3, 0.75rem);\n background: transparent;\n color: var(--text-primary, #111827);\n border: 1px solid transparent;\n border-radius: var(--radius-md, 0.375rem);\n font-family: inherit;\n font-size: var(--font-size-sm, 0.875rem);\n text-align: start;\n cursor: pointer;\n min-width: 0;\n transition:\n background-color var(--motion-duration-fast, 150ms)\n var(--motion-easing-standard, ease),\n border-color var(--motion-duration-fast, 150ms)\n var(--motion-easing-standard, ease);\n}\n\n.trigger:hover {\n background: var(--surface-interactive-hover, var(--surface-hover, #f3f4f6));\n}\n\n.trigger:focus-visible {\n outline: var(--focus-ring-width, 2px) solid\n var(--focus-ring-color, var(--primary, #3b82f6));\n outline-offset: var(--focus-ring-offset, 2px);\n}\n\n.trigger[data-state=\"open\"] {\n background: var(--surface-interactive-hover, var(--surface-hover, #f3f4f6));\n}\n\n.triggerCompact {\n width: auto;\n padding: var(--spacing-2, 0.5rem);\n}\n\n.triggerAvatar {\n flex-shrink: 0;\n}\n\n.triggerText {\n display: flex;\n flex-direction: column;\n align-items: flex-start;\n flex: 1 1 auto;\n min-width: 0;\n line-height: 1.2;\n}\n\n.triggerName {\n font-weight: var(--font-weight-semibold, 600);\n font-size: var(--font-size-sm, 0.875rem);\n color: var(--text-primary, #111827);\n width: 100%;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.triggerPlan {\n font-weight: var(--font-weight-regular, 400);\n font-size: var(--font-size-xs, 0.75rem);\n color: var(--text-tertiary, var(--text-secondary, #6b7280));\n width: 100%;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n margin-top: var(--spacing-0-5, 0.125rem);\n}\n\n.triggerCaret {\n flex-shrink: 0;\n margin-inline-start: auto;\n color: var(--text-tertiary, var(--text-secondary, #6b7280));\n}\n\n.triggerCompact .triggerCaret {\n margin-inline-start: var(--spacing-1, 0.25rem);\n}\n\n/* Menu content */\n.content {\n min-width: 14rem;\n}\n\n/* Menu item layout (composes onto DropdownMenuItem default styles) */\n.item {\n gap: var(--spacing-2, 0.5rem);\n}\n\n.itemAvatar {\n flex-shrink: 0;\n}\n\n.itemText {\n display: flex;\n flex-direction: column;\n flex: 1 1 auto;\n min-width: 0;\n line-height: 1.2;\n}\n\n.itemName {\n font-weight: var(--font-weight-medium, 500);\n font-size: var(--font-size-sm, 0.875rem);\n color: var(--text-primary, #111827);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.itemPlan {\n font-weight: var(--font-weight-regular, 400);\n font-size: var(--font-size-xs, 0.75rem);\n color: var(--text-tertiary, var(--text-secondary, #6b7280));\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n margin-top: var(--spacing-0-5, 0.125rem);\n}\n\n.itemCheck {\n flex-shrink: 0;\n margin-inline-start: auto;\n color: var(--text-secondary, #6b7280);\n}\n\n.emptyItem {\n font-size: var(--font-size-sm, 0.875rem);\n color: var(--text-tertiary, var(--text-secondary, #6b7280));\n}\n"
3552
3582
  }
3553
3583
  ]
3554
3584
  },
@@ -3575,7 +3605,7 @@
3575
3605
  {
3576
3606
  "path": "blocks/profile-menu/profile-menu.module.css",
3577
3607
  "type": "registry:block",
3578
- "content": "/* Trigger button */\n.trigger {\n display: flex;\n align-items: center;\n gap: var(--spacing-3, 0.75rem);\n width: 100%;\n padding: var(--spacing-2, 0.5rem) var(--spacing-3, 0.75rem);\n background: transparent;\n color: var(--text-primary, #111827);\n border: 1px solid transparent;\n border-radius: var(--radius-md, 0.375rem);\n font-family: inherit;\n font-size: var(--font-size-sm, 0.875rem);\n text-align: start;\n cursor: pointer;\n min-width: 0;\n transition:\n background-color var(--motion-duration-fast, 150ms)\n var(--motion-easing-standard, ease),\n border-color var(--motion-duration-fast, 150ms)\n var(--motion-easing-standard, ease);\n}\n\n.trigger:hover {\n background: var(--surface-interactive-hover, var(--surface-hover, #f3f4f6));\n}\n\n.trigger:focus-visible {\n outline: var(--focus-ring-width, 2px) solid\n var(--focus-ring-color, var(--accent-primary, #3b82f6));\n outline-offset: var(--focus-ring-offset, 2px);\n}\n\n.trigger[data-state=\"open\"] {\n background: var(--surface-interactive-hover, var(--surface-hover, #f3f4f6));\n}\n\n.triggerAvatarWrap {\n position: relative;\n flex-shrink: 0;\n display: inline-flex;\n}\n\n.triggerAvatar {\n flex-shrink: 0;\n}\n\n.statusDot {\n position: absolute;\n bottom: 0;\n right: 0;\n width: var(--spacing-2-5, 0.625rem);\n height: var(--spacing-2-5, 0.625rem);\n border-radius: 999px;\n border: var(--stroke-width-medium, 2px) solid\n var(--surface-card, #ffffff);\n background: var(--text-tertiary, #6b7280);\n}\n\n.statusDot[data-status=\"online\"] {\n background: var(--status-success, #10b981);\n}\n\n.statusDot[data-status=\"away\"] {\n background: var(--status-warning, #f59e0b);\n}\n\n.statusDot[data-status=\"busy\"] {\n background: var(--status-error, #ef4444);\n}\n\n.statusDot[data-status=\"offline\"] {\n background: var(--text-tertiary, #6b7280);\n}\n\n.triggerIdentity {\n display: flex;\n flex-direction: column;\n align-items: flex-start;\n flex: 1 1 auto;\n min-width: 0;\n line-height: 1.2;\n}\n\n.triggerName {\n font-weight: var(--font-weight-semibold, 600);\n font-size: var(--font-size-sm, 0.875rem);\n color: var(--text-primary, #111827);\n width: 100%;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.triggerContext {\n display: inline-flex;\n align-items: center;\n gap: var(--spacing-1, 0.25rem);\n font-weight: var(--font-weight-regular, 400);\n font-size: var(--font-size-xs, 0.75rem);\n color: var(--text-tertiary, var(--text-secondary, #6b7280));\n width: 100%;\n min-width: 0;\n margin-top: var(--spacing-0-5, 0.125rem);\n}\n\n.triggerContextIcon {\n display: inline-flex;\n flex-shrink: 0;\n width: 0.875rem;\n height: 0.875rem;\n}\n\n.triggerContextLabel {\n min-width: 0;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.triggerCaret {\n flex-shrink: 0;\n margin-inline-start: auto;\n color: var(--text-tertiary, var(--text-secondary, #6b7280));\n}\n\n/* Menu content */\n.content {\n min-width: 14rem;\n}\n\n.menuHeader {\n display: flex;\n flex-direction: column;\n gap: var(--spacing-0-5, 0.125rem);\n padding: var(--spacing-2, 0.5rem) var(--spacing-3, 0.75rem);\n}\n\n.menuHeaderHint {\n font-size: var(--font-size-xs, 0.75rem);\n color: var(--text-tertiary, var(--text-secondary, #6b7280));\n}\n\n.menuHeaderEmail {\n font-size: var(--font-size-sm, 0.875rem);\n font-weight: var(--font-weight-medium, 500);\n color: var(--text-primary, #111827);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n/* Item rows */\n.item {\n gap: var(--spacing-2, 0.5rem);\n}\n\n.itemIcon {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 1rem;\n height: 1rem;\n flex-shrink: 0;\n color: var(--text-secondary, #6b7280);\n}\n\n.itemLabel {\n flex: 1 1 auto;\n min-width: 0;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.itemBadge {\n margin-inline-start: auto;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n min-width: 1.25rem;\n padding: 0 var(--spacing-1-5, 0.375rem);\n border-radius: 999px;\n background: var(--accent-subtle, color-mix(in srgb, var(--accent-primary, #3b82f6) 18%, transparent));\n color: var(--accent-primary, #3b82f6);\n font-size: var(--font-size-xs, 0.75rem);\n font-weight: var(--font-weight-semibold, 600);\n line-height: 1.4;\n}\n\n/* When both badge and shortcut are present, keep shortcut after badge. */\n.itemBadge + .itemShortcut {\n margin-inline-start: var(--spacing-2, 0.5rem);\n}\n\n.itemShortcut {\n /* DropdownMenuShortcut already aligns to the end via margin-left: auto.\n When a badge precedes it, we override margin-left above to keep spacing. */\n}\n"
3608
+ "content": "/* Trigger button */\n.trigger {\n display: flex;\n align-items: center;\n gap: var(--spacing-3, 0.75rem);\n width: 100%;\n padding: var(--spacing-2, 0.5rem) var(--spacing-3, 0.75rem);\n background: transparent;\n color: var(--text-primary, #111827);\n border: 1px solid transparent;\n border-radius: var(--radius-md, 0.375rem);\n font-family: inherit;\n font-size: var(--font-size-sm, 0.875rem);\n text-align: start;\n cursor: pointer;\n min-width: 0;\n transition:\n background-color var(--motion-duration-fast, 150ms)\n var(--motion-easing-standard, ease),\n border-color var(--motion-duration-fast, 150ms)\n var(--motion-easing-standard, ease);\n}\n\n.trigger:hover {\n background: var(--surface-interactive-hover, var(--surface-hover, #f3f4f6));\n}\n\n.trigger:focus-visible {\n outline: var(--focus-ring-width, 2px) solid\n var(--focus-ring-color, var(--primary, #3b82f6));\n outline-offset: var(--focus-ring-offset, 2px);\n}\n\n.trigger[data-state=\"open\"] {\n background: var(--surface-interactive-hover, var(--surface-hover, #f3f4f6));\n}\n\n.triggerAvatarWrap {\n position: relative;\n flex-shrink: 0;\n display: inline-flex;\n}\n\n.triggerAvatar {\n flex-shrink: 0;\n}\n\n.statusDot {\n position: absolute;\n bottom: 0;\n right: 0;\n width: var(--spacing-2-5, 0.625rem);\n height: var(--spacing-2-5, 0.625rem);\n border-radius: 999px;\n border: var(--stroke-width-medium, 2px) solid\n var(--surface-card, #ffffff);\n background: var(--text-tertiary, #6b7280);\n}\n\n.statusDot[data-status=\"online\"] {\n background: var(--status-success, #10b981);\n}\n\n.statusDot[data-status=\"away\"] {\n background: var(--status-warning, #f59e0b);\n}\n\n.statusDot[data-status=\"busy\"] {\n background: var(--status-error, #ef4444);\n}\n\n.statusDot[data-status=\"offline\"] {\n background: var(--text-tertiary, #6b7280);\n}\n\n.triggerIdentity {\n display: flex;\n flex-direction: column;\n align-items: flex-start;\n flex: 1 1 auto;\n min-width: 0;\n line-height: 1.2;\n}\n\n.triggerName {\n font-weight: var(--font-weight-semibold, 600);\n font-size: var(--font-size-sm, 0.875rem);\n color: var(--text-primary, #111827);\n width: 100%;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.triggerContext {\n display: inline-flex;\n align-items: center;\n gap: var(--spacing-1, 0.25rem);\n font-weight: var(--font-weight-regular, 400);\n font-size: var(--font-size-xs, 0.75rem);\n color: var(--text-tertiary, var(--text-secondary, #6b7280));\n width: 100%;\n min-width: 0;\n margin-top: var(--spacing-0-5, 0.125rem);\n}\n\n.triggerContextIcon {\n display: inline-flex;\n flex-shrink: 0;\n width: 0.875rem;\n height: 0.875rem;\n}\n\n.triggerContextLabel {\n min-width: 0;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.triggerCaret {\n flex-shrink: 0;\n margin-inline-start: auto;\n color: var(--text-tertiary, var(--text-secondary, #6b7280));\n}\n\n/* Menu content */\n.content {\n min-width: 14rem;\n}\n\n.menuHeader {\n display: flex;\n flex-direction: column;\n gap: var(--spacing-0-5, 0.125rem);\n padding: var(--spacing-2, 0.5rem) var(--spacing-3, 0.75rem);\n}\n\n.menuHeaderHint {\n font-size: var(--font-size-xs, 0.75rem);\n color: var(--text-tertiary, var(--text-secondary, #6b7280));\n}\n\n.menuHeaderEmail {\n font-size: var(--font-size-sm, 0.875rem);\n font-weight: var(--font-weight-medium, 500);\n color: var(--text-primary, #111827);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n/* Item rows */\n.item {\n gap: var(--spacing-2, 0.5rem);\n}\n\n.itemIcon {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 1rem;\n height: 1rem;\n flex-shrink: 0;\n color: var(--text-secondary, #6b7280);\n}\n\n.itemLabel {\n flex: 1 1 auto;\n min-width: 0;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.itemBadge {\n margin-inline-start: auto;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n min-width: 1.25rem;\n padding: 0 var(--spacing-1-5, 0.375rem);\n border-radius: 999px;\n background: var(--accent-subtle, color-mix(in srgb, var(--primary, #3b82f6) 18%, transparent));\n color: var(--primary, #3b82f6);\n font-size: var(--font-size-xs, 0.75rem);\n font-weight: var(--font-weight-semibold, 600);\n line-height: 1.4;\n}\n\n/* When both badge and shortcut are present, keep shortcut after badge. */\n.itemBadge + .itemShortcut {\n margin-inline-start: var(--spacing-2, 0.5rem);\n}\n\n.itemShortcut {\n /* DropdownMenuShortcut already aligns to the end via margin-left: auto.\n When a badge precedes it, we override margin-left above to keep spacing. */\n}\n"
3579
3609
  }
3580
3610
  ]
3581
3611
  },
@@ -3992,31 +4022,6 @@
3992
4022
  }
3993
4023
  ]
3994
4024
  },
3995
- {
3996
- "name": "avatar-stack",
3997
- "type": "registry:block",
3998
- "description": "Overlapping avatar group with `+N more` overflow indicator. Pure composition of the Avatar primitive — supports sm / default / lg sizes, configurable max, server-truncated counts, and an overridable accessible label.",
3999
- "category": "data-display",
4000
- "dependencies": [
4001
- "@loworbitstudio/visor-core"
4002
- ],
4003
- "registryDependencies": [
4004
- "utils",
4005
- "avatar"
4006
- ],
4007
- "files": [
4008
- {
4009
- "path": "blocks/avatar-stack/avatar-stack.tsx",
4010
- "type": "registry:block",
4011
- "content": "\"use client\"\n\nimport * as React from \"react\"\nimport {\n Avatar,\n AvatarFallback,\n AvatarImage,\n} from \"../../components/ui/avatar/avatar\"\nimport { cn } from \"../../lib/utils\"\nimport styles from \"./avatar-stack.module.css\"\n\nexport interface AvatarStackProps\n extends Omit<React.HTMLAttributes<HTMLDivElement>, \"role\" | \"aria-label\"> {\n /**\n * Avatar image sources to render, in display order. `undefined` entries\n * render with the `·` fallback so server-truncated lists still occupy a\n * slot.\n */\n avatars: (string | undefined)[]\n /**\n * Total member count. May exceed `avatars.length` when the caller has\n * server-truncated the avatar URLs and only knows the count. The overflow\n * indicator is computed against this value.\n */\n total: number\n /**\n * Maximum number of avatar slots rendered before the `+N` overflow\n * indicator. Defaults to `6`.\n */\n max?: number\n /** Avatar size. Defaults to `\"sm\"`. */\n size?: \"sm\" | \"default\" | \"lg\"\n /**\n * Accessible label override. Defaults to ``${total} members``.\n */\n label?: string\n}\n\nconst AvatarStack = React.forwardRef<HTMLDivElement, AvatarStackProps>(\n function AvatarStack(\n {\n avatars,\n total,\n max = 6,\n size = \"sm\",\n label,\n className,\n ...rest\n },\n ref,\n ) {\n const visible = avatars.slice(0, max)\n const overflow = Math.max(0, total - visible.length)\n const ariaLabel = label ?? `${total} members`\n\n return (\n <div\n ref={ref}\n role=\"img\"\n aria-label={ariaLabel}\n data-slot=\"avatar-stack\"\n data-size={size}\n className={cn(styles.root, className)}\n {...rest}\n >\n {visible.map((src, index) => (\n <Avatar\n key={index}\n size={size}\n className={styles.avatar}\n data-stack-item=\"\"\n >\n {src ? (\n <AvatarImage src={src} alt=\"\" />\n ) : (\n <AvatarFallback>·</AvatarFallback>\n )}\n </Avatar>\n ))}\n {overflow > 0 ? (\n <Avatar\n size={size}\n className={styles.avatar}\n data-stack-overflow=\"\"\n >\n <AvatarFallback>+{overflow}</AvatarFallback>\n </Avatar>\n ) : null}\n </div>\n )\n },\n)\n\nAvatarStack.displayName = \"AvatarStack\"\n\nexport { AvatarStack }\n"
4012
- },
4013
- {
4014
- "path": "blocks/avatar-stack/avatar-stack.module.css",
4015
- "type": "registry:block",
4016
- "content": "/* AvatarStack root */\n.root {\n display: inline-flex;\n flex-direction: row;\n align-items: center;\n isolation: isolate;\n}\n\n/* Each avatar gets a ring matching the parent surface so adjacent avatars\n read as separate circles. Avatar's own `overflow: hidden` clips inner\n shadows, so the ring is projected outward via box-shadow. */\n.avatar {\n box-shadow: 0 0 0 var(--stroke-width-medium, 2px) var(--surface-default, #ffffff);\n}\n\n/* Overlap every avatar except the first. Later siblings stack on top of\n earlier ones because `isolation: isolate` establishes a single stacking\n context and DOM order wins inside it. */\n.avatar:not(:first-child) {\n margin-inline-start: calc(-1 * var(--spacing-2, 0.5rem));\n}\n"
4017
- }
4018
- ]
4019
- },
4020
4025
  {
4021
4026
  "name": "chip-group",
4022
4027
  "type": "registry:block",
@@ -4072,7 +4077,7 @@
4072
4077
  {
4073
4078
  "name": "login-form",
4074
4079
  "type": "registry:block",
4075
- "description": "A login form block using Visor form components (Button, Input, Label, Card).",
4080
+ "description": "A login form block using Visor form components (Button, Input, Label, Card), with optional OAuth provider buttons.",
4076
4081
  "category": "authentication",
4077
4082
  "dependencies": [
4078
4083
  "@loworbitstudio/visor-core"
@@ -4082,18 +4087,20 @@
4082
4087
  "button",
4083
4088
  "input",
4084
4089
  "field",
4085
- "card"
4090
+ "card",
4091
+ "separator",
4092
+ "alert"
4086
4093
  ],
4087
4094
  "files": [
4088
4095
  {
4089
4096
  "path": "blocks/login-form/login-form.tsx",
4090
4097
  "type": "registry:block",
4091
- "content": "\"use client\"\n\nimport { cn } from \"../../lib/utils\"\nimport { Button } from \"../../components/ui/button/button\"\nimport { Input } from \"../../components/ui/input/input\"\nimport { Field, FieldLabel } from \"../../components/ui/field/field\"\nimport { Card } from \"../../components/ui/card/card\"\nimport styles from \"./login-form.module.css\"\n\ninterface LoginFormProps {\n className?: string\n}\n\nexport function LoginForm({\n className,\n}: LoginFormProps) {\n return (\n <Card className={cn(styles.root, className)}>\n <div className={styles.header}>\n <h2 className={styles.title}>Sign in</h2>\n <p className={styles.description}>\n Enter your credentials to continue.\n </p>\n </div>\n <form className={styles.form} onSubmit={(e) => e.preventDefault()}>\n <Field>\n <FieldLabel htmlFor=\"login-email\">Email</FieldLabel>\n <Input\n id=\"login-email\"\n type=\"email\"\n placeholder=\"you@example.com\"\n />\n </Field>\n <Field>\n <FieldLabel htmlFor=\"login-password\">Password</FieldLabel>\n <Input\n id=\"login-password\"\n type=\"password\"\n placeholder=\"••••••••\"\n />\n </Field>\n <Button type=\"submit\" className={styles.button}>\n Sign in\n </Button>\n </form>\n </Card>\n )\n}\n"
4098
+ "content": "\"use client\"\n\nimport * as React from \"react\"\nimport { cn } from \"../../lib/utils\"\nimport { Button } from \"../../components/ui/button/button\"\nimport { Input } from \"../../components/ui/input/input\"\nimport { Field, FieldLabel } from \"../../components/ui/field/field\"\nimport { Card } from \"../../components/ui/card/card\"\nimport { Separator } from \"../../components/ui/separator/separator\"\nimport { Alert } from \"../../components/ui/alert/alert\"\nimport styles from \"./login-form.module.css\"\n\nexport interface OAuthProvider {\n /** Stable identifier passed to `onOAuthSignIn` (e.g. \"google\"). */\n id: string\n /** Button contents — text, or text alongside a caller-supplied icon. */\n label: React.ReactNode\n /** Optional leading icon. The block ships no provider assets. */\n icon?: React.ReactNode\n}\n\nexport interface LoginFormProps {\n className?: string\n /** OAuth providers to render as outline buttons above the credentials form. */\n oauthProviders?: OAuthProvider[]\n /** Called with the provider `id` when its button is clicked. May be async. */\n onOAuthSignIn?: (id: string) => void | Promise<void>\n /** Label shown in the divider between OAuth and credentials. */\n dividerLabel?: React.ReactNode\n /** Error message rendered in a destructive Alert above the form. */\n error?: string | null\n /** Hide the email/password fields and submit button (OAuth-only flows). */\n hideCredentials?: boolean\n}\n\nexport function LoginForm({\n className,\n oauthProviders,\n onOAuthSignIn,\n dividerLabel = \"or continue with\",\n error,\n hideCredentials = false,\n}: LoginFormProps) {\n const [pendingId, setPendingId] = React.useState<string | null>(null)\n\n const hasOAuth = !!oauthProviders && oauthProviders.length > 0\n const showCredentials = !hideCredentials\n const showDivider = hasOAuth && showCredentials\n\n async function handleOAuth(id: string) {\n if (!onOAuthSignIn) return\n setPendingId(id)\n try {\n await onOAuthSignIn(id)\n } catch {\n // Errors surface to the user via the `error` prop, which the consumer\n // sets from its own catch. Swallow here so a rejected handler doesn't\n // become an unhandled promise rejection from this fire-and-forget click.\n } finally {\n setPendingId(null)\n }\n }\n\n return (\n <Card className={cn(styles.root, className)}>\n <div className={styles.header}>\n <h2 className={styles.title}>Sign in</h2>\n <p className={styles.description}>\n Enter your credentials to continue.\n </p>\n </div>\n\n {error ? (\n <Alert variant=\"destructive\" className={styles.error}>\n {error}\n </Alert>\n ) : null}\n\n {hasOAuth ? (\n <div className={styles.oauthGroup}>\n {oauthProviders!.map((provider) => (\n <Button\n key={provider.id}\n type=\"button\"\n variant=\"outline\"\n className={styles.button}\n disabled={pendingId !== null}\n aria-busy={pendingId === provider.id}\n onClick={() => handleOAuth(provider.id)}\n >\n {provider.icon}\n {provider.label}\n </Button>\n ))}\n </div>\n ) : null}\n\n {showDivider ? (\n <div className={styles.divider}>\n <Separator />\n <span className={styles.dividerLabel}>{dividerLabel}</span>\n <Separator />\n </div>\n ) : null}\n\n {showCredentials ? (\n <form className={styles.form} onSubmit={(e) => e.preventDefault()}>\n <Field>\n <FieldLabel htmlFor=\"login-email\">Email</FieldLabel>\n <Input\n id=\"login-email\"\n type=\"email\"\n placeholder=\"you@example.com\"\n />\n </Field>\n <Field>\n <FieldLabel htmlFor=\"login-password\">Password</FieldLabel>\n <Input\n id=\"login-password\"\n type=\"password\"\n placeholder=\"••••••••\"\n />\n </Field>\n <Button type=\"submit\" className={styles.button}>\n Sign in\n </Button>\n </form>\n ) : null}\n </Card>\n )\n}\n"
4092
4099
  },
4093
4100
  {
4094
4101
  "path": "blocks/login-form/login-form.module.css",
4095
4102
  "type": "registry:block",
4096
- "content": ".root {\n display: flex;\n flex-direction: column;\n gap: var(--spacing-6, 1.5rem);\n width: 100%;\n max-width: 24rem;\n margin: 0 auto;\n padding: var(--spacing-8, 2rem);\n}\n\n.header {\n display: flex;\n flex-direction: column;\n gap: var(--spacing-2, 0.5rem);\n text-align: center;\n}\n\n.title {\n font-size: var(--font-size-xl, 1.25rem);\n font-weight: 600;\n color: var(--text-primary, #111827);\n margin: 0;\n}\n\n.description {\n font-size: var(--font-size-sm, 0.875rem);\n color: var(--text-secondary, #6b7280);\n margin: 0;\n}\n\n.form {\n display: flex;\n flex-direction: column;\n gap: var(--spacing-4, 1rem);\n}\n\n.button {\n width: 100%;\n}\n"
4103
+ "content": ".root {\n display: flex;\n flex-direction: column;\n gap: var(--spacing-6, 1.5rem);\n width: 100%;\n max-width: 24rem;\n margin: 0 auto;\n padding: var(--spacing-8, 2rem);\n}\n\n.header {\n display: flex;\n flex-direction: column;\n gap: var(--spacing-2, 0.5rem);\n text-align: center;\n}\n\n.title {\n font-size: var(--font-size-xl, 1.25rem);\n font-weight: 600;\n color: var(--text-primary, #111827);\n margin: 0;\n}\n\n.description {\n font-size: var(--font-size-sm, 0.875rem);\n color: var(--text-secondary, #6b7280);\n margin: 0;\n}\n\n.form {\n display: flex;\n flex-direction: column;\n gap: var(--spacing-4, 1rem);\n}\n\n.button {\n width: 100%;\n}\n\n.oauthGroup {\n display: flex;\n flex-direction: column;\n gap: var(--spacing-3, 0.75rem);\n}\n\n.divider {\n display: flex;\n align-items: center;\n gap: var(--spacing-3, 0.75rem);\n}\n\n.divider > [data-slot=\"separator\"] {\n flex: 1;\n}\n\n.dividerLabel {\n font-size: var(--font-size-sm, 0.875rem);\n color: var(--text-secondary, #6b7280);\n white-space: nowrap;\n}\n\n.error {\n text-align: left;\n}\n"
4097
4104
  }
4098
4105
  ]
4099
4106
  },
@@ -4203,7 +4210,7 @@
4203
4210
  {
4204
4211
  "path": "blocks/prototype-review/prototype-review.module.css",
4205
4212
  "type": "registry:block",
4206
- "content": "/* ============================================================\n Prototype Review block\n Theme-agnostic. All colors come from Visor semantic tokens.\n The brand color is injected by the React block as\n --prototype-review-brand (per-instance override).\n ============================================================ */\n\n.root {\n display: flex;\n flex-direction: column;\n width: 100%;\n min-height: 100vh;\n background: var(--surface-page);\n color: var(--text-primary);\n font-family: var(\n --font-body,\n var(--font-family-body, ui-sans-serif, system-ui, sans-serif)\n );\n font-weight: 300;\n line-height: 1.5;\n -webkit-font-smoothing: antialiased;\n container-type: inline-size;\n}\n\n/* ─── Header ─────────────────────────────────────────────── */\n\n.chrome {\n position: sticky;\n top: 0;\n z-index: 100;\n background: var(--surface-card);\n border-bottom: var(--stroke-width-thin, 1px) solid var(--border-muted);\n}\n\n.chromeRow {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: var(--spacing-6);\n padding: var(--spacing-3) var(--spacing-7);\n flex-wrap: wrap;\n}\n\n.brand {\n display: flex;\n align-items: center;\n gap: var(--spacing-3);\n min-width: 0;\n}\n\n.brandMark {\n width: 1.75rem;\n height: 1.75rem;\n background: var(--prototype-review-brand, var(--interactive-primary-bg));\n display: grid;\n place-items: center;\n color: var(--prototype-review-brand-on, var(--interactive-primary-text));\n font-family: var(\n --font-display,\n var(--font-family-display, var(--font-family-heading, inherit))\n );\n font-weight: 700;\n font-size: var(--font-size-xs);\n letter-spacing: -0.02em;\n}\n\n.brandText {\n display: flex;\n flex-direction: column;\n line-height: 1.15;\n}\n\n.brandName {\n font-family: var(\n --font-display,\n var(--font-family-display, var(--font-family-heading, inherit))\n );\n font-weight: 600;\n font-size: var(--font-size-sm);\n letter-spacing: 0.12em;\n text-transform: uppercase;\n}\n\n.brandSub {\n font-family: var(--font-mono, var(--font-family-mono, monospace));\n font-size: var(--font-size-xs);\n color: var(--text-tertiary);\n letter-spacing: 0.05em;\n}\n\n.chromeActions {\n display: flex;\n gap: var(--spacing-2);\n align-items: center;\n flex-wrap: wrap;\n}\n\n.pill {\n font-family: var(--font-mono, var(--font-family-mono, monospace));\n font-size: var(--font-size-xs);\n text-transform: uppercase;\n letter-spacing: 0.12em;\n padding: var(--spacing-1) var(--spacing-2);\n border: var(--stroke-width-thin, 1px) solid var(--border-default);\n color: var(--text-tertiary);\n border-radius: var(--radius-full, 9999px);\n}\n\n.pillBrand {\n background: var(--prototype-review-brand-soft, var(--surface-subtle));\n border-color: var(--prototype-review-brand, var(--border-default));\n color: var(--prototype-review-brand, var(--text-primary));\n}\n\n/* ─── Controls ───────────────────────────────────────────── */\n\n.controls {\n border-bottom: var(--stroke-width-thin, 1px) solid var(--border-muted);\n background: var(--surface-muted, var(--surface-subtle));\n}\n\n.controlsRow {\n display: grid;\n grid-template-columns: minmax(0, 1fr) auto auto;\n gap: var(--spacing-6);\n align-items: center;\n padding: var(--spacing-3) var(--spacing-7);\n}\n\n@container (max-width: 64rem) {\n .controlsRow {\n grid-template-columns: 1fr;\n }\n}\n\n.controlGroup {\n display: flex;\n align-items: center;\n gap: var(--spacing-4);\n flex-wrap: wrap;\n}\n\n.controlLabel {\n font-family: var(--font-mono, var(--font-family-mono, monospace));\n font-size: var(--font-size-xs);\n letter-spacing: 0.12em;\n text-transform: uppercase;\n color: var(--text-tertiary);\n}\n\n/* Tabs */\n\n.tabs {\n display: flex;\n gap: 0;\n flex-wrap: wrap;\n align-items: stretch;\n border: var(--stroke-width-thin, 1px) solid var(--border-default);\n background: var(--surface-page);\n width: fit-content;\n border-radius: var(--radius-full, 9999px);\n overflow: hidden;\n}\n\n.tab {\n background: transparent;\n border: none;\n color: var(--text-tertiary);\n font-family: var(--font-mono, var(--font-family-mono, monospace));\n font-size: var(--font-size-xs);\n letter-spacing: 0.08em;\n text-transform: uppercase;\n padding: var(--spacing-2) var(--spacing-4);\n cursor: pointer;\n transition:\n color var(--motion-duration-fast, 150ms)\n var(--motion-easing-standard, ease),\n background var(--motion-duration-fast, 150ms)\n var(--motion-easing-standard, ease);\n}\n\n.tab:hover {\n color: var(--text-primary);\n}\n\n.tab[aria-selected=\"true\"] {\n background: var(--prototype-review-brand, var(--interactive-primary-bg));\n color: var(--prototype-review-brand-on, var(--interactive-primary-text));\n}\n\n.tab:focus-visible {\n outline: var(--focus-ring-width, 2px) solid\n var(--focus-ring-color, var(--prototype-review-brand, var(--accent-primary)));\n outline-offset: calc(var(--focus-ring-offset, 2px) * -1);\n}\n\n.tabId {\n font-family: var(\n --font-display,\n var(--font-family-display, var(--font-family-heading, inherit))\n );\n font-weight: 600;\n letter-spacing: 0.02em;\n text-transform: none;\n font-size: var(--font-size-sm);\n margin-right: var(--spacing-2);\n}\n\n/* Theme select */\n\n.themeGroup {\n display: flex;\n align-items: center;\n gap: var(--spacing-2);\n}\n\n.themeSelect {\n background: var(--surface-page);\n border: var(--stroke-width-thin, 1px) solid var(--border-default);\n color: var(--text-primary);\n font-family: var(--font-mono, var(--font-family-mono, monospace));\n font-size: var(--font-size-xs);\n padding: var(--spacing-2) var(--spacing-3);\n border-radius: var(--radius-full, 9999px);\n cursor: pointer;\n letter-spacing: 0.05em;\n text-transform: uppercase;\n}\n\n.themeSelect:focus-visible {\n outline: var(--focus-ring-width, 2px) solid\n var(--focus-ring-color, var(--prototype-review-brand, var(--accent-primary)));\n outline-offset: var(--focus-ring-offset, 2px);\n}\n\n/* Mode + viewport toggle buttons */\n\n.modeGroup,\n.vpGroup {\n display: flex;\n align-items: center;\n gap: var(--spacing-2);\n}\n\n.toggleButtons {\n display: flex;\n border: var(--stroke-width-thin, 1px) solid var(--border-default);\n background: var(--surface-page);\n border-radius: var(--radius-full, 9999px);\n overflow: hidden;\n}\n\n.toggleButton {\n background: transparent;\n border: none;\n color: var(--text-tertiary);\n font-family: var(--font-mono, var(--font-family-mono, monospace));\n font-size: var(--font-size-xs);\n letter-spacing: 0.05em;\n padding: var(--spacing-2) var(--spacing-3);\n cursor: pointer;\n text-transform: uppercase;\n transition:\n color var(--motion-duration-fast, 150ms)\n var(--motion-easing-standard, ease),\n background var(--motion-duration-fast, 150ms)\n var(--motion-easing-standard, ease);\n}\n\n.toggleButton:hover {\n color: var(--text-primary);\n}\n\n.toggleButton[aria-pressed=\"true\"] {\n background: var(--prototype-review-brand, var(--interactive-primary-bg));\n color: var(--prototype-review-brand-on, var(--interactive-primary-text));\n}\n\n.toggleButton:focus-visible {\n outline: var(--focus-ring-width, 2px) solid\n var(--focus-ring-color, var(--prototype-review-brand, var(--accent-primary)));\n outline-offset: calc(var(--focus-ring-offset, 2px) * -1);\n}\n\n/* Brand picker */\n\n.picker {\n display: flex;\n align-items: center;\n gap: var(--spacing-3);\n flex-wrap: wrap;\n}\n\n.swatches {\n display: flex;\n gap: var(--spacing-1);\n align-items: center;\n}\n\n.swatch {\n width: 1.375rem;\n height: 1.375rem;\n border-radius: var(--radius-full, 9999px);\n border: var(--stroke-width-medium, 2px) solid transparent;\n cursor: pointer;\n padding: 0;\n transition:\n transform var(--motion-duration-fast, 150ms)\n var(--motion-easing-standard, ease),\n border-color var(--motion-duration-fast, 150ms)\n var(--motion-easing-standard, ease);\n}\n\n.swatch:hover {\n transform: scale(1.12);\n}\n\n.swatch[data-active=\"true\"] {\n border-color: var(--text-primary);\n box-shadow: 0 0 0 var(--stroke-width-medium, 2px) var(--surface-page);\n}\n\n.swatch:focus-visible {\n outline: var(--focus-ring-width, 2px) solid\n var(--focus-ring-color, var(--prototype-review-brand, var(--accent-primary)));\n outline-offset: var(--focus-ring-offset, 2px);\n}\n\n.hexInput {\n background: var(--surface-page);\n border: var(--stroke-width-thin, 1px) solid var(--border-default);\n color: var(--text-primary);\n font-family: var(--font-mono, var(--font-family-mono, monospace));\n font-size: var(--font-size-xs);\n padding: var(--spacing-1) var(--spacing-3);\n width: 8.5rem;\n letter-spacing: 0.05em;\n text-transform: uppercase;\n border-radius: var(--radius-full, 9999px);\n}\n\n.hexInput:focus {\n outline: none;\n border-color: var(--prototype-review-brand, var(--border-default));\n}\n\n.hexInput:focus-visible {\n outline: var(--focus-ring-width, 2px) solid\n var(--focus-ring-color, var(--prototype-review-brand, var(--accent-primary)));\n outline-offset: var(--focus-ring-offset, 2px);\n}\n\n.resetButton {\n background: transparent;\n border: var(--stroke-width-thin, 1px) solid var(--border-default);\n color: var(--text-tertiary);\n font-family: var(--font-mono, var(--font-family-mono, monospace));\n font-size: var(--font-size-xs);\n letter-spacing: 0.1em;\n text-transform: uppercase;\n padding: var(--spacing-1) var(--spacing-3);\n border-radius: var(--radius-full, 9999px);\n cursor: pointer;\n transition:\n color var(--motion-duration-fast, 150ms)\n var(--motion-easing-standard, ease),\n border-color var(--motion-duration-fast, 150ms)\n var(--motion-easing-standard, ease);\n}\n\n.resetButton:hover {\n color: var(--prototype-review-brand, var(--text-primary));\n border-color: var(--prototype-review-brand, var(--border-strong));\n}\n\n.resetButton:focus-visible {\n outline: var(--focus-ring-width, 2px) solid\n var(--focus-ring-color, var(--prototype-review-brand, var(--accent-primary)));\n outline-offset: var(--focus-ring-offset, 2px);\n}\n\n/* ─── Stage ──────────────────────────────────────────────── */\n\n.stage {\n padding: var(--spacing-7);\n max-width: 100%;\n}\n\n.stageMeta {\n display: flex;\n gap: var(--spacing-6);\n align-items: flex-start;\n justify-content: space-between;\n margin-bottom: var(--spacing-5);\n flex-wrap: wrap;\n}\n\n.stageTitleBlock {\n min-width: 0;\n max-width: 56rem;\n}\n\n.stageTitle {\n font-family: var(\n --font-display,\n var(--font-family-display, var(--font-family-heading, inherit))\n );\n font-weight: 500;\n font-size: var(--font-size-2xl);\n letter-spacing: -0.01em;\n line-height: 1.2;\n margin-bottom: var(--spacing-1);\n}\n\n.stageTitle em {\n font-style: normal;\n color: var(--prototype-review-brand, var(--accent-primary));\n}\n\n.stageSummary {\n color: var(--text-secondary);\n font-size: var(--font-size-base);\n line-height: 1.6;\n}\n\n.stageTagRow {\n display: flex;\n gap: var(--spacing-2);\n flex-wrap: wrap;\n}\n\n/* Viewport grid */\n\n.viewportGrid {\n display: grid;\n gap: var(--spacing-6);\n grid-template-columns: 375px 768px 1280px;\n overflow-x: auto;\n padding-bottom: var(--spacing-4);\n}\n\n.viewportGridSolo {\n grid-template-columns: 1fr;\n}\n\n.vpFrame {\n background: var(--surface-card);\n border: var(--stroke-width-thin, 1px) solid var(--border-default);\n border-radius: var(--radius-lg);\n overflow: hidden;\n display: flex;\n flex-direction: column;\n min-width: 0;\n}\n\n.vpFrameHead {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: var(--spacing-2) var(--spacing-3);\n border-bottom: var(--stroke-width-thin, 1px) solid var(--border-muted);\n background: var(--surface-muted, var(--surface-subtle));\n}\n\n.vpFrameName {\n font-family: var(--font-mono, var(--font-family-mono, monospace));\n font-size: var(--font-size-xs);\n letter-spacing: 0.12em;\n text-transform: uppercase;\n color: var(--text-tertiary);\n}\n\n.vpFrameDims {\n font-family: var(--font-mono, var(--font-family-mono, monospace));\n font-size: var(--font-size-xs);\n color: var(--text-disabled, var(--text-tertiary));\n}\n\n.vpIframeWrap {\n background: var(--surface-page);\n}\n\n.vpIframe {\n width: 100%;\n border: none;\n display: block;\n background: var(--surface-page);\n}\n\n/* ─── Landing ────────────────────────────────────────────── */\n\n.landing {\n max-width: 64rem;\n margin: 0 auto;\n padding: var(--spacing-12, 3.5rem) var(--spacing-7);\n}\n\n.landingEyebrow {\n font-family: var(--font-mono, var(--font-family-mono, monospace));\n font-size: var(--font-size-sm);\n letter-spacing: 0.18em;\n text-transform: uppercase;\n color: var(--prototype-review-brand, var(--accent-primary));\n margin-bottom: var(--spacing-4);\n}\n\n.landingTitle {\n font-family: var(\n --font-display,\n var(--font-family-display, var(--font-family-heading, inherit))\n );\n font-weight: 500;\n font-size: clamp(2rem, 4.5vw, 3.25rem);\n line-height: 1.05;\n letter-spacing: -0.02em;\n margin-bottom: var(--spacing-5);\n}\n\n.landingTitle em {\n font-style: normal;\n color: var(--prototype-review-brand, var(--accent-primary));\n}\n\n.landingLede {\n font-size: var(--font-size-lg);\n color: var(--text-secondary);\n line-height: 1.65;\n margin-bottom: var(--spacing-10, 2.5rem);\n max-width: 48rem;\n}\n\n.landingLede code {\n font-family: var(--font-mono, var(--font-family-mono, monospace));\n color: var(--prototype-review-brand, var(--accent-primary));\n font-size: 0.95em;\n}\n\n.protoGrid {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));\n gap: var(--spacing-5);\n margin-bottom: var(--spacing-12, 3rem);\n}\n\n.protoCard {\n background: var(--surface-card);\n border: var(--stroke-width-thin, 1px) solid var(--border-default);\n border-radius: var(--radius-lg);\n padding: var(--spacing-6);\n cursor: pointer;\n text-align: left;\n font-family: inherit;\n color: inherit;\n display: flex;\n flex-direction: column;\n gap: var(--spacing-3);\n transition:\n border-color var(--motion-duration-fast, 150ms)\n var(--motion-easing-standard, ease),\n background var(--motion-duration-fast, 150ms)\n var(--motion-easing-standard, ease);\n}\n\n.protoCard:hover {\n border-color: var(--prototype-review-brand, var(--border-strong));\n background: var(--surface-interactive-hover, var(--surface-subtle));\n}\n\n.protoCard:focus-visible {\n outline: var(--focus-ring-width, 2px) solid\n var(--focus-ring-color, var(--prototype-review-brand, var(--accent-primary)));\n outline-offset: var(--focus-ring-offset, 2px);\n}\n\n.protoCardId {\n font-family: var(--font-mono, var(--font-family-mono, monospace));\n font-size: var(--font-size-xs);\n letter-spacing: 0.18em;\n text-transform: uppercase;\n color: var(--prototype-review-brand, var(--accent-primary));\n}\n\n.protoCardTitle {\n font-family: var(\n --font-display,\n var(--font-family-display, var(--font-family-heading, inherit))\n );\n font-weight: 500;\n font-size: var(--font-size-xl, 1.25rem);\n letter-spacing: -0.01em;\n}\n\n.protoCardDesc {\n color: var(--text-secondary);\n font-size: var(--font-size-sm);\n line-height: 1.55;\n}\n\n.protoCardMeta {\n margin-top: auto;\n font-family: var(--font-mono, var(--font-family-mono, monospace));\n font-size: var(--font-size-xs);\n color: var(--text-tertiary);\n letter-spacing: 0.05em;\n text-transform: uppercase;\n}\n\n.ctxGrid {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(14rem, 1fr));\n gap: var(--spacing-5);\n margin-top: var(--spacing-10, 2.5rem);\n padding-top: var(--spacing-8);\n border-top: var(--stroke-width-thin, 1px) solid var(--border-muted);\n}\n\n.ctxCard h4 {\n font-family: var(--font-mono, var(--font-family-mono, monospace));\n font-size: var(--font-size-sm);\n text-transform: uppercase;\n letter-spacing: 0.12em;\n color: var(--prototype-review-brand, var(--accent-primary));\n margin-bottom: var(--spacing-2);\n}\n\n.ctxCard p {\n color: var(--text-secondary);\n font-size: var(--font-size-sm);\n line-height: 1.6;\n}\n\n/* ─── Footer ─────────────────────────────────────────────── */\n\n.foot {\n border-top: var(--stroke-width-thin, 1px) solid var(--border-muted);\n padding: var(--spacing-6) var(--spacing-7);\n display: flex;\n justify-content: space-between;\n gap: var(--spacing-4);\n flex-wrap: wrap;\n font-family: var(--font-mono, var(--font-family-mono, monospace));\n font-size: var(--font-size-xs);\n color: var(--text-tertiary);\n letter-spacing: 0.06em;\n text-transform: uppercase;\n margin-top: auto;\n}\n"
4213
+ "content": "/* ============================================================\n Prototype Review block\n Theme-agnostic. All colors come from Visor semantic tokens.\n The brand color is injected by the React block as\n --prototype-review-brand (per-instance override).\n ============================================================ */\n\n.root {\n display: flex;\n flex-direction: column;\n width: 100%;\n min-height: 100vh;\n background: var(--surface-page);\n color: var(--text-primary);\n font-family: var(\n --font-body,\n var(--font-family-body, ui-sans-serif, system-ui, sans-serif)\n );\n font-weight: 300;\n line-height: 1.5;\n -webkit-font-smoothing: antialiased;\n container-type: inline-size;\n}\n\n/* ─── Header ─────────────────────────────────────────────── */\n\n.chrome {\n position: sticky;\n top: 0;\n z-index: 100;\n background: var(--surface-card);\n border-bottom: var(--stroke-width-thin, 1px) solid var(--border-muted);\n}\n\n.chromeRow {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: var(--spacing-6);\n padding: var(--spacing-3) var(--spacing-7);\n flex-wrap: wrap;\n}\n\n.brand {\n display: flex;\n align-items: center;\n gap: var(--spacing-3);\n min-width: 0;\n}\n\n.brandMark {\n width: 1.75rem;\n height: 1.75rem;\n background: var(--prototype-review-brand, var(--interactive-primary-bg));\n display: grid;\n place-items: center;\n color: var(--prototype-review-brand-on, var(--interactive-primary-text));\n font-family: var(\n --font-display,\n var(--font-family-display, var(--font-family-heading, inherit))\n );\n font-weight: 700;\n font-size: var(--font-size-xs);\n letter-spacing: -0.02em;\n}\n\n.brandText {\n display: flex;\n flex-direction: column;\n line-height: 1.15;\n}\n\n.brandName {\n font-family: var(\n --font-display,\n var(--font-family-display, var(--font-family-heading, inherit))\n );\n font-weight: 600;\n font-size: var(--font-size-sm);\n letter-spacing: 0.12em;\n text-transform: uppercase;\n}\n\n.brandSub {\n font-family: var(--font-mono, var(--font-family-mono, monospace));\n font-size: var(--font-size-xs);\n color: var(--text-tertiary);\n letter-spacing: 0.05em;\n}\n\n.chromeActions {\n display: flex;\n gap: var(--spacing-2);\n align-items: center;\n flex-wrap: wrap;\n}\n\n.pill {\n font-family: var(--font-mono, var(--font-family-mono, monospace));\n font-size: var(--font-size-xs);\n text-transform: uppercase;\n letter-spacing: 0.12em;\n padding: var(--spacing-1) var(--spacing-2);\n border: var(--stroke-width-thin, 1px) solid var(--border-default);\n color: var(--text-tertiary);\n border-radius: var(--radius-full, 9999px);\n}\n\n.pillBrand {\n background: var(--prototype-review-brand-soft, var(--surface-subtle));\n border-color: var(--prototype-review-brand, var(--border-default));\n color: var(--prototype-review-brand, var(--text-primary));\n}\n\n/* ─── Controls ───────────────────────────────────────────── */\n\n.controls {\n border-bottom: var(--stroke-width-thin, 1px) solid var(--border-muted);\n background: var(--surface-muted, var(--surface-subtle));\n}\n\n.controlsRow {\n display: grid;\n grid-template-columns: minmax(0, 1fr) auto auto;\n gap: var(--spacing-6);\n align-items: center;\n padding: var(--spacing-3) var(--spacing-7);\n}\n\n@container (max-width: 64rem) {\n .controlsRow {\n grid-template-columns: 1fr;\n }\n}\n\n.controlGroup {\n display: flex;\n align-items: center;\n gap: var(--spacing-4);\n flex-wrap: wrap;\n}\n\n.controlLabel {\n font-family: var(--font-mono, var(--font-family-mono, monospace));\n font-size: var(--font-size-xs);\n letter-spacing: 0.12em;\n text-transform: uppercase;\n color: var(--text-tertiary);\n}\n\n/* Tabs */\n\n.tabs {\n display: flex;\n gap: 0;\n flex-wrap: wrap;\n align-items: stretch;\n border: var(--stroke-width-thin, 1px) solid var(--border-default);\n background: var(--surface-page);\n width: fit-content;\n border-radius: var(--radius-full, 9999px);\n overflow: hidden;\n}\n\n.tab {\n background: transparent;\n border: none;\n color: var(--text-tertiary);\n font-family: var(--font-mono, var(--font-family-mono, monospace));\n font-size: var(--font-size-xs);\n letter-spacing: 0.08em;\n text-transform: uppercase;\n padding: var(--spacing-2) var(--spacing-4);\n cursor: pointer;\n transition:\n color var(--motion-duration-fast, 150ms)\n var(--motion-easing-standard, ease),\n background var(--motion-duration-fast, 150ms)\n var(--motion-easing-standard, ease);\n}\n\n.tab:hover {\n color: var(--text-primary);\n}\n\n.tab[aria-selected=\"true\"] {\n background: var(--prototype-review-brand, var(--interactive-primary-bg));\n color: var(--prototype-review-brand-on, var(--interactive-primary-text));\n}\n\n.tab:focus-visible {\n outline: var(--focus-ring-width, 2px) solid\n var(--focus-ring-color, var(--prototype-review-brand, var(--primary)));\n outline-offset: calc(var(--focus-ring-offset, 2px) * -1);\n}\n\n.tabId {\n font-family: var(\n --font-display,\n var(--font-family-display, var(--font-family-heading, inherit))\n );\n font-weight: 600;\n letter-spacing: 0.02em;\n text-transform: none;\n font-size: var(--font-size-sm);\n margin-right: var(--spacing-2);\n}\n\n/* Theme select */\n\n.themeGroup {\n display: flex;\n align-items: center;\n gap: var(--spacing-2);\n}\n\n.themeSelect {\n background: var(--surface-page);\n border: var(--stroke-width-thin, 1px) solid var(--border-default);\n color: var(--text-primary);\n font-family: var(--font-mono, var(--font-family-mono, monospace));\n font-size: var(--font-size-xs);\n padding: var(--spacing-2) var(--spacing-3);\n border-radius: var(--radius-full, 9999px);\n cursor: pointer;\n letter-spacing: 0.05em;\n text-transform: uppercase;\n}\n\n.themeSelect:focus-visible {\n outline: var(--focus-ring-width, 2px) solid\n var(--focus-ring-color, var(--prototype-review-brand, var(--primary)));\n outline-offset: var(--focus-ring-offset, 2px);\n}\n\n/* Mode + viewport toggle buttons */\n\n.modeGroup,\n.vpGroup {\n display: flex;\n align-items: center;\n gap: var(--spacing-2);\n}\n\n.toggleButtons {\n display: flex;\n border: var(--stroke-width-thin, 1px) solid var(--border-default);\n background: var(--surface-page);\n border-radius: var(--radius-full, 9999px);\n overflow: hidden;\n}\n\n.toggleButton {\n background: transparent;\n border: none;\n color: var(--text-tertiary);\n font-family: var(--font-mono, var(--font-family-mono, monospace));\n font-size: var(--font-size-xs);\n letter-spacing: 0.05em;\n padding: var(--spacing-2) var(--spacing-3);\n cursor: pointer;\n text-transform: uppercase;\n transition:\n color var(--motion-duration-fast, 150ms)\n var(--motion-easing-standard, ease),\n background var(--motion-duration-fast, 150ms)\n var(--motion-easing-standard, ease);\n}\n\n.toggleButton:hover {\n color: var(--text-primary);\n}\n\n.toggleButton[aria-pressed=\"true\"] {\n background: var(--prototype-review-brand, var(--interactive-primary-bg));\n color: var(--prototype-review-brand-on, var(--interactive-primary-text));\n}\n\n.toggleButton:focus-visible {\n outline: var(--focus-ring-width, 2px) solid\n var(--focus-ring-color, var(--prototype-review-brand, var(--primary)));\n outline-offset: calc(var(--focus-ring-offset, 2px) * -1);\n}\n\n/* Brand picker */\n\n.picker {\n display: flex;\n align-items: center;\n gap: var(--spacing-3);\n flex-wrap: wrap;\n}\n\n.swatches {\n display: flex;\n gap: var(--spacing-1);\n align-items: center;\n}\n\n.swatch {\n width: 1.375rem;\n height: 1.375rem;\n border-radius: var(--radius-full, 9999px);\n border: var(--stroke-width-medium, 2px) solid transparent;\n cursor: pointer;\n padding: 0;\n transition:\n transform var(--motion-duration-fast, 150ms)\n var(--motion-easing-standard, ease),\n border-color var(--motion-duration-fast, 150ms)\n var(--motion-easing-standard, ease);\n}\n\n.swatch:hover {\n transform: scale(1.12);\n}\n\n.swatch[data-active=\"true\"] {\n border-color: var(--text-primary);\n box-shadow: 0 0 0 var(--stroke-width-medium, 2px) var(--surface-page);\n}\n\n.swatch:focus-visible {\n outline: var(--focus-ring-width, 2px) solid\n var(--focus-ring-color, var(--prototype-review-brand, var(--primary)));\n outline-offset: var(--focus-ring-offset, 2px);\n}\n\n.hexInput {\n background: var(--surface-page);\n border: var(--stroke-width-thin, 1px) solid var(--border-default);\n color: var(--text-primary);\n font-family: var(--font-mono, var(--font-family-mono, monospace));\n font-size: var(--font-size-xs);\n padding: var(--spacing-1) var(--spacing-3);\n width: 8.5rem;\n letter-spacing: 0.05em;\n text-transform: uppercase;\n border-radius: var(--radius-full, 9999px);\n}\n\n.hexInput:focus {\n outline: none;\n border-color: var(--prototype-review-brand, var(--border-default));\n}\n\n.hexInput:focus-visible {\n outline: var(--focus-ring-width, 2px) solid\n var(--focus-ring-color, var(--prototype-review-brand, var(--primary)));\n outline-offset: var(--focus-ring-offset, 2px);\n}\n\n.resetButton {\n background: transparent;\n border: var(--stroke-width-thin, 1px) solid var(--border-default);\n color: var(--text-tertiary);\n font-family: var(--font-mono, var(--font-family-mono, monospace));\n font-size: var(--font-size-xs);\n letter-spacing: 0.1em;\n text-transform: uppercase;\n padding: var(--spacing-1) var(--spacing-3);\n border-radius: var(--radius-full, 9999px);\n cursor: pointer;\n transition:\n color var(--motion-duration-fast, 150ms)\n var(--motion-easing-standard, ease),\n border-color var(--motion-duration-fast, 150ms)\n var(--motion-easing-standard, ease);\n}\n\n.resetButton:hover {\n color: var(--prototype-review-brand, var(--text-primary));\n border-color: var(--prototype-review-brand, var(--border-strong));\n}\n\n.resetButton:focus-visible {\n outline: var(--focus-ring-width, 2px) solid\n var(--focus-ring-color, var(--prototype-review-brand, var(--primary)));\n outline-offset: var(--focus-ring-offset, 2px);\n}\n\n/* ─── Stage ──────────────────────────────────────────────── */\n\n.stage {\n padding: var(--spacing-7);\n max-width: 100%;\n}\n\n.stageMeta {\n display: flex;\n gap: var(--spacing-6);\n align-items: flex-start;\n justify-content: space-between;\n margin-bottom: var(--spacing-5);\n flex-wrap: wrap;\n}\n\n.stageTitleBlock {\n min-width: 0;\n max-width: 56rem;\n}\n\n.stageTitle {\n font-family: var(\n --font-display,\n var(--font-family-display, var(--font-family-heading, inherit))\n );\n font-weight: 500;\n font-size: var(--font-size-2xl);\n letter-spacing: -0.01em;\n line-height: 1.2;\n margin-bottom: var(--spacing-1);\n}\n\n.stageTitle em {\n font-style: normal;\n color: var(--prototype-review-brand, var(--primary));\n}\n\n.stageSummary {\n color: var(--text-secondary);\n font-size: var(--font-size-base);\n line-height: 1.6;\n}\n\n.stageTagRow {\n display: flex;\n gap: var(--spacing-2);\n flex-wrap: wrap;\n}\n\n/* Viewport grid */\n\n.viewportGrid {\n display: grid;\n gap: var(--spacing-6);\n grid-template-columns: 375px 768px 1280px;\n overflow-x: auto;\n padding-bottom: var(--spacing-4);\n}\n\n.viewportGridSolo {\n grid-template-columns: 1fr;\n}\n\n.vpFrame {\n background: var(--surface-card);\n border: var(--stroke-width-thin, 1px) solid var(--border-default);\n border-radius: var(--radius-lg);\n overflow: hidden;\n display: flex;\n flex-direction: column;\n min-width: 0;\n}\n\n.vpFrameHead {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: var(--spacing-2) var(--spacing-3);\n border-bottom: var(--stroke-width-thin, 1px) solid var(--border-muted);\n background: var(--surface-muted, var(--surface-subtle));\n}\n\n.vpFrameName {\n font-family: var(--font-mono, var(--font-family-mono, monospace));\n font-size: var(--font-size-xs);\n letter-spacing: 0.12em;\n text-transform: uppercase;\n color: var(--text-tertiary);\n}\n\n.vpFrameDims {\n font-family: var(--font-mono, var(--font-family-mono, monospace));\n font-size: var(--font-size-xs);\n color: var(--text-disabled, var(--text-tertiary));\n}\n\n.vpIframeWrap {\n background: var(--surface-page);\n}\n\n.vpIframe {\n width: 100%;\n border: none;\n display: block;\n background: var(--surface-page);\n}\n\n/* ─── Landing ────────────────────────────────────────────── */\n\n.landing {\n max-width: 64rem;\n margin: 0 auto;\n padding: var(--spacing-12, 3.5rem) var(--spacing-7);\n}\n\n.landingEyebrow {\n font-family: var(--font-mono, var(--font-family-mono, monospace));\n font-size: var(--font-size-sm);\n letter-spacing: 0.18em;\n text-transform: uppercase;\n color: var(--prototype-review-brand, var(--primary));\n margin-bottom: var(--spacing-4);\n}\n\n.landingTitle {\n font-family: var(\n --font-display,\n var(--font-family-display, var(--font-family-heading, inherit))\n );\n font-weight: 500;\n font-size: clamp(2rem, 4.5vw, 3.25rem);\n line-height: 1.05;\n letter-spacing: -0.02em;\n margin-bottom: var(--spacing-5);\n}\n\n.landingTitle em {\n font-style: normal;\n color: var(--prototype-review-brand, var(--primary));\n}\n\n.landingLede {\n font-size: var(--font-size-lg);\n color: var(--text-secondary);\n line-height: 1.65;\n margin-bottom: var(--spacing-10, 2.5rem);\n max-width: 48rem;\n}\n\n.landingLede code {\n font-family: var(--font-mono, var(--font-family-mono, monospace));\n color: var(--prototype-review-brand, var(--primary));\n font-size: 0.95em;\n}\n\n.protoGrid {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));\n gap: var(--spacing-5);\n margin-bottom: var(--spacing-12, 3rem);\n}\n\n.protoCard {\n background: var(--surface-card);\n border: var(--stroke-width-thin, 1px) solid var(--border-default);\n border-radius: var(--radius-lg);\n padding: var(--spacing-6);\n cursor: pointer;\n text-align: left;\n font-family: inherit;\n color: inherit;\n display: flex;\n flex-direction: column;\n gap: var(--spacing-3);\n transition:\n border-color var(--motion-duration-fast, 150ms)\n var(--motion-easing-standard, ease),\n background var(--motion-duration-fast, 150ms)\n var(--motion-easing-standard, ease);\n}\n\n.protoCard:hover {\n border-color: var(--prototype-review-brand, var(--border-strong));\n background: var(--surface-interactive-hover, var(--surface-subtle));\n}\n\n.protoCard:focus-visible {\n outline: var(--focus-ring-width, 2px) solid\n var(--focus-ring-color, var(--prototype-review-brand, var(--primary)));\n outline-offset: var(--focus-ring-offset, 2px);\n}\n\n.protoCardId {\n font-family: var(--font-mono, var(--font-family-mono, monospace));\n font-size: var(--font-size-xs);\n letter-spacing: 0.18em;\n text-transform: uppercase;\n color: var(--prototype-review-brand, var(--primary));\n}\n\n.protoCardTitle {\n font-family: var(\n --font-display,\n var(--font-family-display, var(--font-family-heading, inherit))\n );\n font-weight: 500;\n font-size: var(--font-size-xl, 1.25rem);\n letter-spacing: -0.01em;\n}\n\n.protoCardDesc {\n color: var(--text-secondary);\n font-size: var(--font-size-sm);\n line-height: 1.55;\n}\n\n.protoCardMeta {\n margin-top: auto;\n font-family: var(--font-mono, var(--font-family-mono, monospace));\n font-size: var(--font-size-xs);\n color: var(--text-tertiary);\n letter-spacing: 0.05em;\n text-transform: uppercase;\n}\n\n.ctxGrid {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(14rem, 1fr));\n gap: var(--spacing-5);\n margin-top: var(--spacing-10, 2.5rem);\n padding-top: var(--spacing-8);\n border-top: var(--stroke-width-thin, 1px) solid var(--border-muted);\n}\n\n.ctxCard h4 {\n font-family: var(--font-mono, var(--font-family-mono, monospace));\n font-size: var(--font-size-sm);\n text-transform: uppercase;\n letter-spacing: 0.12em;\n color: var(--prototype-review-brand, var(--primary));\n margin-bottom: var(--spacing-2);\n}\n\n.ctxCard p {\n color: var(--text-secondary);\n font-size: var(--font-size-sm);\n line-height: 1.6;\n}\n\n/* ─── Footer ─────────────────────────────────────────────── */\n\n.foot {\n border-top: var(--stroke-width-thin, 1px) solid var(--border-muted);\n padding: var(--spacing-6) var(--spacing-7);\n display: flex;\n justify-content: space-between;\n gap: var(--spacing-4);\n flex-wrap: wrap;\n font-family: var(--font-mono, var(--font-family-mono, monospace));\n font-size: var(--font-size-xs);\n color: var(--text-tertiary);\n letter-spacing: 0.06em;\n text-transform: uppercase;\n margin-top: auto;\n}\n"
4207
4214
  }
4208
4215
  ]
4209
4216
  },
@@ -4284,7 +4291,7 @@
4284
4291
  {
4285
4292
  "path": "components/devtools/source-inspector/visor-component-names.generated.ts",
4286
4293
  "type": "registry:devtool",
4287
- "content": "// THIS FILE IS GENERATED BY scripts/generate-visor-component-names.ts.\n// Do not edit by hand. Re-run `npm run generate:component-names` after\n// adding, removing, or renaming a Visor component.\n//\n// Source of truth: registry/registry-{ui,blocks,deck,visual,devtools}.ts\n// Used by: components/devtools/source-inspector/* (VI-311)\n\nexport const VISOR_COMPONENT_NAMES: ReadonlySet<string> = new Set([\n \"AccessibilitySection\",\n \"AccessibilitySlide\",\n \"AccessibilitySpecimen\",\n \"Accordion\",\n \"AccordionContent\",\n \"AccordionItem\",\n \"AccordionTrigger\",\n \"ActivityFeed\",\n \"ActivityFeedContext\",\n \"ActivityFeedItem\",\n \"ActivityFeedRoot\",\n \"AdminDashboard\",\n \"AdminDetailDrawer\",\n \"AdminListPage\",\n \"AdminListPageInner\",\n \"AdminSettingsPage\",\n \"AdminShell\",\n \"AdminTabbedEditor\",\n \"AdminWizard\",\n \"Alert\",\n \"AlertDescription\",\n \"AlertTitle\",\n \"Avatar\",\n \"AvatarFallback\",\n \"AvatarImage\",\n \"AvatarStack\",\n \"Badge\",\n \"Banner\",\n \"BannerAction\",\n \"BannerDescription\",\n \"BannerTitle\",\n \"BentoGrid\",\n \"BentoTile\",\n \"BentoTileBody\",\n \"BentoTileDescription\",\n \"BentoTileFigure\",\n \"BentoTileHeadline\",\n \"BentoTileMedia\",\n \"BentoTileMeta\",\n \"BentoTileTitle\",\n \"Box\",\n \"Breadcrumb\",\n \"BreadcrumbEllipsis\",\n \"BreadcrumbItem\",\n \"BreadcrumbLink\",\n \"BreadcrumbList\",\n \"BreadcrumbPage\",\n \"BreadcrumbSeparator\",\n \"BulkActionBar\",\n \"Button\",\n \"ButtonSpecimenSection\",\n \"ButtonSpecimenSlide\",\n \"Calendar\",\n \"Card\",\n \"CardContent\",\n \"CardDescription\",\n \"CardFooter\",\n \"CardGrid\",\n \"CardHeader\",\n \"CardTitle\",\n \"Carousel\",\n \"CarouselContent\",\n \"CarouselContext\",\n \"CarouselGallery\",\n \"CarouselItem\",\n \"CarouselNext\",\n \"CarouselPrevious\",\n \"ChartContainer\",\n \"ChartContext\",\n \"ChartLegend\",\n \"ChartLegendContent\",\n \"ChartStyle\",\n \"ChartTooltip\",\n \"ChartTooltipContent\",\n \"Checkbox\",\n \"Chip\",\n \"ChipGroup\",\n \"ChipGroupContext\",\n \"ChipGroupItem\",\n \"ChoiceChip\",\n \"ChromeButton\",\n \"ClosingSlide\",\n \"CodeBlock\",\n \"Collapsible\",\n \"CollapsibleContent\",\n \"CollapsibleTrigger\",\n \"ColorBar\",\n \"ColorPaletteSection\",\n \"ColorPicker\",\n \"ColorPickerSurface\",\n \"ColorSwatch\",\n \"ColorSwatchGrid\",\n \"Combobox\",\n \"ComboboxContent\",\n \"ComboboxContext\",\n \"ComboboxEmpty\",\n \"ComboboxGroup\",\n \"ComboboxInput\",\n \"ComboboxItem\",\n \"ComboboxSeparator\",\n \"Command\",\n \"CommandDialog\",\n \"CommandEmpty\",\n \"CommandGroup\",\n \"CommandInput\",\n \"CommandItem\",\n \"CommandList\",\n \"CommandLoading\",\n \"CommandSeparator\",\n \"CommandShortcut\",\n \"ComponentShowcaseContent\",\n \"ComponentShowcaseSection\",\n \"ComponentShowcaseSlide\",\n \"ConceptSlide\",\n \"ConfigurationPanel\",\n \"ConfirmDialog\",\n \"Container\",\n \"ContextMenu\",\n \"ContextMenuCheckboxItem\",\n \"ContextMenuContent\",\n \"ContextMenuGroup\",\n \"ContextMenuItem\",\n \"ContextMenuLabel\",\n \"ContextMenuPortal\",\n \"ContextMenuRadioGroup\",\n \"ContextMenuRadioItem\",\n \"ContextMenuSeparator\",\n \"ContextMenuShortcut\",\n \"ContextMenuSub\",\n \"ContextMenuSubContent\",\n \"ContextMenuSubTrigger\",\n \"ContextMenuTrigger\",\n \"Controls\",\n \"CtaSection\",\n \"DataTable\",\n \"DataTableInner\",\n \"DatePicker\",\n \"DateRangePicker\",\n \"DeckContext\",\n \"DeckFooter\",\n \"DeckLayout\",\n \"DeckProvider\",\n \"DeckRenderer\",\n \"DesignSystemDeck\",\n \"DesignSystemSpecimen\",\n \"Dialog\",\n \"DialogClose\",\n \"DialogContent\",\n \"DialogDescription\",\n \"DialogHeader\",\n \"DialogOverlay\",\n \"DialogPortal\",\n \"DialogTitle\",\n \"DialogTrigger\",\n \"DotNav\",\n \"DropdownMenu\",\n \"DropdownMenuCheckboxItem\",\n \"DropdownMenuContent\",\n \"DropdownMenuGroup\",\n \"DropdownMenuItem\",\n \"DropdownMenuLabel\",\n \"DropdownMenuPortal\",\n \"DropdownMenuRadioGroup\",\n \"DropdownMenuRadioItem\",\n \"DropdownMenuSeparator\",\n \"DropdownMenuShortcut\",\n \"DropdownMenuSub\",\n \"DropdownMenuSubContent\",\n \"DropdownMenuSubTrigger\",\n \"DropdownMenuTrigger\",\n \"ElevationCard\",\n \"ElevationSlide\",\n \"EmptyState\",\n \"ExportMenu\",\n \"FeaturesGrid\",\n \"Field\",\n \"FieldDescription\",\n \"FieldError\",\n \"FieldLabel\",\n \"Fieldset\",\n \"FieldsetLegend\",\n \"FileUpload\",\n \"FilterBar\",\n \"FilterChip\",\n \"FontShowcase\",\n \"FontShowcaseGrid\",\n \"Footer\",\n \"FooterSection\",\n \"Form\",\n \"FormField\",\n \"FormSpecimenSection\",\n \"FormSpecimenSlide\",\n \"FullscreenOverlay\",\n \"FullscreenOverlayContent\",\n \"FullscreenOverlayTrigger\",\n \"Grid\",\n \"Header\",\n \"Heading\",\n \"HeroSection\",\n \"HeroSlide\",\n \"HoverCard\",\n \"HoverCardContent\",\n \"HoverCardTrigger\",\n \"IconGrid\",\n \"IconGridSection\",\n \"IconSizeRow\",\n \"IconsSlide\",\n \"Image\",\n \"Inline\",\n \"Input\",\n \"Kbd\",\n \"Label\",\n \"Landing\",\n \"Lightbox\",\n \"LightboxContent\",\n \"LightboxContext\",\n \"LightboxTrigger\",\n \"LoginForm\",\n \"Marquee\",\n \"MarqueeBandRenderer\",\n \"Menubar\",\n \"MenubarCheckboxItem\",\n \"MenubarContent\",\n \"MenubarGroup\",\n \"MenubarItem\",\n \"MenubarLabel\",\n \"MenubarMenu\",\n \"MenubarRadioGroup\",\n \"MenubarRadioItem\",\n \"MenubarSeparator\",\n \"MenubarShortcut\",\n \"MenubarSub\",\n \"MenubarSubContent\",\n \"MenubarSubTrigger\",\n \"MenubarTrigger\",\n \"MotionDuration\",\n \"MotionDurationSection\",\n \"MotionEasing\",\n \"MotionEasingSection\",\n \"MotionSlide\",\n \"NameRoster\",\n \"NameRosterItem\",\n \"Navbar\",\n \"NavbarBrand\",\n \"NavbarContent\",\n \"NavbarItem\",\n \"NavbarLink\",\n \"NavbarToggle\",\n \"NumberInput\",\n \"OpacityBar\",\n \"OpacitySlide\",\n \"OTPInput\",\n \"PageHeader\",\n \"Pagination\",\n \"PaginationContent\",\n \"PaginationEllipsis\",\n \"PaginationItem\",\n \"PaginationLink\",\n \"PaginationNext\",\n \"PaginationPrevious\",\n \"PasswordInput\",\n \"PhoneInput\",\n \"Popover\",\n \"PopoverAnchor\",\n \"PopoverContent\",\n \"PopoverTrigger\",\n \"PricingSection\",\n \"ProfileMenu\",\n \"Progress\",\n \"PrototypeReview\",\n \"QuickActions\",\n \"RadioGroup\",\n \"RadioGroupItem\",\n \"RadiusScale\",\n \"RadiusSection\",\n \"RadiusSlide\",\n \"RightRailList\",\n \"ScoreIndicator\",\n \"ScrollArea\",\n \"ScrollBar\",\n \"SearchInput\",\n \"SectionHeader\",\n \"Select\",\n \"SelectContent\",\n \"SelectGroup\",\n \"SelectItem\",\n \"SelectLabel\",\n \"SelectScrollDownButton\",\n \"SelectScrollUpButton\",\n \"SelectSeparator\",\n \"SelectTrigger\",\n \"SelectValue\",\n \"SemanticColorGrid\",\n \"SemanticColorItem\",\n \"SemanticTokensSlide\",\n \"Separator\",\n \"ShadowSection\",\n \"Sheet\",\n \"SheetClose\",\n \"SheetContent\",\n \"SheetDescription\",\n \"SheetFooter\",\n \"SheetHeader\",\n \"SheetOverlay\",\n \"SheetPortal\",\n \"SheetTitle\",\n \"SheetTrigger\",\n \"Sidebar\",\n \"SidebarContent\",\n \"SidebarContext\",\n \"SidebarFooter\",\n \"SidebarGroup\",\n \"SidebarGroupAction\",\n \"SidebarGroupContent\",\n \"SidebarGroupLabel\",\n \"SidebarHeader\",\n \"SidebarInset\",\n \"SidebarMenu\",\n \"SidebarMenuAction\",\n \"SidebarMenuBadge\",\n \"SidebarMenuButton\",\n \"SidebarMenuItem\",\n \"SidebarMenuSub\",\n \"SidebarMenuSubButton\",\n \"SidebarMenuSubItem\",\n \"SidebarProvider\",\n \"SidebarRail\",\n \"SidebarSeparator\",\n \"SidebarTrigger\",\n \"Skeleton\",\n \"Slide\",\n \"SlideHeader\",\n \"Slider\",\n \"SliderControl\",\n \"SlideThemeContext\",\n \"SlideThemeProvider\",\n \"SourceInspector\",\n \"SourceInspectorContext\",\n \"SourceInspectorDevImpl\",\n \"SourceInspectorProvider\",\n \"SourceInspectorRunner\",\n \"SourceInspectorToggle\",\n \"SpacingScale\",\n \"SpacingSection\",\n \"SpacingSlide\",\n \"Sparkline\",\n \"Sphere\",\n \"SpherePlayground\",\n \"Stack\",\n \"Stage\",\n \"StatCard\",\n \"StatHero\",\n \"StationSpectrum\",\n \"StatusBadge\",\n \"StatusColorsSlide\",\n \"StatusDot\",\n \"Stepper\",\n \"StepperContext\",\n \"StepperDescription\",\n \"StepperItem\",\n \"StepperSeparator\",\n \"StepperTitle\",\n \"StepperTrigger\",\n \"StepsSection\",\n \"SurfaceRow\",\n \"SurfaceSection\",\n \"Switch\",\n \"Table\",\n \"TableBody\",\n \"TableCaption\",\n \"TableCell\",\n \"TableFooter\",\n \"TableHead\",\n \"TableHeader\",\n \"TableRow\",\n \"Tabs\",\n \"TabsContent\",\n \"TabsList\",\n \"TabsTrigger\",\n \"TagInput\",\n \"TestimonialAttribution\",\n \"TestimonialSection\",\n \"Text\",\n \"Textarea\",\n \"ThemeArchitectureSlide\",\n \"ThemeColorsSlide\",\n \"ThemeSwitcher\",\n \"Timeline\",\n \"TimelineContent\",\n \"TimelineDescription\",\n \"TimelineIcon\",\n \"TimelineItem\",\n \"TimelineTimestamp\",\n \"TimelineTitle\",\n \"TitleSlide\",\n \"Toaster\",\n \"TOCSlide\",\n \"ToggleButton\",\n \"ToggleDevImpl\",\n \"ToggleGroup\",\n \"ToggleGroupContext\",\n \"ToggleGroupItem\",\n \"Tooltip\",\n \"TooltipContent\",\n \"TooltipProvider\",\n \"TooltipTrigger\",\n \"TypeBodySlide\",\n \"TypeDisplaySlide\",\n \"TypeSpecimen\",\n \"TypographySection\",\n \"WorkspaceSwitcher\",\n])\n"
4294
+ "content": "// THIS FILE IS GENERATED BY scripts/generate-visor-component-names.ts.\n// Do not edit by hand. Re-run `npm run generate:component-names` after\n// adding, removing, or renaming a Visor component.\n//\n// Source of truth: registry/registry-{ui,blocks,deck,visual,devtools}.ts\n// Used by: components/devtools/source-inspector/* (VI-311)\n\nexport const VISOR_COMPONENT_NAMES: ReadonlySet<string> = new Set([\n \"AccessibilitySection\",\n \"AccessibilitySlide\",\n \"AccessibilitySpecimen\",\n \"Accordion\",\n \"AccordionContent\",\n \"AccordionItem\",\n \"AccordionTrigger\",\n \"ActivityFeed\",\n \"ActivityFeedContext\",\n \"ActivityFeedItem\",\n \"ActivityFeedRoot\",\n \"AdminDashboard\",\n \"AdminDetailDrawer\",\n \"AdminListPage\",\n \"AdminListPageInner\",\n \"AdminSettingsPage\",\n \"AdminShell\",\n \"AdminTabbedEditor\",\n \"AdminWizard\",\n \"Alert\",\n \"AlertActions\",\n \"AlertDescription\",\n \"AlertTitle\",\n \"Avatar\",\n \"AvatarFallback\",\n \"AvatarImage\",\n \"AvatarStack\",\n \"Badge\",\n \"Banner\",\n \"BannerAction\",\n \"BannerDescription\",\n \"BannerTitle\",\n \"BentoGrid\",\n \"BentoTile\",\n \"BentoTileBody\",\n \"BentoTileDescription\",\n \"BentoTileFigure\",\n \"BentoTileHeadline\",\n \"BentoTileMedia\",\n \"BentoTileMeta\",\n \"BentoTileTitle\",\n \"Box\",\n \"Breadcrumb\",\n \"BreadcrumbEllipsis\",\n \"BreadcrumbItem\",\n \"BreadcrumbLink\",\n \"BreadcrumbList\",\n \"BreadcrumbPage\",\n \"BreadcrumbSeparator\",\n \"BulkActionBar\",\n \"Button\",\n \"ButtonSpecimenSection\",\n \"ButtonSpecimenSlide\",\n \"Calendar\",\n \"Card\",\n \"CardContent\",\n \"CardDescription\",\n \"CardFooter\",\n \"CardGrid\",\n \"CardHeader\",\n \"CardTitle\",\n \"Carousel\",\n \"CarouselContent\",\n \"CarouselContext\",\n \"CarouselGallery\",\n \"CarouselItem\",\n \"CarouselNext\",\n \"CarouselPrevious\",\n \"ChartContainer\",\n \"ChartContext\",\n \"ChartLegend\",\n \"ChartLegendContent\",\n \"ChartStyle\",\n \"ChartTooltip\",\n \"ChartTooltipContent\",\n \"Checkbox\",\n \"Chip\",\n \"ChipGroup\",\n \"ChipGroupContext\",\n \"ChipGroupItem\",\n \"ChoiceChip\",\n \"ChromeButton\",\n \"ClosingSlide\",\n \"CodeBlock\",\n \"Collapsible\",\n \"CollapsibleContent\",\n \"CollapsibleTrigger\",\n \"ColorBar\",\n \"ColorPaletteSection\",\n \"ColorPicker\",\n \"ColorPickerSurface\",\n \"ColorSwatch\",\n \"ColorSwatchGrid\",\n \"Combobox\",\n \"ComboboxContent\",\n \"ComboboxContext\",\n \"ComboboxEmpty\",\n \"ComboboxGroup\",\n \"ComboboxInput\",\n \"ComboboxItem\",\n \"ComboboxSeparator\",\n \"Command\",\n \"CommandDialog\",\n \"CommandEmpty\",\n \"CommandGroup\",\n \"CommandInput\",\n \"CommandItem\",\n \"CommandList\",\n \"CommandLoading\",\n \"CommandSeparator\",\n \"CommandShortcut\",\n \"ComponentShowcaseContent\",\n \"ComponentShowcaseSection\",\n \"ComponentShowcaseSlide\",\n \"ConceptSlide\",\n \"ConfigurationPanel\",\n \"ConfirmDialog\",\n \"Container\",\n \"ContextMenu\",\n \"ContextMenuCheckboxItem\",\n \"ContextMenuContent\",\n \"ContextMenuGroup\",\n \"ContextMenuItem\",\n \"ContextMenuLabel\",\n \"ContextMenuPortal\",\n \"ContextMenuRadioGroup\",\n \"ContextMenuRadioItem\",\n \"ContextMenuSeparator\",\n \"ContextMenuShortcut\",\n \"ContextMenuSub\",\n \"ContextMenuSubContent\",\n \"ContextMenuSubTrigger\",\n \"ContextMenuTrigger\",\n \"Controls\",\n \"CtaSection\",\n \"DataTable\",\n \"DataTableInner\",\n \"DatePicker\",\n \"DateRangePicker\",\n \"DeckContext\",\n \"DeckFooter\",\n \"DeckLayout\",\n \"DeckProvider\",\n \"DeckRenderer\",\n \"DesignSystemDeck\",\n \"DesignSystemSpecimen\",\n \"Dialog\",\n \"DialogClose\",\n \"DialogContent\",\n \"DialogDescription\",\n \"DialogHeader\",\n \"DialogOverlay\",\n \"DialogPortal\",\n \"DialogTitle\",\n \"DialogTrigger\",\n \"DotNav\",\n \"DropdownMenu\",\n \"DropdownMenuCheckboxItem\",\n \"DropdownMenuContent\",\n \"DropdownMenuGroup\",\n \"DropdownMenuItem\",\n \"DropdownMenuLabel\",\n \"DropdownMenuPortal\",\n \"DropdownMenuRadioGroup\",\n \"DropdownMenuRadioItem\",\n \"DropdownMenuSeparator\",\n \"DropdownMenuShortcut\",\n \"DropdownMenuSub\",\n \"DropdownMenuSubContent\",\n \"DropdownMenuSubTrigger\",\n \"DropdownMenuTrigger\",\n \"ElevationCard\",\n \"ElevationSlide\",\n \"EmptyState\",\n \"ExportMenu\",\n \"FeaturesGrid\",\n \"Field\",\n \"FieldDescription\",\n \"FieldError\",\n \"FieldLabel\",\n \"Fieldset\",\n \"FieldsetLegend\",\n \"FileUpload\",\n \"FilterBar\",\n \"FilterChip\",\n \"FontShowcase\",\n \"FontShowcaseGrid\",\n \"Footer\",\n \"FooterSection\",\n \"Form\",\n \"FormField\",\n \"FormSpecimenSection\",\n \"FormSpecimenSlide\",\n \"FullscreenOverlay\",\n \"FullscreenOverlayContent\",\n \"FullscreenOverlayTrigger\",\n \"Grid\",\n \"Header\",\n \"Heading\",\n \"HeroSection\",\n \"HeroSlide\",\n \"HoverCard\",\n \"HoverCardContent\",\n \"HoverCardTrigger\",\n \"IconGrid\",\n \"IconGridSection\",\n \"IconSizeRow\",\n \"IconsSlide\",\n \"Image\",\n \"Inline\",\n \"Input\",\n \"Kbd\",\n \"KeyValueList\",\n \"Label\",\n \"Landing\",\n \"Lightbox\",\n \"LightboxContent\",\n \"LightboxContext\",\n \"LightboxTrigger\",\n \"LoginForm\",\n \"Marquee\",\n \"MarqueeBandRenderer\",\n \"Menubar\",\n \"MenubarCheckboxItem\",\n \"MenubarContent\",\n \"MenubarGroup\",\n \"MenubarItem\",\n \"MenubarLabel\",\n \"MenubarMenu\",\n \"MenubarRadioGroup\",\n \"MenubarRadioItem\",\n \"MenubarSeparator\",\n \"MenubarShortcut\",\n \"MenubarSub\",\n \"MenubarSubContent\",\n \"MenubarSubTrigger\",\n \"MenubarTrigger\",\n \"MotionDuration\",\n \"MotionDurationSection\",\n \"MotionEasing\",\n \"MotionEasingSection\",\n \"MotionSlide\",\n \"NameRoster\",\n \"NameRosterItem\",\n \"Navbar\",\n \"NavbarBrand\",\n \"NavbarContent\",\n \"NavbarItem\",\n \"NavbarLink\",\n \"NavbarToggle\",\n \"NumberInput\",\n \"OpacityBar\",\n \"OpacitySlide\",\n \"OTPInput\",\n \"PageHeader\",\n \"Pagination\",\n \"PaginationContent\",\n \"PaginationEllipsis\",\n \"PaginationItem\",\n \"PaginationLink\",\n \"PaginationNext\",\n \"PaginationPrevious\",\n \"PasswordInput\",\n \"PhoneInput\",\n \"Popover\",\n \"PopoverAnchor\",\n \"PopoverContent\",\n \"PopoverFooter\",\n \"PopoverSelectionItem\",\n \"PopoverSelectionLabel\",\n \"PopoverSelectionList\",\n \"PopoverTrigger\",\n \"PricingSection\",\n \"ProfileMenu\",\n \"Progress\",\n \"PrototypeReview\",\n \"QuickActions\",\n \"RadioGroup\",\n \"RadioGroupItem\",\n \"RadiusScale\",\n \"RadiusSection\",\n \"RadiusSlide\",\n \"RightRailList\",\n \"ScoreIndicator\",\n \"ScrollArea\",\n \"ScrollBar\",\n \"SearchInput\",\n \"SectionHeader\",\n \"Select\",\n \"SelectContent\",\n \"SelectGroup\",\n \"SelectionListContext\",\n \"SelectItem\",\n \"SelectLabel\",\n \"SelectScrollDownButton\",\n \"SelectScrollUpButton\",\n \"SelectSeparator\",\n \"SelectTrigger\",\n \"SelectValue\",\n \"SemanticColorGrid\",\n \"SemanticColorItem\",\n \"SemanticTokensSlide\",\n \"Separator\",\n \"ShadowSection\",\n \"Sheet\",\n \"SheetClose\",\n \"SheetContent\",\n \"SheetDescription\",\n \"SheetFooter\",\n \"SheetHeader\",\n \"SheetOverlay\",\n \"SheetPortal\",\n \"SheetTitle\",\n \"SheetTrigger\",\n \"Sidebar\",\n \"SidebarContent\",\n \"SidebarContext\",\n \"SidebarFooter\",\n \"SidebarGroup\",\n \"SidebarGroupAction\",\n \"SidebarGroupContent\",\n \"SidebarGroupLabel\",\n \"SidebarHeader\",\n \"SidebarInset\",\n \"SidebarMenu\",\n \"SidebarMenuAction\",\n \"SidebarMenuBadge\",\n \"SidebarMenuButton\",\n \"SidebarMenuItem\",\n \"SidebarMenuSub\",\n \"SidebarMenuSubButton\",\n \"SidebarMenuSubItem\",\n \"SidebarProvider\",\n \"SidebarRail\",\n \"SidebarSeparator\",\n \"SidebarTrigger\",\n \"Skeleton\",\n \"Slide\",\n \"SlideHeader\",\n \"Slider\",\n \"SliderControl\",\n \"SlideThemeContext\",\n \"SlideThemeProvider\",\n \"SourceInspector\",\n \"SourceInspectorContext\",\n \"SourceInspectorDevImpl\",\n \"SourceInspectorProvider\",\n \"SourceInspectorRunner\",\n \"SourceInspectorToggle\",\n \"SpacingScale\",\n \"SpacingSection\",\n \"SpacingSlide\",\n \"Sparkline\",\n \"Sphere\",\n \"SpherePlayground\",\n \"Stack\",\n \"Stage\",\n \"StatCard\",\n \"StatHero\",\n \"StationSpectrum\",\n \"StatusBadge\",\n \"StatusColorsSlide\",\n \"StatusDot\",\n \"Stepper\",\n \"StepperContext\",\n \"StepperDescription\",\n \"StepperItem\",\n \"StepperSeparator\",\n \"StepperTitle\",\n \"StepperTrigger\",\n \"StepsSection\",\n \"SurfaceRow\",\n \"SurfaceSection\",\n \"Switch\",\n \"Table\",\n \"TableBody\",\n \"TableCaption\",\n \"TableCell\",\n \"TableFooter\",\n \"TableHead\",\n \"TableHeader\",\n \"TableRow\",\n \"Tabs\",\n \"TabsContent\",\n \"TabsList\",\n \"TabsTrigger\",\n \"TagInput\",\n \"TestimonialAttribution\",\n \"TestimonialSection\",\n \"Text\",\n \"Textarea\",\n \"ThemeArchitectureSlide\",\n \"ThemeColorsSlide\",\n \"ThemeSwitcher\",\n \"Timeline\",\n \"TimelineContent\",\n \"TimelineDescription\",\n \"TimelineIcon\",\n \"TimelineItem\",\n \"TimelineTimestamp\",\n \"TimelineTitle\",\n \"TitleSlide\",\n \"Toaster\",\n \"TOCSlide\",\n \"ToggleButton\",\n \"ToggleDevImpl\",\n \"ToggleGroup\",\n \"ToggleGroupContext\",\n \"ToggleGroupItem\",\n \"Tooltip\",\n \"TooltipContent\",\n \"TooltipProvider\",\n \"TooltipTrigger\",\n \"TypeBodySlide\",\n \"TypeDisplaySlide\",\n \"TypeSpecimen\",\n \"TypographySection\",\n \"WorkspaceSwitcher\",\n])\n"
4288
4295
  }
4289
4296
  ]
4290
4297
  },