@loworbitstudio/visor 1.11.0 → 1.11.1

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.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "version": "0.4.0",
3
- "generated_at": "2026-06-12T05:08:25.423Z",
3
+ "generated_at": "2026-06-15T22:40:15.943Z",
4
4
  "components": {
5
5
  "accessibility-specimen": {
6
6
  "changeType": "current",
@@ -66,12 +66,12 @@
66
66
  {
67
67
  "path": "components/ui/stepper/stepper.tsx",
68
68
  "type": "registry:ui",
69
- "content": "\"use client\"\n\nimport * as React from \"react\"\nimport { Check, Lock } from \"@phosphor-icons/react\"\nimport { cn } from \"../../../lib/utils\"\nimport styles from \"./stepper.module.css\"\n\n/* ─── Context ──────────────────────────────────────────────────────────────── */\n\ninterface StepperContextValue {\n activeStep: number\n orientation: \"horizontal\" | \"vertical\"\n}\n\nconst StepperContext = React.createContext<StepperContextValue>({\n activeStep: 0,\n orientation: \"horizontal\",\n})\n\nfunction useStepperContext() {\n return React.useContext(StepperContext)\n}\n\n/* ─── Stepper ──────────────────────────────────────────────────────────────── */\n\nexport interface StepperProps extends React.HTMLAttributes<HTMLDivElement> {\n activeStep?: number\n orientation?: \"horizontal\" | \"vertical\"\n}\n\nconst Stepper = React.forwardRef<HTMLDivElement, StepperProps>(\n ({ className, activeStep = 0, orientation = \"horizontal\", children, ...props }, ref) => {\n const contextValue = React.useMemo(\n () => ({ activeStep, orientation }),\n [activeStep, orientation]\n )\n\n return (\n <StepperContext.Provider value={contextValue}>\n <div\n ref={ref}\n role=\"group\"\n aria-label=\"Progress\"\n data-slot=\"stepper\"\n data-orientation={orientation}\n className={cn(\n styles.stepper,\n orientation === \"vertical\" && styles.stepperVertical,\n className\n )}\n {...props}\n >\n {children}\n </div>\n </StepperContext.Provider>\n )\n }\n)\nStepper.displayName = \"Stepper\"\n\n/* ─── StepperItem ──────────────────────────────────────────────────────────── */\n\nexport interface StepperItemProps extends React.HTMLAttributes<HTMLDivElement> {\n step: number\n status?: \"complete\" | \"active\" | \"upcoming\" | \"locked\"\n}\n\nconst StepperItem = React.forwardRef<HTMLDivElement, StepperItemProps>(\n ({ className, step, status, children, ...props }, ref) => {\n const { activeStep, orientation } = useStepperContext()\n\n const resolvedStatus =\n status ?? (step < activeStep ? \"complete\" : step === activeStep ? \"active\" : \"upcoming\")\n\n return (\n <div\n ref={ref}\n data-slot=\"stepper-item\"\n data-step={step}\n data-status={resolvedStatus}\n data-orientation={orientation}\n aria-current={resolvedStatus === \"active\" ? \"step\" : undefined}\n className={cn(\n styles.item,\n orientation === \"vertical\" && styles.itemVertical,\n className\n )}\n {...props}\n >\n {children}\n </div>\n )\n }\n)\nStepperItem.displayName = \"StepperItem\"\n\n/* ─── StepperTrigger ───────────────────────────────────────────────────────── */\n\nexport interface StepperTriggerProps\n extends React.ButtonHTMLAttributes<HTMLButtonElement> {\n step: number\n status?: \"complete\" | \"active\" | \"upcoming\" | \"locked\"\n}\n\nconst StepperTrigger = React.forwardRef<HTMLButtonElement, StepperTriggerProps>(\n ({ className, step, status, children, onClick, ...props }, ref) => {\n const { activeStep } = useStepperContext()\n\n const resolvedStatus =\n status ?? (step < activeStep ? \"complete\" : step === activeStep ? \"active\" : \"upcoming\")\n\n const isLocked = resolvedStatus === \"locked\"\n\n const handleClick = isLocked\n ? undefined\n : onClick\n\n return (\n <button\n ref={ref}\n type=\"button\"\n data-slot=\"stepper-trigger\"\n data-status={resolvedStatus}\n aria-disabled={isLocked || undefined}\n tabIndex={isLocked ? -1 : undefined}\n className={cn(\n styles.trigger,\n styles[`trigger--${resolvedStatus}`],\n className\n )}\n onClick={handleClick}\n {...props}\n >\n {resolvedStatus === \"complete\" ? (\n <Check size={14} weight=\"bold\" aria-hidden=\"true\" />\n ) : resolvedStatus === \"locked\" ? (\n <Lock size={12} weight=\"bold\" aria-hidden=\"true\" />\n ) : (\n children ?? step + 1\n )}\n <span className={styles.srOnly}>\n {resolvedStatus === \"complete\"\n ? \"Completed\"\n : resolvedStatus === \"locked\"\n ? `Step ${step + 1}, locked`\n : `Step ${step + 1}`}\n </span>\n </button>\n )\n }\n)\nStepperTrigger.displayName = \"StepperTrigger\"\n\n/* ─── StepperTitle ─────────────────────────────────────────────────────────── */\n\nconst StepperTitle = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(\n ({ className, ...props }, ref) => {\n return (\n <div\n ref={ref}\n data-slot=\"stepper-title\"\n className={cn(styles.title, className)}\n {...props}\n />\n )\n }\n)\nStepperTitle.displayName = \"StepperTitle\"\n\n/* ─── StepperDescription ───────────────────────────────────────────────────── */\n\nconst StepperDescription = React.forwardRef<\n HTMLParagraphElement,\n React.HTMLAttributes<HTMLParagraphElement>\n>(({ className, ...props }, ref) => {\n return (\n <p\n ref={ref}\n data-slot=\"stepper-description\"\n className={cn(styles.description, className)}\n {...props}\n />\n )\n})\nStepperDescription.displayName = \"StepperDescription\"\n\n/* ─── StepperSeparator ─────────────────────────────────────────────────────── */\n\nexport interface StepperSeparatorProps extends React.HTMLAttributes<HTMLDivElement> {\n complete?: boolean\n}\n\nconst StepperSeparator = React.forwardRef<HTMLDivElement, StepperSeparatorProps>(\n ({ className, complete = false, ...props }, ref) => {\n const { orientation } = useStepperContext()\n\n return (\n <div\n ref={ref}\n role=\"separator\"\n data-slot=\"stepper-separator\"\n data-orientation={orientation}\n data-complete={complete || undefined}\n className={cn(\n styles.separator,\n orientation === \"vertical\" && styles.separatorVertical,\n complete && styles.separatorComplete,\n className\n )}\n {...props}\n />\n )\n }\n)\nStepperSeparator.displayName = \"StepperSeparator\"\n\nexport {\n Stepper,\n StepperItem,\n StepperTrigger,\n StepperTitle,\n StepperDescription,\n StepperSeparator,\n}\n"
69
+ "content": "\"use client\"\n\nimport * as React from \"react\"\nimport { Check, Lock } from \"@phosphor-icons/react\"\nimport { cn } from \"../../../lib/utils\"\nimport styles from \"./stepper.module.css\"\n\n/* ─── Context ──────────────────────────────────────────────────────────────── */\n\ninterface StepperContextValue {\n activeStep: number\n orientation: \"horizontal\" | \"vertical\"\n variant: \"default\" | \"prominent\"\n}\n\nconst StepperContext = React.createContext<StepperContextValue>({\n activeStep: 0,\n orientation: \"horizontal\",\n variant: \"default\",\n})\n\nfunction useStepperContext() {\n return React.useContext(StepperContext)\n}\n\n/* ─── Stepper ──────────────────────────────────────────────────────────────── */\n\nexport interface StepperProps extends React.HTMLAttributes<HTMLDivElement> {\n activeStep?: number\n orientation?: \"horizontal\" | \"vertical\"\n /**\n * Visual treatment variant.\n * - `\"default\"` — standard step indicator, suitable for multi-step forms and\n * linear wizards. Use anywhere a stepper supports secondary navigation.\n * - `\"prominent\"` — enhanced treatment for vertical derivation spines or\n * primary-navigation surfaces: active row gets a primary-soft tint, the\n * active bullet renders a concentric halo + filled pulse dot (instead of\n * a step number), and complete-to-next rails render in a primary-line tint.\n * Best used vertically. Fully theme-agnostic — tokens resolve against the\n * active theme, so monochromatic themes stay restrained while colorful ones\n * get the intended pop.\n */\n variant?: \"default\" | \"prominent\"\n}\n\nconst Stepper = React.forwardRef<HTMLDivElement, StepperProps>(\n ({ className, activeStep = 0, orientation = \"horizontal\", variant = \"default\", children, ...props }, ref) => {\n const contextValue = React.useMemo(\n () => ({ activeStep, orientation, variant }),\n [activeStep, orientation, variant]\n )\n\n return (\n <StepperContext.Provider value={contextValue}>\n <div\n ref={ref}\n role=\"group\"\n aria-label=\"Progress\"\n data-slot=\"stepper\"\n data-orientation={orientation}\n data-variant={variant}\n className={cn(\n styles.stepper,\n orientation === \"vertical\" && styles.stepperVertical,\n className\n )}\n {...props}\n >\n {children}\n </div>\n </StepperContext.Provider>\n )\n }\n)\nStepper.displayName = \"Stepper\"\n\n/* ─── StepperItem ──────────────────────────────────────────────────────────── */\n\nexport interface StepperItemProps extends React.HTMLAttributes<HTMLDivElement> {\n step: number\n status?: \"complete\" | \"active\" | \"upcoming\" | \"locked\"\n}\n\nconst StepperItem = React.forwardRef<HTMLDivElement, StepperItemProps>(\n ({ className, step, status, children, ...props }, ref) => {\n const { activeStep, orientation, variant } = useStepperContext()\n\n const resolvedStatus =\n status ?? (step < activeStep ? \"complete\" : step === activeStep ? \"active\" : \"upcoming\")\n\n return (\n <div\n ref={ref}\n data-slot=\"stepper-item\"\n data-step={step}\n data-status={resolvedStatus}\n data-orientation={orientation}\n data-variant={variant}\n aria-current={resolvedStatus === \"active\" ? \"step\" : undefined}\n className={cn(\n styles.item,\n orientation === \"vertical\" && styles.itemVertical,\n variant === \"prominent\" && styles.itemProminent,\n variant === \"prominent\" && resolvedStatus === \"active\" && styles.itemProminentActive,\n className\n )}\n {...props}\n >\n {children}\n </div>\n )\n }\n)\nStepperItem.displayName = \"StepperItem\"\n\n/* ─── StepperTrigger ───────────────────────────────────────────────────────── */\n\nexport interface StepperTriggerProps\n extends React.ButtonHTMLAttributes<HTMLButtonElement> {\n step: number\n status?: \"complete\" | \"active\" | \"upcoming\" | \"locked\"\n}\n\nconst StepperTrigger = React.forwardRef<HTMLButtonElement, StepperTriggerProps>(\n ({ className, step, status, children, onClick, ...props }, ref) => {\n const { activeStep, variant } = useStepperContext()\n\n const resolvedStatus =\n status ?? (step < activeStep ? \"complete\" : step === activeStep ? \"active\" : \"upcoming\")\n\n const isLocked = resolvedStatus === \"locked\"\n const isProminentActive = variant === \"prominent\" && resolvedStatus === \"active\"\n\n const handleClick = isLocked\n ? undefined\n : onClick\n\n return (\n <button\n ref={ref}\n type=\"button\"\n data-slot=\"stepper-trigger\"\n data-status={resolvedStatus}\n data-variant={variant}\n aria-disabled={isLocked || undefined}\n tabIndex={isLocked ? -1 : undefined}\n className={cn(\n styles.trigger,\n styles[`trigger--${resolvedStatus}`],\n variant === \"prominent\" && styles[`triggerProminent--${resolvedStatus}`],\n className\n )}\n onClick={handleClick}\n {...props}\n >\n {resolvedStatus === \"complete\" ? (\n <Check size={14} weight=\"bold\" aria-hidden=\"true\" />\n ) : resolvedStatus === \"locked\" ? (\n <Lock size={12} weight=\"bold\" aria-hidden=\"true\" />\n ) : isProminentActive ? (\n /* Pulse dot replaces the step number in prominent active state */\n <span className={styles.pulseDot} aria-hidden=\"true\" />\n ) : (\n children ?? step + 1\n )}\n <span className={styles.srOnly}>\n {resolvedStatus === \"complete\"\n ? \"Completed\"\n : resolvedStatus === \"locked\"\n ? `Step ${step + 1}, locked`\n : `Step ${step + 1}`}\n </span>\n </button>\n )\n }\n)\nStepperTrigger.displayName = \"StepperTrigger\"\n\n/* ─── StepperTitle ─────────────────────────────────────────────────────────── */\n\nconst StepperTitle = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(\n ({ className, ...props }, ref) => {\n return (\n <div\n ref={ref}\n data-slot=\"stepper-title\"\n className={cn(styles.title, className)}\n {...props}\n />\n )\n }\n)\nStepperTitle.displayName = \"StepperTitle\"\n\n/* ─── StepperDescription ───────────────────────────────────────────────────── */\n\nconst StepperDescription = React.forwardRef<\n HTMLParagraphElement,\n React.HTMLAttributes<HTMLParagraphElement>\n>(({ className, ...props }, ref) => {\n return (\n <p\n ref={ref}\n data-slot=\"stepper-description\"\n className={cn(styles.description, className)}\n {...props}\n />\n )\n})\nStepperDescription.displayName = \"StepperDescription\"\n\n/* ─── StepperSeparator ─────────────────────────────────────────────────────── */\n\nexport interface StepperSeparatorProps extends React.HTMLAttributes<HTMLDivElement> {\n complete?: boolean\n}\n\nconst StepperSeparator = React.forwardRef<HTMLDivElement, StepperSeparatorProps>(\n ({ className, complete = false, ...props }, ref) => {\n const { orientation, variant } = useStepperContext()\n\n return (\n <div\n ref={ref}\n role=\"separator\"\n data-slot=\"stepper-separator\"\n data-orientation={orientation}\n data-complete={complete || undefined}\n data-variant={variant}\n className={cn(\n styles.separator,\n orientation === \"vertical\" && styles.separatorVertical,\n complete && styles.separatorComplete,\n variant === \"prominent\" && complete && styles.separatorProminentComplete,\n className\n )}\n {...props}\n />\n )\n }\n)\nStepperSeparator.displayName = \"StepperSeparator\"\n\nexport {\n Stepper,\n StepperItem,\n StepperTrigger,\n StepperTitle,\n StepperDescription,\n StepperSeparator,\n}\n"
70
70
  },
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/* A bare single-line title centers against the 2rem trigger; wrapped\n * title+description blocks keep the flex-start top alignment. */\n.itemVertical > .title {\n line-height: 2rem;\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.trigger--locked {\n background-color: transparent;\n border-color: var(--border-muted, #e5e7eb);\n color: var(--text-tertiary, #9ca3af);\n cursor: not-allowed;\n opacity: var(--opacity-60, 0.6);\n}\n\n/* Locked item — muted label */\n.item[data-status=\"locked\"] .title {\n color: var(--text-secondary, #6b7280);\n font-weight: var(--font-weight-normal, 400);\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"
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/* A bare single-line title centers against the 2rem trigger; wrapped\n * title+description blocks keep the flex-start top alignment. */\n.itemVertical > .title {\n line-height: 2rem;\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.trigger--locked {\n background-color: transparent;\n border-color: var(--border-muted, #e5e7eb);\n color: var(--text-tertiary, #9ca3af);\n cursor: not-allowed;\n opacity: var(--opacity-60, 0.6);\n}\n\n/* Locked item — muted label */\n.item[data-status=\"locked\"] .title {\n color: var(--text-secondary, #6b7280);\n font-weight: var(--font-weight-normal, 400);\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\n/* ─── Prominent variant ────────────────────────────────────────────────────── */\n\n/*\n * Prominent variant tokens (all via the active theme; no hardcoded colors):\n * --interactive-primary-bg — solid primary fill (complete bullet, active border)\n * --interactive-primary-text — contrast text on primary bg (complete bullet icon)\n * --interactive-primary-soft — ~12% primary alpha overlay (active row tint, halo)\n * --interactive-primary-glow — ~32% primary alpha overlay (stronger halo ring if needed)\n *\n * No --primary-line token is emitted; the tinted rail uses color-mix at ~34%.\n */\n\n/* Active row tint */\n.itemProminent {\n border-radius: var(--radius-lg, 8px);\n padding: var(--spacing-2, 0.5rem) var(--spacing-2, 0.5rem);\n margin: 0 calc(var(--spacing-2, 0.5rem) * -1);\n}\n\n.itemProminentActive {\n background-color: var(--interactive-primary-soft, color-mix(in srgb, var(--interactive-primary-bg, #111827) 12%, transparent));\n}\n\n/* Active row label color */\n.itemProminentActive .title {\n color: var(--interactive-primary-bg, #111827);\n}\n\n/* Prominent trigger — complete state: identical to default (already solid primary) */\n.triggerProminent--complete {\n /* no extra styles needed; default trigger--complete already matches */\n}\n\n/* Prominent trigger — active state: primary border + halo */\n.triggerProminent--active {\n border-color: var(--interactive-primary-bg, #111827);\n box-shadow: 0 0 0 var(--spacing-1, 0.25rem) var(--interactive-primary-soft, color-mix(in srgb, var(--interactive-primary-bg, #111827) 12%, transparent));\n}\n\n/* Prominent trigger — upcoming/locked: unchanged (no extra styles) */\n.triggerProminent--upcoming {}\n.triggerProminent--locked {}\n\n/* Pulse dot — primary-filled inner dot for active prominent trigger */\n.pulseDot {\n display: block;\n width: var(--spacing-2, 0.5rem);\n height: var(--spacing-2, 0.5rem);\n border-radius: var(--radius-full, 9999px);\n background-color: var(--interactive-primary-bg, #111827);\n flex-shrink: 0;\n}\n\n/* Prominent separator — complete rail tinted primary-line (~34% primary) */\n.separatorProminentComplete {\n background-color: color-mix(in srgb, var(--interactive-primary-bg, #111827) 34%, transparent);\n}\n"
75
75
  }
76
76
  ]
77
77
  },
@@ -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 Default rendering uses canonical values directly. Under data-density=\"editorial\"\n (set on any ancestor), the editorial density axis bakes in the blessed admin\n values: 1.125rem box, 4px radius, var(--surface-subtle) background, and\n var(--hairline-strong) border. */\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(--border-default, #e5e7eb);\n background-color: 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:global([data-density=\"editorial\"]) .root {\n width: 1.125rem;\n height: 1.125rem;\n border-radius: 4px;\n border-color: var(--hairline-strong, #e5e7eb);\n background-color: var(--surface-subtle);\n}\n\n@media (hover: hover) {\n .root:hover:not(:focus-visible):not(:disabled):not([aria-invalid=\"true\"]) {\n border-color: var(--border-strong, #d1d5db);\n background-color: transparent;\n }\n}\n\n@media (hover: hover) {\n :global([data-density=\"editorial\"]) .root:hover:not(:focus-visible):not(:disabled):not([aria-invalid=\"true\"]) {\n background-color: var(--surface-subtle);\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"
252
+ "content": "/* Checkbox root styles\n Default rendering uses canonical values directly. Under data-density=\"editorial\"\n (set on any ancestor), the editorial density axis bakes in the blessed admin\n values: 1.125rem box, 4px radius, var(--surface-subtle) background, and\n var(--hairline-strong) border. */\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(--border-default, #e5e7eb);\n background-color: 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:global([data-density=\"editorial\"]) .root {\n width: 1.125rem;\n height: 1.125rem;\n border-radius: 4px;\n border-color: var(--hairline-strong, #e5e7eb);\n background-color: var(--surface-subtle);\n}\n\n@media (hover: hover) {\n .root:hover:not(:focus-visible):not(:disabled):not([aria-invalid=\"true\"]):not([data-state=\"checked\"]):not([data-state=\"indeterminate\"]) {\n border-color: var(--border-strong, #d1d5db);\n background-color: transparent;\n }\n}\n\n@media (hover: hover) {\n :global([data-density=\"editorial\"]) .root:hover:not(:focus-visible):not(:disabled):not([aria-invalid=\"true\"]):not([data-state=\"checked\"]):not([data-state=\"indeterminate\"]) {\n background-color: var(--surface-subtle);\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
  },
@@ -443,12 +443,12 @@
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 /** 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 * Selected-state visual treatment.\n * - `\"accent\"` (default) — accent-tinted background + accent border + link text colour.\n * - `\"neutral\"` — neutral-elevated surface (--surface-card) + neutral border + primary text;\n * the count pill renders as a solid mint pill (--surface-success-default) when selected.\n * Use for editorial / admin contexts where accent bleed across shared tokens is undesirable.\n */\n selectedTreatment?: \"accent\" | \"neutral\"\n /** Optional trailing icon rendered after the count (e.g. a dropdown caret) for \"filter-as-dropdown\" chips. Muted by default. */\n trailingIcon?: React.ReactNode\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 selectedTreatment = \"accent\",\n trailingIcon,\n ...props\n },\n ref,\n ) => {\n const content = label ?? children\n const isNeutral = selectedTreatment === \"neutral\"\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-selected-treatment={selectedTreatment}\n data-value={value}\n disabled={disabled}\n className={cn(\n chipVariants({ variant, size }),\n styles.interactive,\n styles.filterChip,\n selected && (isNeutral ? styles.selectedNeutral : 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 isNeutral && selected\n ? styles.countSolid\n : countTone === \"primary\"\n ? styles.countPrimary\n : styles.countNeutral,\n )}\n >\n {count}\n </span>\n ) : null}\n {trailingIcon ? (\n <span className={styles.trailing} aria-hidden=\"true\">\n {trailingIcon}\n </span>\n ) : null}\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 \"filled-primary\": styles.variantFilledPrimary,\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 * Selected-state visual treatment.\n * - `\"accent\"` (default) — accent-tinted background + accent border + link text colour.\n * - `\"neutral\"` — neutral-elevated surface (--surface-card) + neutral border + primary text;\n * the count pill renders as a solid mint pill (--surface-success-default) when selected.\n * Use for editorial / admin contexts where accent bleed across shared tokens is undesirable.\n */\n selectedTreatment?: \"accent\" | \"neutral\"\n /** Optional trailing icon rendered after the count (e.g. a dropdown caret) for \"filter-as-dropdown\" chips. Muted by default. */\n trailingIcon?: React.ReactNode\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 selectedTreatment = \"accent\",\n trailingIcon,\n ...props\n },\n ref,\n ) => {\n const content = label ?? children\n const isNeutral = selectedTreatment === \"neutral\"\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-selected-treatment={selectedTreatment}\n data-value={value}\n disabled={disabled}\n className={cn(\n chipVariants({ variant, size }),\n styles.interactive,\n styles.filterChip,\n selected && (isNeutral ? styles.selectedNeutral : 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 isNeutral && selected\n ? styles.countSolid\n : countTone === \"primary\"\n ? styles.countPrimary\n : styles.countNeutral,\n )}\n >\n {count}\n </span>\n ) : null}\n {trailingIcon ? (\n <span className={styles.trailing} aria-hidden=\"true\">\n {trailingIcon}\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/* Editorial density: tighter font + gap for md chips. */\n:global([data-density=\"editorial\"]) .sizeMd {\n font-size: var(--font-size-xs);\n gap: var(--spacing-2);\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). Under data-density=\"editorial\", it renders\n as a fixed circular semibold pill. */\n.count {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n min-width: auto;\n height: auto;\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:global([data-density=\"editorial\"]) .count {\n min-width: 1.25rem;\n height: 1.25rem;\n padding-inline: var(--spacing-1);\n font-weight: var(--font-weight-semibold);\n align-self: center;\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/* Accent selected state overrides count pill (default behaviour). */\n.selected .count {\n background-color: var(--surface-card, #ffffff);\n color: var(--text-link, #2563eb);\n}\n\n/* Editorial density: selected count uses solid primary pill. */\n:global([data-density=\"editorial\"]) .selected .count {\n background-color: var(--primary);\n color: var(--primary-text);\n}\n\n/* Solid mint count pill — editorial/neutral selected treatment */\n.countSolid {\n background-color: var(--surface-success-default, #22c55e);\n color: var(--text-inverse, #ffffff);\n}\n\n/* Trailing icon (FilterChip dropdown caret) — muted, after the count. */\n.trailing {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n color: var(--text-tertiary, #9ca3af);\n font-size: 0.875rem;\n line-height: 1;\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. Under data-density=\"editorial\", switches to neutral-elevated\n treatment (surface-elev bg + transparent border + primary text). */\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/* Editorial density: neutral-elevated selected treatment.\n --surface-elev is a theme role; the color-mix fallback matches how the\n retired overlay derived it. */\n:global([data-density=\"editorial\"]) .selected {\n background: var(--surface-elev, color-mix(in srgb, var(--surface-card), var(--surface-muted, var(--surface-card))));\n border-color: transparent;\n color: var(--text-primary);\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\n/* Editorial / neutral-elevated selected treatment\n * Uses --surface-card bg + neutral border instead of accent tint.\n * Compose with .selected to override the accent colours. */\n.selectedNeutral {\n background-color: var(--surface-card, #ffffff);\n border-color: var(--border-strong, #d1d5db);\n color: var(--text-primary, #111827);\n}\n\n/* Re-assert selectedNeutral under editorial density: the density .selected rule\n * is (0,2,0) and would otherwise override .selectedNeutral at (0,1,0). */\n:global([data-density=\"editorial\"]) .selectedNeutral {\n background-color: var(--surface-card, #ffffff);\n border-color: var(--border-strong, #d1d5db);\n color: var(--text-primary, #111827);\n}\n\n.selectedNeutral .count {\n background-color: var(--surface-success-default, #22c55e);\n color: var(--text-inverse, #ffffff);\n}\n\n/* Re-assert selectedNeutral count under editorial density: the density\n * .selected .count rule at (0,3,0) would otherwise override at (0,2,0). */\n:global([data-density=\"editorial\"]) .selectedNeutral .count {\n background-color: var(--surface-success-default, #22c55e);\n color: var(--text-inverse, #ffffff);\n}\n\n@media (hover: hover) {\n .interactive.selectedNeutral:hover:not(:disabled) {\n background-color: var(--surface-interactive-hover, #f3f4f6);\n }\n}\n\n/* FilterChip resting (unselected) surface. Under editorial density, uses\n --surface-elev so the filter row reads as one consistent elevated set. */\n.filterChip[data-selected=\"false\"] {\n background-color: var(--surface-muted, #f3f4f6);\n}\n\n:global([data-density=\"editorial\"]) .filterChip[data-selected=\"false\"] {\n background-color: var(--surface-elev, color-mix(in srgb, var(--surface-card), var(--surface-muted, var(--surface-card))));\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/* Variant: filled-primary — saturated brand-essence chip treatment.\n * Primary background + primary-text foreground + subtle shadow.\n * 700 weight + slight negative tracking assert \"this IS a brand value\".\n * Use when the chip must carry primary brand prominence — essence chips\n * on the Brand Workbench Elicit canvas, strategy surfaces, brand decks. */\n.variantFilledPrimary {\n background-color: var(--primary, #111827);\n border-color: transparent;\n color: var(--primary-text, #f9fafb);\n font-weight: 700;\n letter-spacing: -0.01em;\n box-shadow: var(--shadow-sm, 0 1px 2px rgba(0, 0, 0, 0.05));\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/* Editorial density: tighter font + gap for md chips. */\n:global([data-density=\"editorial\"]) .sizeMd {\n font-size: var(--font-size-xs);\n gap: var(--spacing-2);\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). Under data-density=\"editorial\", it renders\n as a fixed circular semibold pill. */\n.count {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n min-width: auto;\n height: auto;\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:global([data-density=\"editorial\"]) .count {\n min-width: 1.25rem;\n height: 1.25rem;\n padding-inline: var(--spacing-1);\n font-weight: var(--font-weight-semibold);\n align-self: center;\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/* Accent selected state overrides count pill (default behaviour). */\n.selected .count {\n background-color: var(--surface-card, #ffffff);\n color: var(--text-link, #2563eb);\n}\n\n/* Editorial density: selected count uses solid primary pill. */\n:global([data-density=\"editorial\"]) .selected .count {\n background-color: var(--primary);\n color: var(--primary-text);\n}\n\n/* Solid mint count pill — editorial/neutral selected treatment */\n.countSolid {\n background-color: var(--surface-success-default, #22c55e);\n color: var(--text-inverse, #ffffff);\n}\n\n/* Trailing icon (FilterChip dropdown caret) — muted, after the count. */\n.trailing {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n color: var(--text-tertiary, #9ca3af);\n font-size: 0.875rem;\n line-height: 1;\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. Under data-density=\"editorial\", switches to neutral-elevated\n treatment (surface-elev bg + transparent border + primary text). */\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/* Editorial density: neutral-elevated selected treatment.\n --surface-elev is a theme role; the color-mix fallback matches how the\n retired overlay derived it. */\n:global([data-density=\"editorial\"]) .selected {\n background: var(--surface-elev, color-mix(in srgb, var(--surface-card), var(--surface-muted, var(--surface-card))));\n border-color: transparent;\n color: var(--text-primary);\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\n/* Editorial / neutral-elevated selected treatment\n * Uses --surface-card bg + neutral border instead of accent tint.\n * Compose with .selected to override the accent colours. */\n.selectedNeutral {\n background-color: var(--surface-card, #ffffff);\n border-color: var(--border-strong, #d1d5db);\n color: var(--text-primary, #111827);\n}\n\n/* Re-assert selectedNeutral under editorial density: the density .selected rule\n * is (0,2,0) and would otherwise override .selectedNeutral at (0,1,0). */\n:global([data-density=\"editorial\"]) .selectedNeutral {\n background-color: var(--surface-card, #ffffff);\n border-color: var(--border-strong, #d1d5db);\n color: var(--text-primary, #111827);\n}\n\n.selectedNeutral .count {\n background-color: var(--surface-success-default, #22c55e);\n color: var(--text-inverse, #ffffff);\n}\n\n/* Re-assert selectedNeutral count under editorial density: the density\n * .selected .count rule at (0,3,0) would otherwise override at (0,2,0). */\n:global([data-density=\"editorial\"]) .selectedNeutral .count {\n background-color: var(--surface-success-default, #22c55e);\n color: var(--text-inverse, #ffffff);\n}\n\n@media (hover: hover) {\n .interactive.selectedNeutral:hover:not(:disabled) {\n background-color: var(--surface-interactive-hover, #f3f4f6);\n }\n}\n\n/* FilterChip resting (unselected) surface. Under editorial density, uses\n --surface-elev so the filter row reads as one consistent elevated set. */\n.filterChip[data-selected=\"false\"] {\n background-color: var(--surface-muted, #f3f4f6);\n}\n\n:global([data-density=\"editorial\"]) .filterChip[data-selected=\"false\"] {\n background-color: var(--surface-elev, color-mix(in srgb, var(--surface-card), var(--surface-muted, var(--surface-card))));\n}\n"
452
452
  }
453
453
  ]
454
454
  },
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "version": "0.4.0",
3
- "generated_at": "2026-06-12T05:08:25.418Z",
3
+ "generated_at": "2026-06-15T22:40:15.938Z",
4
4
  "components": {
5
5
  "accessibility-specimen": {
6
6
  "category": "specimen",
@@ -1551,7 +1551,8 @@
1551
1551
  "variants": {
1552
1552
  "variant": [
1553
1553
  "default",
1554
- "outlined"
1554
+ "outlined",
1555
+ "filled-primary"
1555
1556
  ],
1556
1557
  "size": [
1557
1558
  "sm",
@@ -1562,7 +1563,7 @@
1562
1563
  "props": [
1563
1564
  {
1564
1565
  "name": "variant",
1565
- "type": "\"default\" | \"outlined\"",
1566
+ "type": "\"default\" | \"outlined\" | \"filled-primary\"",
1566
1567
  "default": "\"default\""
1567
1568
  },
1568
1569
  {
@@ -1693,6 +1694,7 @@
1693
1694
  "--primary",
1694
1695
  "--primary-text",
1695
1696
  "--radius-full",
1697
+ "--shadow-sm",
1696
1698
  "--spacing-1",
1697
1699
  "--spacing-2",
1698
1700
  "--spacing-3",
@@ -7875,6 +7877,14 @@
7875
7877
  "Pagination through pages of content (use Pagination)"
7876
7878
  ],
7877
7879
  "variants": [
7880
+ {
7881
+ "name": "variant",
7882
+ "values": [
7883
+ "default",
7884
+ "prominent"
7885
+ ],
7886
+ "description": "Visual treatment for the entire Stepper. \"default\" is the standard step indicator for multi-step forms and linear wizards. \"prominent\" is designed for vertical derivation spines and primary-navigation surfaces: the active row gets a primary-soft tint, the active bullet renders a concentric halo and filled pulse dot (replacing the step number), and complete-to-next rails render in a primary-line tint. Token surface: --interactive-primary-bg (border + fill + pulse dot), --interactive-primary-soft (row tint + halo), color-mix(in srgb, --interactive-primary-bg 34%, transparent) (rail tint). All values are fully theme-agnostic.\n"
7887
+ },
7878
7888
  {
7879
7889
  "name": "status",
7880
7890
  "values": [
@@ -7939,6 +7949,7 @@
7939
7949
  "--font-weight-medium",
7940
7950
  "--font-weight-normal",
7941
7951
  "--interactive-primary-bg",
7952
+ "--interactive-primary-soft",
7942
7953
  "--interactive-primary-text",
7943
7954
  "--line-height-normal",
7944
7955
  "--line-height-snug",
@@ -7947,6 +7958,7 @@
7947
7958
  "--opacity-60",
7948
7959
  "--primary",
7949
7960
  "--radius-full",
7961
+ "--radius-lg",
7950
7962
  "--spacing-1",
7951
7963
  "--spacing-2",
7952
7964
  "--spacing-4",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@loworbitstudio/visor",
3
- "version": "1.11.0",
3
+ "version": "1.11.1",
4
4
  "description": "CLI for the Visor design system — add components, hooks, and utilities to your project.",
5
5
  "type": "module",
6
6
  "bin": {