{
  "$schema": "https://ui.shadcn.com/schema/registry.json",
  "name": "bose-ui",
  "homepage": "https://boseui.site",
  "author": "Rishabh Bose (https://theb0se.vercel.app/)",
  "items": [
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "accordion",
      "type": "registry:ui",
      "title": "Accordion",
      "author": "Rishabh Bose <https://theb0se.vercel.app/>",
      "description": "Smooth collapsible disclosure panels with spring-rotated chevron indicators, single or multiple expansion modes, and full keyboard accessibility.",
      "dependencies": [
        "framer-motion",
        "lucide-react",
        "clsx",
        "tailwind-merge"
      ],
      "files": [
        {
          "path": "components/ui/accordion.tsx",
          "content": "\"use client\";\n\nimport React, { useState } from \"react\";\nimport { AnimatePresence, motion, useReducedMotion } from \"framer-motion\";\nimport { ChevronDown } from \"lucide-react\";\nimport { cn } from \"@/lib/utils\";\n\nexport interface AccordionItem {\n  id: string;\n  title: string;\n  subtitle?: string;\n  content: React.ReactNode;\n}\n\nexport interface AccordionProps {\n  /** Array of collapsible items */\n  items?: AccordionItem[];\n  /** Allow multiple items to stay open simultaneously */\n  allowMultiple?: boolean;\n  /** Default open item IDs */\n  defaultOpenIds?: string[];\n  /** Additional container class names */\n  className?: string;\n}\n\nconst DEFAULT_ITEMS: AccordionItem[] = [\n  {\n    id: \"item-1\",\n    title: \"How do I install BoseUI components?\",\n    subtitle: \"CLI & Manual Copy\",\n    content:\n      \"Run npx shadcn@latest add https://boseui.site/r/<slug>.json in your project terminal, or copy the TypeScript code directly from any component page.\",\n  },\n  {\n    id: \"item-2\",\n    title: \"Can I customize the Tailwind styles and animations?\",\n    subtitle: \"100% Source Ownership\",\n    content:\n      \"Yes. Because the source file lives directly inside your src/components/ui/ folder, you can edit every Tailwind class, Framer Motion spring parameter, or TypeScript prop.\",\n  },\n  {\n    id: \"item-3\",\n    title: \"Does it support Light Mode, Dark Mode, and Reduced Motion?\",\n    subtitle: \"Built-in Accessibility\",\n    content:\n      \"Every component is designed for high-contrast Light and Dark themes and automatically respects system prefers-reduced-motion settings.\",\n  },\n];\n\nexport function Accordion({\n  items = DEFAULT_ITEMS,\n  allowMultiple = false,\n  defaultOpenIds = [\"item-1\"],\n  className,\n}: AccordionProps) {\n  const shouldReduceMotion = useReducedMotion();\n  const [openIds, setOpenIds] = useState<string[]>(defaultOpenIds);\n\n  const toggleItem = (id: string) => {\n    setOpenIds((prev) => {\n      const isOpen = prev.includes(id);\n      if (allowMultiple) {\n        return isOpen ? prev.filter((i) => i !== id) : [...prev, id];\n      }\n      return isOpen ? [] : [id];\n    });\n  };\n\n  return (\n    <div\n      className={cn(\n        \"w-full max-w-md divide-y divide-neutral-200 overflow-hidden rounded-2xl border border-neutral-200 bg-white dark:divide-[#1F1F1F] dark:border-[#222222] dark:bg-[#0A0A0A]\",\n        className\n      )}\n    >\n      {items.map((item) => {\n        const isOpen = openIds.includes(item.id);\n        return (\n          <div key={item.id} className=\"flex flex-col\">\n            <button\n              type=\"button\"\n              aria-expanded={isOpen}\n              onClick={() => toggleItem(item.id)}\n              className=\"flex w-full cursor-pointer items-center justify-between gap-4 px-5 py-4 text-left transition-colors hover:bg-neutral-50 dark:hover:bg-[#111111]\"\n            >\n              <div className=\"min-w-0\">\n                <div className=\"text-xs font-semibold text-black dark:text-white sm:text-sm\">\n                  {item.title}\n                </div>\n                {item.subtitle && (\n                  <div className=\"mt-0.5 font-mono text-[10px] uppercase tracking-wider text-neutral-400\">\n                    {item.subtitle}\n                  </div>\n                )}\n              </div>\n\n              <motion.span\n                animate={{ rotate: isOpen ? 180 : 0 }}\n                transition={\n                  shouldReduceMotion\n                    ? { duration: 0 }\n                    : { type: \"spring\", stiffness: 360, damping: 26 }\n                }\n                className=\"flex h-6 w-6 shrink-0 items-center justify-center rounded-md border border-neutral-200 text-neutral-500 dark:border-[#262626] dark:text-neutral-400\"\n              >\n                <ChevronDown className=\"h-3.5 w-3.5\" />\n              </motion.span>\n            </button>\n\n            <AnimatePresence initial={false}>\n              {isOpen && (\n                <motion.div\n                  initial={\n                    shouldReduceMotion ? { opacity: 0 } : { height: 0, opacity: 0 }\n                  }\n                  animate={\n                    shouldReduceMotion\n                      ? { opacity: 1 }\n                      : { height: \"auto\", opacity: 1 }\n                  }\n                  exit={\n                    shouldReduceMotion ? { opacity: 0 } : { height: 0, opacity: 0 }\n                  }\n                  transition={{\n                    duration: shouldReduceMotion ? 0 : 0.22,\n                    ease: [0.22, 1, 0.36, 1],\n                  }}\n                  className=\"overflow-hidden\"\n                >\n                  <div className=\"px-5 pb-4 text-xs leading-relaxed text-neutral-600 dark:text-neutral-400\">\n                    {item.content}\n                  </div>\n                </motion.div>\n              )}\n            </AnimatePresence>\n          </div>\n        );\n      })}\n    </div>\n  );\n}\n\nexport default Accordion;\n",
          "type": "registry:ui",
          "target": "components/ui/accordion.tsx"
        },
        {
          "path": "lib/utils.ts",
          "content": "import { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...inputs: ClassValue[]) {\n  return twMerge(clsx(inputs));\n}\n\nexport async function copyToClipboard(text: string): Promise<boolean> {\n  if (typeof window === \"undefined\") return false;\n\n  try {\n    if (navigator.clipboard && window.isSecureContext) {\n      await navigator.clipboard.writeText(text);\n      return true;\n    }\n\n    const textArea = document.createElement(\"textarea\");\n    textArea.value = text;\n    textArea.style.position = \"fixed\";\n    textArea.style.left = \"-999999px\";\n    textArea.style.top = \"-999999px\";\n    document.body.appendChild(textArea);\n    textArea.focus();\n    textArea.select();\n    const succeeded = document.execCommand(\"copy\");\n    textArea.remove();\n    return succeeded;\n  } catch {\n    return false;\n  }\n}\n",
          "type": "registry:lib",
          "target": "lib/utils.ts"
        }
      ]
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "accordion-stack-cards",
      "type": "registry:ui",
      "title": "Accordion Stack Cards",
      "author": "Rishabh Bose <https://theb0se.vercel.app/>",
      "description": "Spatial 3D card deck that fans out into a vertical cascade on pointer hover or focus and cycles card order with spring layout projection.",
      "dependencies": [
        "framer-motion",
        "lucide-react",
        "clsx",
        "tailwind-merge"
      ],
      "files": [
        {
          "path": "components/ui/accordion-stack-cards.tsx",
          "content": "\"use client\";\n\nimport React, { useState } from \"react\";\nimport { motion, useReducedMotion } from \"framer-motion\";\nimport { Layers, ArrowUpRight, Sparkles, Terminal } from \"lucide-react\";\nimport { cn } from \"@/lib/utils\";\n\nexport interface StackCardItem {\n  id: string;\n  badge: string;\n  title: string;\n  metric: string;\n  subtitle: string;\n}\n\nexport interface AccordionStackCardsProps {\n  /** Array of stack card items. Defaults to a 3-card telemetry deck. */\n  items?: StackCardItem[];\n  /** Spring stiffness coefficient for deck expansion and rotation. Default: 300 */\n  stiffness?: number;\n  /** Spring damping coefficient for deck expansion and rotation. Default: 25 */\n  damping?: number;\n  className?: string;\n}\n\nconst DEFAULT_CARDS: StackCardItem[] = [\n  {\n    id: \"spring-core\",\n    badge: \"01 // PHYSICS ENGINE\",\n    title: \"Hooke's Law Solver\",\n    metric: \"120 Hz\",\n    subtitle: \"Continuous velocity-preserving spring interpolation\",\n  },\n  {\n    id: \"gpu-compositor\",\n    badge: \"02 // COMPOSITOR\",\n    title: \"Zero React Re-Renders\",\n    metric: \"0.0 ms\",\n    subtitle: \"Direct MotionValue & CSS mask-image projection\",\n  },\n  {\n    id: \"shadcn-cli\",\n    badge: \"03 // DISTRIBUTION\",\n    title: \"Shadcn Registry v2\",\n    metric: \"1-Click\",\n    subtitle: \"Copy-paste source ownership with strict TypeScript\",\n  },\n];\n\nexport function AccordionStackCards({\n  items = DEFAULT_CARDS,\n  stiffness = 300,\n  damping = 25,\n  className,\n}: AccordionStackCardsProps) {\n  const shouldReduceMotion = useReducedMotion() ?? false;\n  const [deck, setDeck] = useState<StackCardItem[]>(items);\n  const [isExpanded, setIsExpanded] = useState(false);\n\n  const cycleFrontCard = () => {\n    setDeck((prev) => {\n      if (prev.length <= 1) return prev;\n      const [first, ...rest] = prev;\n      return [...rest, first!];\n    });\n  };\n\n  return (\n    <div\n      onMouseEnter={() => setIsExpanded(true)}\n      onMouseLeave={() => setIsExpanded(false)}\n      className={cn(\n        \"relative flex min-h-[260px] w-full max-w-sm flex-col items-center justify-center py-4\",\n        className\n      )}\n    >\n      <div className=\"relative h-[200px] w-full\">\n        {deck.map((card, index) => {\n          const isFront = index === 0;\n          const yOffset = isExpanded ? index * 54 : index * 12;\n          const scale = isExpanded ? 1 : 1 - index * 0.05;\n          const opacity = isExpanded ? 1 : 1 - index * 0.22;\n\n          return (\n            <motion.div\n              key={card.id}\n              layout\n              role=\"button\"\n              tabIndex={0}\n              aria-label={`${card.title} — ${card.subtitle}. Click to cycle stack.`}\n              onFocus={() => setIsExpanded(true)}\n              onBlur={() => setIsExpanded(false)}\n              onClick={cycleFrontCard}\n              onKeyDown={(e) => {\n                if (e.key === \"Enter\" || e.key === \" \") {\n                  e.preventDefault();\n                  cycleFrontCard();\n                }\n              }}\n              animate={{\n                y: yOffset,\n                scale: shouldReduceMotion ? 1 : scale,\n                opacity,\n                zIndex: deck.length - index,\n              }}\n              transition={\n                shouldReduceMotion\n                  ? { duration: 0 }\n                  : { type: \"spring\", stiffness, damping }\n              }\n              className={cn(\n                \"absolute inset-x-0 top-0 cursor-pointer select-none rounded-2xl border p-5 shadow-sm transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-black dark:focus-visible:ring-white\",\n                isFront\n                  ? \"border-neutral-300 bg-white hover:border-black dark:border-[#2E2E2E] dark:bg-[#0D0D0D] dark:hover:border-white\"\n                  : \"border-neutral-200 bg-neutral-50/95 dark:border-[#222222] dark:bg-[#141414]/95\"\n              )}\n            >\n              <div className=\"flex items-center justify-between gap-2\">\n                <span className=\"inline-flex items-center gap-1.5 font-mono text-[10px] font-semibold uppercase tracking-wider text-neutral-500 dark:text-neutral-400\">\n                  {index === 0 ? (\n                    <Sparkles className=\"h-3 w-3 text-black dark:text-white\" />\n                  ) : index === 1 ? (\n                    <Layers className=\"h-3 w-3\" />\n                  ) : (\n                    <Terminal className=\"h-3 w-3\" />\n                  )}\n                  {card.badge}\n                </span>\n\n                <span className=\"inline-flex items-center gap-1 rounded-full border border-neutral-200 bg-neutral-100 px-2 py-0.5 font-mono text-[10px] font-bold text-black dark:border-[#262626] dark:bg-[#1B1B1B] dark:text-white\">\n                  {card.metric}\n                  <ArrowUpRight className=\"h-2.5 w-2.5\" />\n                </span>\n              </div>\n\n              <div className=\"mt-2.5 text-sm font-semibold text-black dark:text-white\">\n                {card.title}\n              </div>\n              <p className=\"mt-0.5 text-xs text-neutral-500 dark:text-neutral-400\">\n                {card.subtitle}\n              </p>\n            </motion.div>\n          );\n        })}\n      </div>\n\n      <div className=\"mt-4 text-center text-[11px] text-neutral-400 dark:text-neutral-500\">\n        Hover to fan out deck • Click any card to cycle stack\n      </div>\n    </div>\n  );\n}\n\nexport default AccordionStackCards;\n",
          "type": "registry:ui",
          "target": "components/ui/accordion-stack-cards.tsx"
        },
        {
          "path": "lib/utils.ts",
          "content": "import { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...inputs: ClassValue[]) {\n  return twMerge(clsx(inputs));\n}\n\nexport async function copyToClipboard(text: string): Promise<boolean> {\n  if (typeof window === \"undefined\") return false;\n\n  try {\n    if (navigator.clipboard && window.isSecureContext) {\n      await navigator.clipboard.writeText(text);\n      return true;\n    }\n\n    const textArea = document.createElement(\"textarea\");\n    textArea.value = text;\n    textArea.style.position = \"fixed\";\n    textArea.style.left = \"-999999px\";\n    textArea.style.top = \"-999999px\";\n    document.body.appendChild(textArea);\n    textArea.focus();\n    textArea.select();\n    const succeeded = document.execCommand(\"copy\");\n    textArea.remove();\n    return succeeded;\n  } catch {\n    return false;\n  }\n}\n",
          "type": "registry:lib",
          "target": "lib/utils.ts"
        }
      ]
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "animated-tabs",
      "type": "registry:ui",
      "title": "Animated Tabs",
      "author": "Rishabh Bose <https://theb0se.vercel.app/>",
      "description": "Smooth shared-element sliding pill tabs with animated panel transitions, optional badge counters, and keyboard arrow navigation.",
      "dependencies": [
        "framer-motion",
        "clsx",
        "tailwind-merge"
      ],
      "files": [
        {
          "path": "components/ui/animated-tabs.tsx",
          "content": "\"use client\";\n\nimport React, { useState, useId, useRef } from \"react\";\nimport { AnimatePresence, motion, useReducedMotion } from \"framer-motion\";\nimport { cn } from \"@/lib/utils\";\n\nexport interface TabItem {\n  id: string;\n  label: string;\n  badge?: string | number;\n  content: React.ReactNode;\n}\n\nexport interface AnimatedTabsProps {\n  /** Array of tab definitions */\n  tabs?: TabItem[];\n  /** Default active tab ID */\n  defaultTabId?: string;\n  /** Callback fired when active tab changes */\n  onChange?: (tabId: string) => void;\n  /** Additional container class names */\n  className?: string;\n}\n\nconst DEFAULT_TABS: TabItem[] = [\n  {\n    id: \"preview\",\n    label: \"Overview\",\n    content: (\n      <div className=\"space-y-1.5\">\n        <div className=\"text-xs font-semibold text-black dark:text-white\">\n          Shared-Element Sliding Indicator\n        </div>\n        <p className=\"text-xs leading-relaxed text-neutral-500 dark:text-neutral-400\">\n          The active pill glides smoothly between tabs using Framer Motion\n          layoutId springs with zero layout shift.\n        </p>\n      </div>\n    ),\n  },\n  {\n    id: \"metrics\",\n    label: \"Metrics\",\n    badge: \"99.9%\",\n    content: (\n      <div className=\"grid grid-cols-2 gap-3\">\n        <div className=\"rounded-xl border border-neutral-200 p-3 dark:border-[#222222]\">\n          <div className=\"font-mono text-[10px] text-neutral-400\">FRAME BUDGET</div>\n          <div className=\"mt-1 font-mono text-sm font-semibold text-black dark:text-white\">\n            &lt; 1.2ms\n          </div>\n        </div>\n        <div className=\"rounded-xl border border-neutral-200 p-3 dark:border-[#222222]\">\n          <div className=\"font-mono text-[10px] text-neutral-400\">BUNDLE SIZE</div>\n          <div className=\"mt-1 font-mono text-sm font-semibold text-black dark:text-white\">\n            1.8 kB\n          </div>\n        </div>\n      </div>\n    ),\n  },\n  {\n    id: \"settings\",\n    label: \"Settings\",\n    content: (\n      <div className=\"space-y-1.5\">\n        <div className=\"text-xs font-semibold text-black dark:text-white\">\n          Keyboard Accessible\n        </div>\n        <p className=\"text-xs leading-relaxed text-neutral-500 dark:text-neutral-400\">\n          Use Left, Right, Home, and End keys to cycle through tabs with full\n          WAI-ARIA tablist focus management.\n        </p>\n      </div>\n    ),\n  },\n];\n\nexport function AnimatedTabs({\n  tabs = DEFAULT_TABS,\n  defaultTabId,\n  onChange,\n  className,\n}: AnimatedTabsProps) {\n  const shouldReduceMotion = useReducedMotion();\n  const instanceId = useId();\n  const tabRefs = useRef<Array<HTMLButtonElement | null>>([]);\n  const [activeId, setActiveId] = useState<string>(\n    defaultTabId || tabs[0]?.id || \"\"\n  );\n\n  const activeTab = tabs.find((t) => t.id === activeId) || tabs[0];\n\n  const handleSelect = (id: string, focusIndex?: number) => {\n    setActiveId(id);\n    onChange?.(id);\n    if (focusIndex !== undefined) {\n      tabRefs.current[focusIndex]?.focus();\n    }\n  };\n\n  const handleKeyDown = (\n    e: React.KeyboardEvent<HTMLButtonElement>,\n    idx: number\n  ) => {\n    if (e.key === \"ArrowRight\") {\n      e.preventDefault();\n      const nextIdx = (idx + 1) % tabs.length;\n      const next = tabs[nextIdx];\n      if (next) handleSelect(next.id, nextIdx);\n    } else if (e.key === \"ArrowLeft\") {\n      e.preventDefault();\n      const prevIdx = (idx - 1 + tabs.length) % tabs.length;\n      const prev = tabs[prevIdx];\n      if (prev) handleSelect(prev.id, prevIdx);\n    } else if (e.key === \"Home\") {\n      e.preventDefault();\n      if (tabs[0]) handleSelect(tabs[0].id, 0);\n    } else if (e.key === \"End\") {\n      e.preventDefault();\n      const lastIdx = tabs.length - 1;\n      if (tabs[lastIdx]) handleSelect(tabs[lastIdx].id, lastIdx);\n    }\n  };\n\n  return (\n    <div className={cn(\"w-full max-w-md\", className)}>\n      {/* Tab List */}\n      <div\n        role=\"tablist\"\n        aria-label=\"Content tabs\"\n        className=\"inline-flex w-full items-center gap-1 rounded-xl border border-neutral-200 bg-neutral-100/80 p-1 dark:border-[#222222] dark:bg-[#0C0C0C]\"\n      >\n        {tabs.map((tab, idx) => {\n          const isActive = tab.id === activeId;\n          return (\n            <button\n              key={tab.id}\n              ref={(el) => {\n                tabRefs.current[idx] = el;\n              }}\n              type=\"button\"\n              role=\"tab\"\n              tabIndex={isActive ? 0 : -1}\n              aria-selected={isActive}\n              onClick={() => handleSelect(tab.id)}\n              onKeyDown={(e) => handleKeyDown(e, idx)}\n              className={cn(\n                \"relative flex flex-1 cursor-pointer items-center justify-center gap-1.5 rounded-lg px-3 py-1.5 text-xs font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-black dark:focus-visible:ring-white\",\n                isActive\n                  ? \"text-white dark:text-black\"\n                  : \"text-neutral-600 hover:text-black dark:text-neutral-400 dark:hover:text-white\"\n              )}\n            >\n              {isActive && (\n                <motion.span\n                  layoutId={`tab-pill-${instanceId}`}\n                  transition={\n                    shouldReduceMotion\n                      ? { duration: 0 }\n                      : { type: \"spring\", stiffness: 420, damping: 32 }\n                  }\n                  className=\"absolute inset-0 rounded-lg bg-black shadow-xs dark:bg-white\"\n                />\n              )}\n              <span className=\"relative z-10\">{tab.label}</span>\n              {tab.badge !== undefined && (\n                <span\n                  className={cn(\n                    \"relative z-10 rounded px-1 py-0.2 font-mono text-[10px]\",\n                    isActive\n                      ? \"bg-white/20 text-white dark:bg-black/15 dark:text-black\"\n                      : \"bg-neutral-200/80 text-neutral-600 dark:bg-[#1A1A1A] dark:text-neutral-400\"\n                  )}\n                >\n                  {tab.badge}\n                </span>\n              )}\n            </button>\n          );\n        })}\n      </div>\n\n      {/* Tab Panel */}\n      <div\n        role=\"tabpanel\"\n        className=\"mt-3 overflow-hidden rounded-2xl border border-neutral-200 bg-white p-5 dark:border-[#222222] dark:bg-[#0A0A0A]\"\n      >\n        <AnimatePresence mode=\"wait\" initial={false}>\n          <motion.div\n            key={activeTab?.id}\n            initial={shouldReduceMotion ? { opacity: 0 } : { opacity: 0, y: 6 }}\n            animate={shouldReduceMotion ? { opacity: 1 } : { opacity: 1, y: 0 }}\n            exit={shouldReduceMotion ? { opacity: 0 } : { opacity: 0, y: -4 }}\n            transition={{ duration: shouldReduceMotion ? 0 : 0.16 }}\n          >\n            {activeTab?.content}\n          </motion.div>\n        </AnimatePresence>\n      </div>\n    </div>\n  );\n}\n\nexport default AnimatedTabs;\n",
          "type": "registry:ui",
          "target": "components/ui/animated-tabs.tsx"
        },
        {
          "path": "lib/utils.ts",
          "content": "import { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...inputs: ClassValue[]) {\n  return twMerge(clsx(inputs));\n}\n\nexport async function copyToClipboard(text: string): Promise<boolean> {\n  if (typeof window === \"undefined\") return false;\n\n  try {\n    if (navigator.clipboard && window.isSecureContext) {\n      await navigator.clipboard.writeText(text);\n      return true;\n    }\n\n    const textArea = document.createElement(\"textarea\");\n    textArea.value = text;\n    textArea.style.position = \"fixed\";\n    textArea.style.left = \"-999999px\";\n    textArea.style.top = \"-999999px\";\n    document.body.appendChild(textArea);\n    textArea.focus();\n    textArea.select();\n    const succeeded = document.execCommand(\"copy\");\n    textArea.remove();\n    return succeeded;\n  } catch {\n    return false;\n  }\n}\n",
          "type": "registry:lib",
          "target": "lib/utils.ts"
        }
      ]
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "apple-context-menu",
      "type": "registry:ui",
      "title": "Context Menu & Popover",
      "author": "Rishabh Bose <https://theb0se.vercel.app/>",
      "description": "Frosted glassmorphic context menu and popover with a directional pointer arrow, hairline-divided action groups, keyboard shortcuts, and red destructive items.",
      "dependencies": [
        "framer-motion",
        "lucide-react",
        "clsx",
        "tailwind-merge"
      ],
      "files": [
        {
          "path": "components/ui/apple-context-menu.tsx",
          "content": "\"use client\";\n\nimport React, { useState, useRef, useEffect } from \"react\";\nimport { AnimatePresence, motion, useReducedMotion } from \"framer-motion\";\nimport {\n  Copy,\n  Share2,\n  Pin,\n  FolderInput,\n  Trash2,\n  MoreHorizontal,\n  Check,\n} from \"lucide-react\";\nimport { cn } from \"@/lib/utils\";\n\nexport interface ContextMenuItem {\n  id: string;\n  label: string;\n  shortcut?: string;\n  icon?: React.ReactNode;\n  destructive?: boolean;\n  onSelect?: () => void;\n}\n\nexport interface ContextMenuGroup {\n  id: string;\n  items: ContextMenuItem[];\n}\n\nexport interface AppleContextMenuProps {\n  /** Grouped menu items separated by hairline dividers */\n  groups?: ContextMenuGroup[];\n  /** Label shown on the trigger button */\n  triggerLabel?: string;\n  /** Initial open state for uncontrolled mode. Default: false */\n  defaultOpen?: boolean;\n  /** Callback fired when any menu item is clicked */\n  onSelect?: (item: ContextMenuItem) => void;\n  className?: string;\n}\n\nconst DEFAULT_GROUPS: ContextMenuGroup[] = [\n  {\n    id: \"primary\",\n    items: [\n      {\n        id: \"copy\",\n        label: \"Copy Component Link\",\n        shortcut: \"⌘C\",\n        icon: <Copy className=\"h-3.5 w-3.5\" />,\n      },\n      {\n        id: \"share\",\n        label: \"Share Preview...\",\n        shortcut: \"⇧⌘S\",\n        icon: <Share2 className=\"h-3.5 w-3.5\" />,\n      },\n      {\n        id: \"pin\",\n        label: \"Pin to Workspace\",\n        shortcut: \"⌘P\",\n        icon: <Pin className=\"h-3.5 w-3.5\" />,\n      },\n    ],\n  },\n  {\n    id: \"organize\",\n    items: [\n      {\n        id: \"move\",\n        label: \"Move to Collection\",\n        icon: <FolderInput className=\"h-3.5 w-3.5\" />,\n      },\n    ],\n  },\n  {\n    id: \"danger\",\n    items: [\n      {\n        id: \"delete\",\n        label: \"Delete Component\",\n        shortcut: \"⌘⌫\",\n        icon: <Trash2 className=\"h-3.5 w-3.5\" />,\n        destructive: true,\n      },\n    ],\n  },\n];\n\nexport function AppleContextMenu({\n  groups = DEFAULT_GROUPS,\n  triggerLabel = \"Actions Menu\",\n  defaultOpen = false,\n  onSelect,\n  className,\n}: AppleContextMenuProps) {\n  const shouldReduceMotion = useReducedMotion() ?? false;\n  const containerRef = useRef<HTMLDivElement>(null);\n\n  const [open, setOpen] = useState(defaultOpen);\n  const [lastAction, setLastAction] = useState<string | null>(null);\n\n  useEffect(() => {\n    if (!open) return;\n    const handleOutside = (e: MouseEvent) => {\n      if (\n        containerRef.current &&\n        !containerRef.current.contains(e.target as Node)\n      ) {\n        setOpen(false);\n      }\n    };\n    const handleEscape = (e: KeyboardEvent) => {\n      if (e.key === \"Escape\") {\n        setOpen(false);\n      }\n    };\n    document.addEventListener(\"mousedown\", handleOutside);\n    window.addEventListener(\"keydown\", handleEscape);\n    return () => {\n      document.removeEventListener(\"mousedown\", handleOutside);\n      window.removeEventListener(\"keydown\", handleEscape);\n    };\n  }, [open]);\n\n  const handleSelect = (item: ContextMenuItem) => {\n    item.onSelect?.();\n    onSelect?.(item);\n    setLastAction(item.label);\n    setOpen(false);\n  };\n\n  return (\n    <div\n      ref={containerRef}\n      onContextMenu={(e) => {\n        e.preventDefault();\n        setOpen(true);\n      }}\n      className={cn(\"relative inline-flex flex-col items-center\", className)}\n    >\n      {/* Trigger Bar */}\n      <div className=\"flex items-center gap-2.5\">\n        <button\n          type=\"button\"\n          aria-haspopup=\"menu\"\n          aria-expanded={open}\n          onClick={() => setOpen((v) => !v)}\n          className={cn(\n            \"inline-flex h-10 items-center gap-2 rounded-2xl border px-4 text-xs font-semibold shadow-2xs transition-all active:scale-95\",\n            open\n              ? \"border-neutral-900 bg-neutral-900 text-white dark:border-white dark:bg-white dark:text-black\"\n              : \"border-neutral-200 bg-white text-neutral-900 hover:border-neutral-900 dark:border-neutral-800 dark:bg-[#0A0A0A] dark:text-white dark:hover:border-white\"\n          )}\n        >\n          <span>{triggerLabel}</span>\n          <MoreHorizontal className=\"h-4 w-4\" />\n        </button>\n\n        {lastAction && (\n          <span className=\"inline-flex items-center gap-1 text-[11px] text-neutral-500 dark:text-neutral-400\">\n            <Check className=\"h-3 w-3 text-neutral-900 dark:text-white\" />\n            {lastAction}\n          </span>\n        )}\n      </div>\n\n      {/* Frosted Blurred Context Popover with Small Arrow */}\n      <AnimatePresence>\n        {open && (\n          <motion.div\n            role=\"menu\"\n            aria-label={triggerLabel}\n            initial={\n              shouldReduceMotion\n                ? { opacity: 0 }\n                : { opacity: 0, scale: 0.92, y: -6 }\n            }\n            animate={{ opacity: 1, scale: 1, y: 0 }}\n            exit={\n              shouldReduceMotion\n                ? { opacity: 0 }\n                : { opacity: 0, scale: 0.94, y: -4 }\n            }\n            transition={{ type: \"spring\", stiffness: 440, damping: 28 }}\n            style={{ originY: 0 }}\n            className=\"absolute top-[calc(100%+12px)] z-50 w-60 rounded-2xl border border-neutral-200/90 bg-white/90 p-1.5 shadow-2xl backdrop-blur-xl dark:border-neutral-800/90 dark:bg-[#121212]/90\"\n          >\n            {/* Small Top Arrow Caret */}\n            <div\n              aria-hidden=\"true\"\n              className=\"absolute -top-1.5 left-1/2 h-3 w-3 -translate-x-1/2 rotate-45 border-l border-t border-neutral-200/90 bg-white/90 dark:border-neutral-800/90 dark:bg-[#121212]/90\"\n            />\n\n            {/* Grouped Actions */}\n            <div className=\"relative z-10 divide-y divide-neutral-200/75 dark:divide-neutral-800/80\">\n              {groups.map((group) => (\n                <div key={group.id} className=\"py-1 first:pt-0 last:pb-0\">\n                  {group.items.map((item) => (\n                    <button\n                      key={item.id}\n                      type=\"button\"\n                      role=\"menuitem\"\n                      onClick={() => handleSelect(item)}\n                      className={cn(\n                        \"flex w-full items-center justify-between rounded-xl px-3 py-2 text-left text-xs font-medium transition-colors\",\n                        item.destructive\n                          ? \"text-red-600 hover:bg-red-500/10 dark:text-red-400 dark:hover:bg-red-500/15\"\n                          : \"text-neutral-800 hover:bg-neutral-100/90 dark:text-neutral-200 dark:hover:bg-neutral-800/70\"\n                      )}\n                    >\n                      <span className=\"flex items-center gap-2.5\">\n                        <span\n                          className={cn(\n                            item.destructive\n                              ? \"text-red-500 dark:text-red-400\"\n                              : \"text-neutral-500 dark:text-neutral-400\"\n                          )}\n                        >\n                          {item.icon}\n                        </span>\n                        <span>{item.label}</span>\n                      </span>\n\n                      {item.shortcut && (\n                        <kbd\n                          className={cn(\n                            \"font-mono text-[10px]\",\n                            item.destructive\n                              ? \"text-red-400 dark:text-red-500/80\"\n                              : \"text-neutral-400 dark:text-neutral-500\"\n                          )}\n                        >\n                          {item.shortcut}\n                        </kbd>\n                      )}\n                    </button>\n                  ))}\n                </div>\n              ))}\n            </div>\n          </motion.div>\n        )}\n      </AnimatePresence>\n    </div>\n  );\n}\n\nexport default AppleContextMenu;\n",
          "type": "registry:ui",
          "target": "components/ui/apple-context-menu.tsx"
        },
        {
          "path": "lib/utils.ts",
          "content": "import { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...inputs: ClassValue[]) {\n  return twMerge(clsx(inputs));\n}\n\nexport async function copyToClipboard(text: string): Promise<boolean> {\n  if (typeof window === \"undefined\") return false;\n\n  try {\n    if (navigator.clipboard && window.isSecureContext) {\n      await navigator.clipboard.writeText(text);\n      return true;\n    }\n\n    const textArea = document.createElement(\"textarea\");\n    textArea.value = text;\n    textArea.style.position = \"fixed\";\n    textArea.style.left = \"-999999px\";\n    textArea.style.top = \"-999999px\";\n    document.body.appendChild(textArea);\n    textArea.focus();\n    textArea.select();\n    const succeeded = document.execCommand(\"copy\");\n    textArea.remove();\n    return succeeded;\n  } catch {\n    return false;\n  }\n}\n",
          "type": "registry:lib",
          "target": "lib/utils.ts"
        }
      ]
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "apple-search-field",
      "type": "registry:ui",
      "title": "Search Field",
      "author": "Rishabh Bose <https://theb0se.vercel.app/>",
      "description": "Rounded iOS-inspired search bar with a magnifier icon, inline clear badge, quick suggestion pills, and a 'Cancel' button that slides in smoothly on focus.",
      "dependencies": [
        "framer-motion",
        "lucide-react",
        "clsx",
        "tailwind-merge"
      ],
      "files": [
        {
          "path": "components/ui/apple-search-field.tsx",
          "content": "\"use client\";\n\nimport React, { useState, useRef } from \"react\";\nimport { AnimatePresence, motion, useReducedMotion } from \"framer-motion\";\nimport { Search, X, ArrowUpRight } from \"lucide-react\";\nimport { cn } from \"@/lib/utils\";\n\nexport interface AppleSearchFieldProps {\n  /** Placeholder text inside the search field */\n  placeholder?: string;\n  /** Controlled search query */\n  value?: string;\n  /** Initial query for uncontrolled mode */\n  defaultValue?: string;\n  /** Callback fired when query changes */\n  onChange?: (query: string) => void;\n  /** Callback fired when Cancel is clicked */\n  onCancel?: () => void;\n  /** Quick suggestion pills shown when focused */\n  suggestions?: string[];\n  className?: string;\n}\n\nconst DEFAULT_SUGGESTIONS = [\n  \"Drawer Overlay\",\n  \"Picker Wheel\",\n  \"Sticky Sub-Nav\",\n  \"Command Menu\",\n];\n\nexport function AppleSearchField({\n  placeholder = \"Search components, tokens, or docs...\",\n  value: controlledValue,\n  defaultValue = \"\",\n  onChange,\n  onCancel,\n  suggestions = DEFAULT_SUGGESTIONS,\n  className,\n}: AppleSearchFieldProps) {\n  const shouldReduceMotion = useReducedMotion() ?? false;\n  const inputRef = useRef<HTMLInputElement>(null);\n  const isControlled = controlledValue !== undefined;\n\n  const [internalQuery, setInternalQuery] = useState(defaultValue);\n  const [isActive, setIsActive] = useState(false);\n\n  const query = isControlled ? controlledValue : internalQuery;\n  const showCancel = isActive || query.length > 0;\n\n  const setQuery = (next: string) => {\n    if (!isControlled) {\n      setInternalQuery(next);\n    }\n    onChange?.(next);\n  };\n\n  const handleCancel = () => {\n    setQuery(\"\");\n    setIsActive(false);\n    inputRef.current?.blur();\n    onCancel?.();\n  };\n\n  const filteredSuggestions = suggestions.filter((s) =>\n    s.toLowerCase().includes(query.trim().toLowerCase())\n  );\n\n  return (\n    <div className={cn(\"w-full max-w-md\", className)}>\n      <div className=\"flex items-center gap-2.5\">\n        {/* Expanding / Contracting Rounded Search Field */}\n        <motion.div\n          layout={!shouldReduceMotion}\n          transition={{ type: \"spring\", stiffness: 420, damping: 32 }}\n          className={cn(\n            \"relative flex h-11 flex-1 items-center rounded-2xl border bg-neutral-100/80 px-3.5 transition-colors dark:bg-[#121212]\",\n            isActive\n              ? \"border-neutral-900 bg-white ring-3 ring-neutral-900/10 dark:border-white dark:bg-[#0A0A0A] dark:ring-white/15\"\n              : \"border-neutral-200/80 hover:border-neutral-300 dark:border-neutral-800\"\n          )}\n        >\n          <Search\n            className={cn(\n              \"mr-2.5 h-4 w-4 shrink-0 transition-colors\",\n              isActive\n                ? \"text-neutral-900 dark:text-white\"\n                : \"text-neutral-400 dark:text-neutral-500\"\n            )}\n          />\n\n          <input\n            ref={inputRef}\n            type=\"search\"\n            value={query}\n            onFocus={() => setIsActive(true)}\n            onChange={(e) => setQuery(e.target.value)}\n            onKeyDown={(e) => {\n              if (e.key === \"Escape\") {\n                handleCancel();\n              }\n            }}\n            placeholder={placeholder}\n            className=\"w-full bg-transparent text-xs font-medium text-neutral-950 placeholder:text-neutral-400 focus:outline-none dark:text-white dark:placeholder:text-neutral-500 sm:text-sm [&::-webkit-search-cancel-button]:hidden\"\n          />\n\n          {/* Clear Circle Button */}\n          <AnimatePresence>\n            {query.length > 0 && (\n              <motion.button\n                type=\"button\"\n                aria-label=\"Clear search query\"\n                initial={{ opacity: 0, scale: 0.7 }}\n                animate={{ opacity: 1, scale: 1 }}\n                exit={{ opacity: 0, scale: 0.7 }}\n                transition={{ duration: 0.12 }}\n                onMouseDown={(e) => e.preventDefault()}\n                onClick={() => setQuery(\"\")}\n                className=\"ml-1.5 flex h-5 w-5 shrink-0 items-center justify-center rounded-full bg-neutral-300/80 text-neutral-700 transition-colors hover:bg-neutral-400/80 dark:bg-neutral-800 dark:text-neutral-300 dark:hover:bg-neutral-700\"\n              >\n                <X className=\"h-3 w-3\" />\n              </motion.button>\n            )}\n          </AnimatePresence>\n        </motion.div>\n\n        {/* Sliding Cancel Button */}\n        <AnimatePresence initial={false}>\n          {showCancel && (\n            <motion.button\n              type=\"button\"\n              initial={\n                shouldReduceMotion\n                  ? { opacity: 0 }\n                  : { opacity: 0, x: 16, width: 0 }\n              }\n              animate={{ opacity: 1, x: 0, width: \"auto\" }}\n              exit={\n                shouldReduceMotion\n                  ? { opacity: 0 }\n                  : { opacity: 0, x: 16, width: 0 }\n              }\n              transition={{ type: \"spring\", stiffness: 420, damping: 32 }}\n              onClick={handleCancel}\n              className=\"shrink-0 overflow-hidden whitespace-nowrap text-xs font-semibold text-neutral-900 hover:underline dark:text-white sm:text-sm\"\n            >\n              Cancel\n            </motion.button>\n          )}\n        </AnimatePresence>\n      </div>\n\n      {/* Quick Suggestions Shelf when active */}\n      <AnimatePresence>\n        {showCancel && filteredSuggestions.length > 0 && (\n          <motion.div\n            initial={\n              shouldReduceMotion ? { opacity: 0 } : { opacity: 0, y: -6 }\n            }\n            animate={{ opacity: 1, y: 0 }}\n            exit={shouldReduceMotion ? { opacity: 0 } : { opacity: 0, y: -6 }}\n            transition={{ type: \"spring\", stiffness: 400, damping: 30 }}\n            className=\"mt-2.5 flex flex-wrap items-center gap-1.5\"\n          >\n            {filteredSuggestions.map((item) => (\n              <button\n                key={item}\n                type=\"button\"\n                onMouseDown={(e) => e.preventDefault()}\n                onClick={() => setQuery(item)}\n                className=\"inline-flex items-center gap-1 rounded-full border border-neutral-200 bg-white px-2.5 py-1 text-[11px] font-medium text-neutral-600 transition-colors hover:border-neutral-900 hover:text-neutral-950 dark:border-neutral-800 dark:bg-[#0A0A0A] dark:text-neutral-400 dark:hover:border-white dark:hover:text-white\"\n              >\n                <span>{item}</span>\n                <ArrowUpRight className=\"h-3 w-3 opacity-60\" />\n              </button>\n            ))}\n          </motion.div>\n        )}\n      </AnimatePresence>\n    </div>\n  );\n}\n\nexport default AppleSearchField;\n",
          "type": "registry:ui",
          "target": "components/ui/apple-search-field.tsx"
        },
        {
          "path": "lib/utils.ts",
          "content": "import { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...inputs: ClassValue[]) {\n  return twMerge(clsx(inputs));\n}\n\nexport async function copyToClipboard(text: string): Promise<boolean> {\n  if (typeof window === \"undefined\") return false;\n\n  try {\n    if (navigator.clipboard && window.isSecureContext) {\n      await navigator.clipboard.writeText(text);\n      return true;\n    }\n\n    const textArea = document.createElement(\"textarea\");\n    textArea.value = text;\n    textArea.style.position = \"fixed\";\n    textArea.style.left = \"-999999px\";\n    textArea.style.top = \"-999999px\";\n    document.body.appendChild(textArea);\n    textArea.focus();\n    textArea.select();\n    const succeeded = document.execCommand(\"copy\");\n    textArea.remove();\n    return succeeded;\n  } catch {\n    return false;\n  }\n}\n",
          "type": "registry:lib",
          "target": "lib/utils.ts"
        }
      ]
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "asteroid-field",
      "type": "registry:ui",
      "title": "Asteroid Field",
      "author": "Rishabh Bose <https://theb0se.vercel.app/>",
      "description": "Deep-space parallax asteroid field and meteor shower on Canvas 2D featuring procedural faceted rock polygons across three depth layers, crater shading, ambient dust motes, and high-speed bolide meteors.",
      "dependencies": [
        "lucide-react",
        "clsx",
        "tailwind-merge"
      ],
      "files": [
        {
          "path": "components/ui/asteroid-field.tsx",
          "content": "\"use client\";\n\nimport React, { useEffect, useRef, useState } from \"react\";\nimport { Sparkles, Wind, Sliders, Flame } from \"lucide-react\";\nimport { cn } from \"@/lib/utils\";\n\nexport type AsteroidColorTheme = \"basalt\" | \"ice\" | \"iron\";\n\nexport interface AsteroidFieldProps {\n  /** Total number of procedural 3D faceted asteroids across 3 parallax layers (default: 32) */\n  asteroidCount?: number;\n  /** Drift velocity multiplier (default: 1.0) */\n  speed?: number;\n  /** Trajectory angle in degrees (default: 18) */\n  angle?: number;\n  /** Spawn probability multiplier for high-speed glowing bolide meteors (default: 0.4) */\n  meteorFrequency?: number;\n  /** Mineral composition color palette (default: \"basalt\") */\n  colorTheme?: AsteroidColorTheme;\n  /** Optional foreground content rendered over the asteroid belt */\n  children?: React.ReactNode;\n  /** Additional CSS classes for the root container */\n  className?: string;\n}\n\ninterface Vec3 {\n  x: number;\n  y: number;\n  z: number;\n}\n\ninterface PolyFacet {\n  i0: number;\n  i1: number;\n  i2: number;\n  albedoVar: number;\n}\n\ninterface CraterPit {\n  facetIndex: number;\n  radius: number;\n}\n\ninterface Asteroid3D {\n  x: number;\n  y: number;\n  layer: 0 | 1 | 2; // 0 = far, 1 = mid, 2 = near\n  radius: number;\n  rotZ: number;\n  rotX: number;\n  rotSpeedZ: number;\n  rotSpeedX: number;\n  vertices: Vec3[];\n  outerCount: number;\n  facets: PolyFacet[];\n  craters: CraterPit[];\n  driftJitter: number;\n}\n\ninterface BolideSpark {\n  x: number;\n  y: number;\n  vx: number;\n  vy: number;\n  life: number;\n  maxLife: number;\n  size: number;\n}\n\ninterface SmokePuff {\n  x: number;\n  y: number;\n  radius: number;\n  alpha: number;\n}\n\ninterface BolideMeteor {\n  x: number;\n  y: number;\n  vx: number;\n  vy: number;\n  length: number;\n  life: number;\n  maxLife: number;\n  sparks: BolideSpark[];\n  smoke: SmokePuff[];\n}\n\ninterface DustMote {\n  x: number;\n  y: number;\n  size: number;\n  alpha: number;\n  depth: number;\n}\n\ninterface VolumetricDustCloud {\n  x: number;\n  y: number;\n  rx: number;\n  ry: number;\n  rotation: number;\n  alpha: number;\n  speedFactor: number;\n}\n\nconst THEME_PALETTES: Record<\n  AsteroidColorTheme,\n  {\n    label: string;\n    baseRgb: [number, number, number];\n    specRgb: [number, number, number];\n    shadowRgb: [number, number, number];\n    rimColor: string;\n    comaCore: string;\n    comaHalo: string;\n    plasmaTail: string;\n    sparkRgb: string;\n    nebulaRgb: string;\n  }\n> = {\n  basalt: {\n    label: \"Chondrite Basalt\",\n    baseRgb: [78, 92, 114],\n    specRgb: [165, 184, 208],\n    shadowRgb: [13, 18, 29],\n    rimColor: \"rgba(186, 208, 235, 0.55)\",\n    comaCore: \"#FFFFFF\",\n    comaHalo: \"56, 189, 248\",\n    plasmaTail: \"251, 146, 60\",\n    sparkRgb: \"253, 224, 71\",\n    nebulaRgb: \"56, 189, 248\",\n  },\n  ice: {\n    label: \"Kuiper Frost\",\n    baseRgb: [56, 142, 198],\n    specRgb: [218, 244, 255],\n    shadowRgb: [9, 32, 56],\n    rimColor: \"rgba(224, 242, 254, 0.72)\",\n    comaCore: \"#F0F9FF\",\n    comaHalo: \"125, 211, 252\",\n    plasmaTail: \"56, 189, 248\",\n    sparkRgb: \"186, 230, 253\",\n    nebulaRgb: \"125, 211, 252\",\n  },\n  iron: {\n    label: \"Ferrous Ore\",\n    baseRgb: [112, 96, 86],\n    specRgb: [224, 186, 152],\n    shadowRgb: [22, 17, 15],\n    rimColor: \"rgba(253, 186, 116, 0.62)\",\n    comaCore: \"#FFFBEB\",\n    comaHalo: \"251, 146, 60\",\n    plasmaTail: \"239, 68, 68\",\n    sparkRgb: \"253, 186, 116\",\n    nebulaRgb: \"249, 115, 22\",\n  },\n};\n\nexport function AsteroidField({\n  asteroidCount = 32,\n  speed = 1.0,\n  angle = 18,\n  meteorFrequency = 0.4,\n  colorTheme = \"basalt\",\n  children,\n  className,\n}: AsteroidFieldProps) {\n  const containerRef = useRef<HTMLDivElement>(null);\n  const canvasRef = useRef<HTMLCanvasElement>(null);\n\n  const [activeTheme, setActiveTheme] = useState<AsteroidColorTheme>(colorTheme);\n  const [activeSpeed, setActiveSpeed] = useState(speed);\n  const [activeAngle, setActiveAngle] = useState(angle);\n  const [activeMeteorFreq, setActiveMeteorFreq] = useState(meteorFrequency);\n  useEffect(() => {\n    setActiveTheme(colorTheme);\n  }, [colorTheme]);\n  useEffect(() => {\n    setActiveSpeed(speed);\n  }, [speed]);\n  useEffect(() => {\n    setActiveAngle(angle);\n  }, [angle]);\n  useEffect(() => {\n    setActiveMeteorFreq(meteorFrequency);\n  }, [meteorFrequency]);\n\n  const manualMeteorQueueRef = useRef(0);\n\n  useEffect(() => {\n    const container = containerRef.current;\n    const canvas = canvasRef.current;\n    if (!container || !canvas) return;\n\n    const ctx = canvas.getContext(\"2d\");\n    if (!ctx) return;\n\n    let width = container.clientWidth || 800;\n    let height = container.clientHeight || 520;\n    let dpr = Math.min(window.devicePixelRatio || 1, 2);\n\n    const resize = () => {\n      if (!container || !canvas) return;\n      width = container.clientWidth || 800;\n      height = container.clientHeight || 520;\n      dpr = Math.min(window.devicePixelRatio || 1, 2);\n      canvas.width = Math.floor(width * dpr);\n      canvas.height = Math.floor(height * dpr);\n      ctx.setTransform(dpr, 0, 0, dpr, 0, 0);\n    };\n\n    resize();\n    const observer = new ResizeObserver(resize);\n    observer.observe(container);\n\n    // Construct a 3D faceted polyhedral asteroid mesh (outer silhouette ring + inner ridge ring + apex crown)\n    const createAsteroid3D = (layer: 0 | 1 | 2): Asteroid3D => {\n      const baseRadius =\n        layer === 0\n          ? 8 + Math.random() * 10\n          : layer === 1\n          ? 18 + Math.random() * 18\n          : 34 + Math.random() * 26;\n\n      const N = layer === 0 ? 7 : layer === 1 ? 9 : 11;\n      const vertices: Vec3[] = [];\n\n      // 0..N-1: Outer equatorial craggy perimeter ring\n      for (let i = 0; i < N; i++) {\n        const a = (i / N) * Math.PI * 2 + (Math.random() - 0.5) * 0.18;\n        const r = baseRadius * (0.74 + Math.random() * 0.42);\n        const z = (Math.random() - 0.5) * baseRadius * 0.35;\n        vertices.push({ x: Math.cos(a) * r, y: Math.sin(a) * r, z });\n      }\n\n      // N..2N-1: Inner elevated ridge ring\n      for (let i = 0; i < N; i++) {\n        const a = ((i + 0.5) / N) * Math.PI * 2 + (Math.random() - 0.5) * 0.22;\n        const r = baseRadius * (0.32 + Math.random() * 0.25);\n        const z = baseRadius * (0.48 + Math.random() * 0.35);\n        vertices.push({ x: Math.cos(a) * r, y: Math.sin(a) * r, z });\n      }\n\n      // 2N: Central high crown peak\n      vertices.push({\n        x: (Math.random() - 0.5) * baseRadius * 0.18,\n        y: (Math.random() - 0.5) * baseRadius * 0.18,\n        z: baseRadius * (0.78 + Math.random() * 0.24),\n      });\n\n      const facets: PolyFacet[] = [];\n      for (let i = 0; i < N; i++) {\n        const next = (i + 1) % N;\n        // Outer slope triangle 1: Outer[i] -> Outer[next] -> Inner[i]\n        facets.push({\n          i0: i,\n          i1: next,\n          i2: N + i,\n          albedoVar: 0.9 + Math.random() * 0.2,\n        });\n        // Outer slope triangle 2: Outer[next] -> Inner[next] -> Inner[i]\n        facets.push({\n          i0: next,\n          i1: N + next,\n          i2: N + i,\n          albedoVar: 0.9 + Math.random() * 0.2,\n        });\n        // Crown cap triangle: Inner[i] -> Inner[next] -> Crown[2N]\n        facets.push({\n          i0: N + i,\n          i1: N + next,\n          i2: 2 * N,\n          albedoVar: 0.92 + Math.random() * 0.16,\n        });\n      }\n\n      const craterCount = layer === 0 ? 1 : layer === 1 ? 2 : 4;\n      const craters: CraterPit[] = Array.from({ length: craterCount }, () => ({\n        facetIndex: Math.floor(Math.random() * facets.length),\n        radius: baseRadius * (0.09 + Math.random() * 0.11),\n      }));\n\n      return {\n        x: Math.random() * width,\n        y: Math.random() * height,\n        layer,\n        radius: baseRadius,\n        rotZ: Math.random() * Math.PI * 2,\n        rotX: (Math.random() - 0.5) * 0.7,\n        rotSpeedZ: (Math.random() - 0.5) * (0.015 - layer * 0.003),\n        rotSpeedX: (Math.random() - 0.5) * 0.008,\n        vertices,\n        outerCount: N,\n        facets,\n        craters,\n        driftJitter: 0.85 + Math.random() * 0.3,\n      };\n    };\n\n    const count = Math.max(8, Math.min(90, asteroidCount));\n    const asteroids: Asteroid3D[] = [];\n    for (let i = 0; i < count; i++) {\n      const layer: 0 | 1 | 2 = i % 6 === 0 ? 2 : i % 2 === 0 ? 1 : 0;\n      asteroids.push(createAsteroid3D(layer));\n    }\n    asteroids.sort((a, b) => a.layer - b.layer);\n\n    // Volumetric background cosmic dust clouds\n    const dustClouds: VolumetricDustCloud[] = Array.from({ length: 7 }, () => ({\n      x: Math.random() * width,\n      y: Math.random() * height,\n      rx: 140 + Math.random() * 180,\n      ry: 65 + Math.random() * 95,\n      rotation: (Math.random() - 0.5) * 0.8,\n      alpha: 0.045 + Math.random() * 0.055,\n      speedFactor: 0.12 + Math.random() * 0.18,\n    }));\n\n    const dustMotes: DustMote[] = Array.from({ length: 120 }, () => ({\n      x: Math.random() * width,\n      y: Math.random() * height,\n      size: 0.45 + Math.random() * 1.4,\n      alpha: 0.15 + Math.random() * 0.6,\n      depth: 0.2 + Math.random() * 0.85,\n    }));\n\n    const meteors: BolideMeteor[] = [];\n\n    const spawnBolide = () => {\n      const rad = (activeAngle * Math.PI) / 180;\n      const spd = 11.5 + Math.random() * 6.5;\n      meteors.push({\n        x: Math.random() * width * 0.82,\n        y: -35,\n        vx: Math.cos(rad + 0.22) * spd,\n        vy: Math.sin(rad + 0.36) * spd + 4.2,\n        length: 95 + Math.random() * 90,\n        life: 0,\n        maxLife: 48 + Math.random() * 34,\n        sparks: [],\n        smoke: [],\n      });\n    };\n\n    // Fixed directional solar light vector (top-left grazing sun)\n    const sunDir: Vec3 = (() => {\n      const lx = -0.68;\n      const ly = -0.54;\n      const lz = 0.49;\n      const len = Math.hypot(lx, ly, lz);\n      return { x: lx / len, y: ly / len, z: lz / len };\n    })();\n\n    let rafId = 0;\n\n    const render = () => {\n      const palette = THEME_PALETTES[activeTheme] || THEME_PALETTES.basalt;\n      const rad = (activeAngle * Math.PI) / 180;\n      const dirX = Math.cos(rad);\n      const dirY = Math.sin(rad);\n\n      // Deep space background\n      ctx.fillStyle = \"#03050B\";\n      ctx.fillRect(0, 0, width, height);\n\n      // 1. Volumetric Mineral Dust Clouds\n      ctx.save();\n      ctx.globalCompositeOperation = \"screen\";\n      for (let i = 0; i < dustClouds.length; i++) {\n        const dc = dustClouds[i];\n        dc.x += dirX * dc.speedFactor * activeSpeed;\n        dc.y += dirY * dc.speedFactor * activeSpeed;\n\n        if (dc.x > width + dc.rx) dc.x = -dc.rx;\n        if (dc.x < -dc.rx) dc.x = width + dc.rx;\n        if (dc.y > height + dc.ry) dc.y = -dc.ry;\n        if (dc.y < -dc.ry) dc.y = height + dc.ry;\n\n        ctx.save();\n        ctx.translate(dc.x, dc.y);\n        ctx.rotate(dc.rotation);\n        const cGrad = ctx.createRadialGradient(0, 0, 10, 0, 0, dc.rx);\n        cGrad.addColorStop(\n          0,\n          `rgba(${palette.nebulaRgb}, ${(dc.alpha * 1.4).toFixed(3)})`\n        );\n        cGrad.addColorStop(\n          0.55,\n          `rgba(${palette.nebulaRgb}, ${(dc.alpha * 0.5).toFixed(3)})`\n        );\n        cGrad.addColorStop(1, \"rgba(0, 0, 0, 0)\");\n        ctx.fillStyle = cGrad;\n        ctx.beginPath();\n        ctx.ellipse(0, 0, dc.rx, dc.ry, 0, 0, Math.PI * 2);\n        ctx.fill();\n        ctx.restore();\n      }\n      ctx.restore();\n\n      // 2. Ambient Parallax Dust Motes & Background Stars\n      for (let i = 0; i < dustMotes.length; i++) {\n        const d = dustMotes[i];\n        d.x += dirX * d.depth * 0.35 * activeSpeed;\n        d.y += dirY * d.depth * 0.35 * activeSpeed;\n\n        if (d.x > width + 10) d.x = -10;\n        if (d.x < -10) d.x = width + 10;\n        if (d.y > height + 10) d.y = -10;\n        if (d.y < -10) d.y = height + 10;\n\n        ctx.fillStyle = `rgba(226, 232, 240, ${d.alpha.toFixed(3)})`;\n        ctx.beginPath();\n        ctx.arc(d.x, d.y, d.size, 0, Math.PI * 2);\n        ctx.fill();\n      }\n\n      // 3. Vaporizing Bolide Meteors (Ionized Coma, Fragmenting Sparks & Smoke Trail)\n      if (\n        manualMeteorQueueRef.current > 0 ||\n        Math.random() < 0.025 * activeMeteorFreq * Math.max(0.2, activeSpeed)\n      ) {\n        if (manualMeteorQueueRef.current > 0) {\n          manualMeteorQueueRef.current -= 1;\n        }\n        spawnBolide();\n      }\n\n      for (let i = meteors.length - 1; i >= 0; i--) {\n        const m = meteors[i];\n        m.x += m.vx;\n        m.y += m.vy;\n        m.life += 1;\n\n        const progress = m.life / m.maxLife;\n        const alpha = Math.sin(progress * Math.PI);\n\n        // Emit decaying atmospheric ablation smoke puffs along trajectory\n        if (m.life % 2 === 0) {\n          m.smoke.push({\n            x: m.x - m.vx * 0.4 + (Math.random() - 0.5) * 3,\n            y: m.y - m.vy * 0.4 + (Math.random() - 0.5) * 3,\n            radius: 3.5 + Math.random() * 3,\n            alpha: 0.22 * alpha,\n          });\n        }\n\n        // Emit fragmenting incandescent ember sparks\n        for (let s = 0; s < 2; s++) {\n          if (Math.random() < 0.75) {\n            m.sparks.push({\n              x: m.x,\n              y: m.y,\n              vx: m.vx * (0.25 + Math.random() * 0.3) + (Math.random() - 0.5) * 2.6,\n              vy: m.vy * (0.25 + Math.random() * 0.3) + (Math.random() - 0.5) * 2.6,\n              life: 0,\n              maxLife: 12 + Math.random() * 14,\n              size: 0.8 + Math.random() * 1.4,\n            });\n          }\n        }\n\n        // Render decaying smoke trail\n        for (let k = m.smoke.length - 1; k >= 0; k--) {\n          const sm = m.smoke[k];\n          sm.radius += 0.25;\n          sm.alpha *= 0.93;\n          if (sm.alpha <= 0.01) {\n            m.smoke.splice(k, 1);\n            continue;\n          }\n          ctx.fillStyle = `rgba(148, 163, 184, ${sm.alpha.toFixed(3)})`;\n          ctx.beginPath();\n          ctx.arc(sm.x, sm.y, sm.radius, 0, Math.PI * 2);\n          ctx.fill();\n        }\n\n        ctx.save();\n        ctx.globalCompositeOperation = \"lighter\";\n\n        // Render fragmenting ember sparks\n        for (let k = m.sparks.length - 1; k >= 0; k--) {\n          const sp = m.sparks[k];\n          sp.x += sp.vx;\n          sp.y += sp.vy;\n          sp.life += 1;\n          const spAlpha = (1 - sp.life / sp.maxLife) * alpha;\n          if (sp.life >= sp.maxLife) {\n            m.sparks.splice(k, 1);\n            continue;\n          }\n          ctx.fillStyle = `rgba(${palette.sparkRgb}, ${spAlpha.toFixed(3)})`;\n          ctx.beginPath();\n          ctx.arc(sp.x, sp.y, sp.size, 0, Math.PI * 2);\n          ctx.fill();\n        }\n\n        // Render ionized plasma tail\n        const norm = Math.hypot(m.vx, m.vy) || 1;\n        const tailX = m.x - (m.vx / norm) * m.length;\n        const tailY = m.y - (m.vy / norm) * m.length;\n\n        const mGrad = ctx.createLinearGradient(m.x, m.y, tailX, tailY);\n        mGrad.addColorStop(0, `rgba(255, 255, 255, ${alpha.toFixed(3)})`);\n        mGrad.addColorStop(\n          0.18,\n          `rgba(${palette.comaHalo}, ${(alpha * 0.9).toFixed(3)})`\n        );\n        mGrad.addColorStop(\n          0.48,\n          `rgba(${palette.plasmaTail}, ${(alpha * 0.65).toFixed(3)})`\n        );\n        mGrad.addColorStop(1, \"rgba(0, 0, 0, 0)\");\n\n        ctx.strokeStyle = mGrad;\n        ctx.lineWidth = 2.6;\n        ctx.lineCap = \"round\";\n        ctx.beginPath();\n        ctx.moveTo(m.x, m.y);\n        ctx.lineTo(tailX, tailY);\n        ctx.stroke();\n\n        // Glowing ionized bolide coma halo & incandescent head\n        const comaGrad = ctx.createRadialGradient(m.x, m.y, 0, m.x, m.y, 16);\n        comaGrad.addColorStop(0, `rgba(255, 255, 255, ${alpha.toFixed(3)})`);\n        comaGrad.addColorStop(\n          0.35,\n          `rgba(${palette.comaHalo}, ${(alpha * 0.72).toFixed(3)})`\n        );\n        comaGrad.addColorStop(1, \"rgba(0, 0, 0, 0)\");\n        ctx.fillStyle = comaGrad;\n        ctx.beginPath();\n        ctx.arc(m.x, m.y, 16, 0, Math.PI * 2);\n        ctx.fill();\n\n        ctx.fillStyle = palette.comaCore;\n        ctx.beginPath();\n        ctx.arc(m.x, m.y, 2.4, 0, Math.PI * 2);\n        ctx.fill();\n\n        ctx.restore();\n\n        if (m.life >= m.maxLife || m.x > width + 240 || m.y > height + 240) {\n          meteors.splice(i, 1);\n        }\n      }\n\n      // 4. Three-Layer Parallax 3D Polyhedral Asteroids with Per-Facet Normal Lighting\n      const layerSpeedMultipliers = [0.42, 1.0, 2.1];\n      const layerAlpha = [0.58, 0.88, 1.0];\n\n      for (let i = 0; i < asteroids.length; i++) {\n        const a = asteroids[i];\n        const lSpeed =\n          layerSpeedMultipliers[a.layer] * activeSpeed * a.driftJitter;\n\n        a.x += dirX * lSpeed;\n        a.y += dirY * lSpeed;\n        a.rotZ += a.rotSpeedZ * Math.max(0.25, activeSpeed);\n        a.rotX += a.rotSpeedX * Math.max(0.25, activeSpeed);\n\n        const pad = a.radius + 50;\n        if (a.x > width + pad) a.x = -pad;\n        if (a.x < -pad) a.x = width + pad;\n        if (a.y > height + pad) a.y = -pad;\n        if (a.y < -pad) a.y = height + pad;\n\n        // Transform 3D vertices by Z rotation + subtle X tumble\n        const cosZ = Math.cos(a.rotZ);\n        const sinZ = Math.sin(a.rotZ);\n        const tiltX = Math.sin(a.rotX) * 0.32;\n        const cosX = Math.cos(tiltX);\n        const sinX = Math.sin(tiltX);\n\n        const transformed: Vec3[] = a.vertices.map((v) => {\n          const rx = v.x * cosZ - v.y * sinZ;\n          const ry = v.x * sinZ + v.y * cosZ;\n          const rz = v.z;\n          return {\n            x: rx,\n            y: ry * cosX - rz * sinX,\n            z: ry * sinX + rz * cosX,\n          };\n        });\n\n        ctx.save();\n        ctx.translate(a.x, a.y);\n        ctx.globalAlpha = layerAlpha[a.layer];\n\n        // Render each triangular facet with true 3D surface normal dot product lighting\n        for (let f = 0; f < a.facets.length; f++) {\n          const facet = a.facets[f];\n          const v0 = transformed[facet.i0];\n          const v1 = transformed[facet.i1];\n          const v2 = transformed[facet.i2];\n\n          // Compute 3D edge vectors and surface normal\n          const ux = v1.x - v0.x;\n          const uy = v1.y - v0.y;\n          const uz = v1.z - v0.z;\n          const vx = v2.x - v0.x;\n          const vy = v2.y - v0.y;\n          const vz = v2.z - v0.z;\n\n          let nx = uy * vz - uz * vy;\n          let ny = uz * vx - ux * vz;\n          let nz = ux * vy - uy * vx;\n          const nLen = Math.hypot(nx, ny, nz) || 1;\n          nx /= nLen;\n          ny /= nLen;\n          nz /= nLen;\n\n          if (nz < 0) {\n            nx = -nx;\n            ny = -ny;\n            nz = -nz;\n          }\n\n          // Lambertian diffuse + specular mineral glint against sunDir\n          const ndotl = Math.max(\n            0,\n            nx * sunDir.x + ny * sunDir.y + nz * sunDir.z\n          );\n          const lit = Math.min(1, Math.pow(ndotl, 0.85) * facet.albedoVar);\n          const spec = Math.pow(Math.max(0, ndotl), 4.5) * 0.45;\n\n          const mixChannel = (cIdx: 0 | 1 | 2) => {\n            const shadow = palette.shadowRgb[cIdx];\n            const mid = palette.baseRgb[cIdx];\n            const hi = palette.specRgb[cIdx];\n            const baseMix =\n              lit < 0.45\n                ? shadow + (mid - shadow) * (lit / 0.45)\n                : mid + (hi - mid) * ((lit - 0.45) / 0.55);\n            return Math.min(255, Math.round(baseMix + spec * 90));\n          };\n\n          const rCol = mixChannel(0);\n          const gCol = mixChannel(1);\n          const bCol = mixChannel(2);\n\n          const colorStr = `rgb(${rCol}, ${gCol}, ${bCol})`;\n          ctx.fillStyle = colorStr;\n          ctx.strokeStyle = colorStr;\n          ctx.lineWidth = 0.65;\n          ctx.lineJoin = \"round\";\n\n          ctx.beginPath();\n          ctx.moveTo(v0.x, v0.y);\n          ctx.lineTo(v1.x, v1.y);\n          ctx.lineTo(v2.x, v2.y);\n          ctx.closePath();\n          ctx.fill();\n          ctx.stroke();\n        }\n\n        // Render recessed impact craters with opposite-side sunlit inner rim\n        for (let c = 0; c < a.craters.length; c++) {\n          const cr = a.craters[c];\n          const facet = a.facets[cr.facetIndex];\n          const v0 = transformed[facet.i0];\n          const v1 = transformed[facet.i1];\n          const v2 = transformed[facet.i2];\n          const cx = (v0.x + v1.x + v2.x) / 3;\n          const cy = (v0.y + v1.y + v2.y) / 3;\n\n          ctx.fillStyle = `rgba(${palette.shadowRgb[0]}, ${palette.shadowRgb[1]}, ${palette.shadowRgb[2]}, 0.78)`;\n          ctx.beginPath();\n          ctx.arc(cx, cy, cr.radius, 0, Math.PI * 2);\n          ctx.fill();\n\n          ctx.strokeStyle = palette.rimColor;\n          ctx.lineWidth = 0.9;\n          ctx.beginPath();\n          ctx.arc(cx, cy, cr.radius, -Math.PI * 0.2, Math.PI * 0.75);\n          ctx.stroke();\n        }\n\n        // Crisp specular rim-lighting on sunward silhouette edges\n        ctx.lineWidth = a.layer === 2 ? 1.5 : 1.0;\n        for (let s = 0; s < a.outerCount; s++) {\n          const p0 = transformed[s];\n          const p1 = transformed[(s + 1) % a.outerCount];\n          const edgeMidX = (p0.x + p1.x) * 0.5;\n          const edgeMidY = (p0.y + p1.y) * 0.5;\n          const edgeLen = Math.hypot(edgeMidX, edgeMidY) || 1;\n          const rimDot =\n            (edgeMidX / edgeLen) * sunDir.x + (edgeMidY / edgeLen) * sunDir.y;\n\n          if (rimDot > 0.15) {\n            ctx.strokeStyle = palette.rimColor;\n            ctx.beginPath();\n            ctx.moveTo(p0.x, p0.y);\n            ctx.lineTo(p1.x, p1.y);\n            ctx.stroke();\n          }\n        }\n\n        ctx.restore();\n      }\n\n      rafId = requestAnimationFrame(render);\n    };\n\n    rafId = requestAnimationFrame(render);\n\n    return () => {\n      cancelAnimationFrame(rafId);\n      observer.disconnect();\n    };\n  }, [asteroidCount, activeSpeed, activeAngle, activeMeteorFreq, activeTheme]);\n\n  return (\n    <div\n      ref={containerRef}\n      data-fullscreen-scroll\n      className={cn(\n        \"relative w-full min-h-[520px] overflow-hidden rounded-2xl bg-[#03050B] text-white select-none\",\n        className\n      )}\n    >\n      <canvas\n        ref={canvasRef}\n        aria-hidden=\"true\"\n        className=\"pointer-events-none absolute inset-0 h-full w-full\"\n      />\n\n      {children && (\n        <div className=\"relative z-10 flex min-h-[520px] w-full flex-col\">\n          {children}\n        </div>\n      )}\n    </div>\n  );\n}\n\nexport default AsteroidField;\n",
          "type": "registry:ui",
          "target": "components/ui/asteroid-field.tsx"
        },
        {
          "path": "lib/utils.ts",
          "content": "import { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...inputs: ClassValue[]) {\n  return twMerge(clsx(inputs));\n}\n\nexport async function copyToClipboard(text: string): Promise<boolean> {\n  if (typeof window === \"undefined\") return false;\n\n  try {\n    if (navigator.clipboard && window.isSecureContext) {\n      await navigator.clipboard.writeText(text);\n      return true;\n    }\n\n    const textArea = document.createElement(\"textarea\");\n    textArea.value = text;\n    textArea.style.position = \"fixed\";\n    textArea.style.left = \"-999999px\";\n    textArea.style.top = \"-999999px\";\n    document.body.appendChild(textArea);\n    textArea.focus();\n    textArea.select();\n    const succeeded = document.execCommand(\"copy\");\n    textArea.remove();\n    return succeeded;\n  } catch {\n    return false;\n  }\n}\n",
          "type": "registry:lib",
          "target": "lib/utils.ts"
        }
      ]
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "atmospheric-fog",
      "type": "registry:ui",
      "title": "Atmospheric Fog",
      "author": "Rishabh Bose <https://theb0se.vercel.app/>",
      "description": "Volumetric drifting fog and mist banks powered by a custom WebGL domain-warped FBM shader with multi-layer parallax across a moody moonlit depth gradient.",
      "dependencies": [
        "lucide-react",
        "clsx",
        "tailwind-merge"
      ],
      "files": [
        {
          "path": "components/ui/atmospheric-fog.tsx",
          "content": "\"use client\";\n\nimport React, { useEffect, useRef, useState } from \"react\";\nimport { CloudFog, Layers, Gauge, Droplets, RotateCcw } from \"lucide-react\";\nimport { cn } from \"@/lib/utils\";\n\nexport interface AtmosphericFogProps {\n  /** Volumetric mist opacity and thickness (0.1 to 1.5) */\n  density?: number;\n  /** Drift velocity multiplier */\n  speed?: number;\n  /** Primary mist bank color in hex */\n  fogColor?: string;\n  /** Deep sky / background color in hex */\n  backgroundColor?: string;\n  /** Number of parallax mist octaves/layers (1 to 6) */\n  layers?: number;\n  /** Optional foreground content */\n  children?: React.ReactNode;\n  /** Additional container classes */\n  className?: string;\n}\n\nfunction hexToRgbNormalized(hex: string): [number, number, number] {\n  const clean = hex.replace(\"#\", \"\").trim();\n  const full =\n    clean.length === 3\n      ? clean\n          .split(\"\")\n          .map((c) => c + c)\n          .join(\"\")\n      : clean;\n  const num = parseInt(full, 16);\n  if (Number.isNaN(num)) return [0.796, 0.835, 0.882];\n  return [\n    ((num >> 16) & 255) / 255,\n    ((num >> 8) & 255) / 255,\n    (num & 255) / 255,\n  ];\n}\n\nconst VERTEX_SHADER = `\nattribute vec2 a_position;\nvarying vec2 v_uv;\nvoid main() {\n  v_uv = a_position * 0.5 + 0.5;\n  gl_Position = vec4(a_position, 0.0, 1.0);\n}\n`;\n\nconst FRAGMENT_SHADER = `\nprecision highp float;\nvarying vec2 v_uv;\nuniform vec2 u_resolution;\nuniform float u_time;\nuniform float u_density;\nuniform float u_speed;\nuniform vec3 u_fogColor;\nuniform vec3 u_bgColor;\nuniform float u_layers;\nuniform vec2 u_pointer;\n\nfloat hash(vec2 p) {\n  p = fract(p * vec2(123.34, 456.21));\n  p += dot(p, p + 45.32);\n  return fract(p.x * p.y);\n}\n\n// Interleaved gradient noise for filmic 8-bit anti-banding dithering\nfloat ignDither(vec2 fragCoord) {\n  vec3 magic = vec3(0.06711056, 0.00583715, 52.9829189);\n  return fract(magic.z * fract(dot(fragCoord, magic.xy)));\n}\n\nfloat noise(vec2 p) {\n  vec2 i = floor(p);\n  vec2 f = fract(p);\n  vec2 u = f * f * (3.0 - 2.0 * f);\n  return mix(\n    mix(hash(i + vec2(0.0, 0.0)), hash(i + vec2(1.0, 0.0)), u.x),\n    mix(hash(i + vec2(0.0, 1.0)), hash(i + vec2(1.0, 1.0)), u.x),\n    u.y\n  );\n}\n\nfloat fbm(vec2 p) {\n  float value = 0.0;\n  float amp = 0.5;\n  mat2 rot = mat2(0.8, 0.6, -0.6, 0.8);\n  for (int i = 0; i < 5; i++) {\n    value += amp * noise(p);\n    p = rot * p * 2.03 + vec2(1.7, 9.2);\n    amp *= 0.5;\n  }\n  return value;\n}\n\nfloat ridgeHeight(float x, float seed, float baseH, float amp) {\n  float n1 = sin(x * 1.4 + seed) * 0.5 + cos(x * 2.7 - seed * 1.3) * 0.3;\n  float n2 = noise(vec2(x * 3.2 + seed * 4.0, seed)) * 0.45;\n  float n3 = noise(vec2(x * 7.5 - seed * 2.0, seed * 2.0)) * 0.18;\n  return baseH + (n1 + n2 + n3) * amp;\n}\n\nvoid main() {\n  vec2 uv = v_uv;\n  float aspect = u_resolution.x / max(u_resolution.y, 1.0);\n  vec2 p = vec2(uv.x * aspect, uv.y);\n\n  float t = u_time * 0.13 * u_speed;\n\n  // Base twilight sky gradient with moonlit zenith & crepuscular light shafts\n  vec3 zenith = u_bgColor * 0.68;\n  vec3 horizon = mix(u_bgColor, u_fogColor * 0.42, 0.48);\n  vec3 col = mix(horizon, zenith, pow(uv.y, 0.8));\n\n  vec2 lightPos = vec2(aspect * 0.72, 0.82);\n  float moonDist = length(p - lightPos);\n  float moonHalo = exp(-moonDist * 2.6) * 0.34;\n  col += u_fogColor * moonHalo;\n\n  // Soft diagonal crepuscular light shafts radiating from the moonlit sky\n  vec2 toLight = p - lightPos;\n  float rayAngle = atan(toLight.y, toLight.x);\n  float rays = sin(rayAngle * 14.0 + u_time * 0.15) * 0.5 + 0.5;\n  rays *= sin(rayAngle * 23.0 - u_time * 0.1) * 0.5 + 0.5;\n  float rayMask = exp(-moonDist * 1.45) * smoothstep(0.05, 0.85, uv.y);\n  col += u_fogColor * rays * rayMask * 0.14 * u_density;\n\n  // Interleave mountain valley ridges and domain-warped volumetric FBM mist banks\n  // from back (i = 0, distant high ridge) to front (i = u_layers - 1, low foreground ridge)\n  vec2 ptr = vec2(u_pointer.x * aspect, 1.0 - u_pointer.y);\n\n  for (int i = 0; i < 6; i++) {\n    if (float(i) >= u_layers) break;\n    float layerIdx = float(i);\n    float progress = layerIdx / max(u_layers - 1.0, 1.0);\n\n    // 1. Render mountain/valley ridge silhouette for this depth plane\n    float rBase = mix(0.48, 0.11, progress);\n    float rAmp = mix(0.14, 0.06, progress);\n    float rElev = ridgeHeight(p.x * (0.85 + layerIdx * 0.18), 1.7 + layerIdx * 3.9, rBase, rAmp);\n\n    float ridgeMask = smoothstep(rElev + 0.006, rElev - 0.006, uv.y);\n    // Distant ridges are hazier; near ridges are darker silhouettes\n    vec3 ridgeTint = mix(\n      mix(u_bgColor * 0.85, u_fogColor * 0.38, 0.45),\n      u_bgColor * 0.32,\n      progress\n    );\n    col = mix(col, ridgeTint, ridgeMask * 0.92);\n\n    // 2. Render domain-warped FBM mist bank weaving over and along this valley ridge\n    float depthScale = 1.0 + layerIdx * 0.48;\n    float driftDir = mod(layerIdx, 2.0) == 0.0 ? 1.0 : -0.78;\n    float layerSpeed = (0.35 + layerIdx * 0.24) * driftDir;\n\n    vec2 lp = p * vec2(1.25 * depthScale, 2.2 * depthScale);\n    lp.x += t * layerSpeed + layerIdx * 4.3;\n    lp.y += sin(t * 0.28 + layerIdx) * 0.1;\n\n    // Subtle pointer parting displacement\n    float dPtr = length(p - ptr);\n    lp += normalize(p - ptr + 0.001) * exp(-dPtr * 3.8) * 0.16;\n\n    vec2 q = vec2(\n      fbm(lp + vec2(0.0, 0.0) + 0.11 * t),\n      fbm(lp + vec2(5.2, 1.3) - 0.09 * t)\n    );\n    vec2 r = vec2(\n      fbm(lp + 2.6 * q + vec2(1.7, 9.2) + 0.14 * t),\n      fbm(lp + 2.6 * q + vec2(8.3, 2.8) + 0.1 * t)\n    );\n    float fbmVal = fbm(lp + 2.1 * r);\n\n    // Mist settles into the valley trough just around and below each ridge elevation\n    float mistTop = rElev + 0.18;\n    float mistBot = rElev - 0.26;\n    float valleyEnvelope = smoothstep(mistTop, rElev - 0.02, uv.y) * smoothstep(mistBot, rElev + 0.04, uv.y);\n\n    float billow = smoothstep(0.28, 0.8, fbmVal) * valleyEnvelope;\n    float mistAlpha = clamp(billow * u_density * (0.52 - progress * 0.05), 0.0, 0.88);\n\n    // Rim lighting on the top edge of the mist bank from the moonlit sky\n    float topHighlight = smoothstep(rElev - 0.04, mistTop, uv.y) * fbmVal;\n    vec3 mistLayerColor = mix(u_fogColor * 0.68, u_fogColor * 1.08, topHighlight);\n\n    col = mix(col, mistLayerColor, mistAlpha);\n  }\n\n  // Deep valley floor ground mist\n  float floorMist = smoothstep(0.22, 0.0, uv.y) * 0.34 * u_density;\n  col = mix(col, u_fogColor * 0.82, clamp(floorMist, 0.0, 0.82));\n\n  // Apply filmic interleaved gradient noise dithering to eliminate any 8-bit banding\n  float dither = (ignDither(gl_FragCoord.xy) - 0.5) / 255.0;\n  col += dither * 1.8;\n\n  gl_FragColor = vec4(clamp(col, 0.0, 1.0), 1.0);\n}\n`;\n\nconst FOG_PRESETS = [\n  { label: \"Moonlit Slate\", fog: \"#CBD5E1\", bg: \"#090D16\" },\n  { label: \"Nordic Pine\", fog: \"#99F6E4\", bg: \"#041318\" },\n  { label: \"Crimson Dusk\", fog: \"#FDA4AF\", bg: \"#160712\" },\n  { label: \"Golden Dawn\", fog: \"#FDE68A\", bg: \"#171008\" },\n];\n\nexport function AtmosphericFog({\n  density = 0.7,\n  speed = 1.0,\n  fogColor = \"#CBD5E1\",\n  backgroundColor = \"#090D16\",\n  layers = 4,\n  children,\n  className,\n}: AtmosphericFogProps) {\n  const containerRef = useRef<HTMLDivElement>(null);\n  const canvasRef = useRef<HTMLCanvasElement>(null);\n\n  const [simDensity, setSimDensity] = useState(density);\n  const [simSpeed, setSimSpeed] = useState(speed);\n  const [simFogColor, setSimFogColor] = useState(fogColor);\n  const [simBgColor, setSimBgColor] = useState(backgroundColor);\n  const [simLayers, setSimLayers] = useState(layers);\n\n  useEffect(() => setSimDensity(density), [density]);\n  useEffect(() => setSimSpeed(speed), [speed]);\n  useEffect(() => setSimFogColor(fogColor), [fogColor]);\n  useEffect(() => setSimBgColor(backgroundColor), [backgroundColor]);\n  useEffect(() => setSimLayers(layers), [layers]);\n\n  const pointerRef = useRef<{ x: number; y: number }>({ x: 0.5, y: 0.5 });\n  const paramsRef = useRef({\n    density: simDensity,\n    speed: simSpeed,\n    fogColor: simFogColor,\n    bgColor: simBgColor,\n    layers: simLayers,\n  });\n\n  useEffect(() => {\n    paramsRef.current = {\n      density: simDensity,\n      speed: simSpeed,\n      fogColor: simFogColor,\n      bgColor: simBgColor,\n      layers: simLayers,\n    };\n  }, [simDensity, simSpeed, simFogColor, simBgColor, simLayers]);\n\n  useEffect(() => {\n    const container = containerRef.current;\n    const canvas = canvasRef.current;\n    if (!container || !canvas) return;\n\n    const gl = canvas.getContext(\"webgl\", {\n      alpha: false,\n      antialias: false,\n      preserveDrawingBuffer: false,\n    });\n\n    if (!gl) return;\n\n    const compileShader = (type: number, source: string) => {\n      const shader = gl.createShader(type);\n      if (!shader) return null;\n      gl.shaderSource(shader, source);\n      gl.compileShader(shader);\n      if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {\n        gl.deleteShader(shader);\n        return null;\n      }\n      return shader;\n    };\n\n    const vs = compileShader(gl.VERTEX_SHADER, VERTEX_SHADER);\n    const fs = compileShader(gl.FRAGMENT_SHADER, FRAGMENT_SHADER);\n    if (!vs || !fs) return;\n\n    const program = gl.createProgram();\n    if (!program) return;\n    gl.attachShader(program, vs);\n    gl.attachShader(program, fs);\n    gl.linkProgram(program);\n    if (!gl.getProgramParameter(program, gl.LINK_STATUS)) return;\n\n    gl.useProgram(program);\n\n    const buffer = gl.createBuffer();\n    gl.bindBuffer(gl.ARRAY_BUFFER, buffer);\n    gl.bufferData(\n      gl.ARRAY_BUFFER,\n      new Float32Array([-1, -1, 1, -1, -1, 1, -1, 1, 1, -1, 1, 1]),\n      gl.STATIC_DRAW\n    );\n\n    const posLoc = gl.getAttribLocation(program, \"a_position\");\n    gl.enableVertexAttribArray(posLoc);\n    gl.vertexAttribPointer(posLoc, 2, gl.FLOAT, false, 0, 0);\n\n    const uRes = gl.getUniformLocation(program, \"u_resolution\");\n    const uTime = gl.getUniformLocation(program, \"u_time\");\n    const uDensity = gl.getUniformLocation(program, \"u_density\");\n    const uSpeed = gl.getUniformLocation(program, \"u_speed\");\n    const uFogColor = gl.getUniformLocation(program, \"u_fogColor\");\n    const uBgColor = gl.getUniformLocation(program, \"u_bgColor\");\n    const uLayers = gl.getUniformLocation(program, \"u_layers\");\n    const uPointer = gl.getUniformLocation(program, \"u_pointer\");\n\n    const updateSize = () => {\n      if (!container || !canvas) return;\n      const dpr = Math.min(window.devicePixelRatio || 1, 1.75);\n      const w = Math.max(1, Math.floor((container.clientWidth || 800) * dpr));\n      const h = Math.max(1, Math.floor((container.clientHeight || 520) * dpr));\n      canvas.width = w;\n      canvas.height = h;\n      gl.viewport(0, 0, w, h);\n    };\n\n    updateSize();\n    const observer = new ResizeObserver(updateSize);\n    observer.observe(container);\n\n    let rafId = 0;\n    const startTime = performance.now();\n\n    const render = (now: number) => {\n      const elapsed = (now - startTime) * 0.001;\n      const p = paramsRef.current;\n      const fogRgb = hexToRgbNormalized(p.fogColor);\n      const bgRgb = hexToRgbNormalized(p.bgColor);\n\n      gl.uniform2f(uRes, canvas.width, canvas.height);\n      gl.uniform1f(uTime, elapsed);\n      gl.uniform1f(uDensity, p.density);\n      gl.uniform1f(uSpeed, p.speed);\n      gl.uniform3f(uFogColor, fogRgb[0], fogRgb[1], fogRgb[2]);\n      gl.uniform3f(uBgColor, bgRgb[0], bgRgb[1], bgRgb[2]);\n      gl.uniform1f(uLayers, p.layers);\n      gl.uniform2f(uPointer, pointerRef.current.x, pointerRef.current.y);\n\n      gl.drawArrays(gl.TRIANGLES, 0, 6);\n      rafId = requestAnimationFrame(render);\n    };\n\n    rafId = requestAnimationFrame(render);\n\n    return () => {\n      cancelAnimationFrame(rafId);\n      observer.disconnect();\n      gl.deleteBuffer(buffer);\n      gl.deleteProgram(program);\n      gl.deleteShader(vs);\n      gl.deleteShader(fs);\n    };\n  }, []);\n\n  const handlePointerMove = (e: React.PointerEvent<HTMLDivElement>) => {\n    const rect = e.currentTarget.getBoundingClientRect();\n    pointerRef.current = {\n      x: (e.clientX - rect.left) / Math.max(rect.width, 1),\n      y: (e.clientY - rect.top) / Math.max(rect.height, 1),\n    };\n  };\n\n  const resetDefaults = () => {\n    setSimDensity(density);\n    setSimSpeed(speed);\n    setSimFogColor(fogColor);\n    setSimBgColor(backgroundColor);\n    setSimLayers(layers);\n  };\n\n  return (\n    <div\n      ref={containerRef}\n      data-fullscreen-scroll\n      onPointerMove={handlePointerMove}\n      className={cn(\n        \"relative w-full min-h-[520px] overflow-hidden rounded-2xl bg-[#090D16] text-slate-100 select-none\",\n        className\n      )}\n    >\n      <canvas\n        ref={canvasRef}\n        className=\"pointer-events-none absolute inset-0 h-full w-full\"\n      />\n\n      {children && (\n        <div className=\"relative z-10 flex min-h-[520px] w-full flex-col\">\n          {children}\n        </div>\n      )}\n    </div>\n  );\n}\n\nexport default AtmosphericFog;\n",
          "type": "registry:ui",
          "target": "components/ui/atmospheric-fog.tsx"
        },
        {
          "path": "lib/utils.ts",
          "content": "import { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...inputs: ClassValue[]) {\n  return twMerge(clsx(inputs));\n}\n\nexport async function copyToClipboard(text: string): Promise<boolean> {\n  if (typeof window === \"undefined\") return false;\n\n  try {\n    if (navigator.clipboard && window.isSecureContext) {\n      await navigator.clipboard.writeText(text);\n      return true;\n    }\n\n    const textArea = document.createElement(\"textarea\");\n    textArea.value = text;\n    textArea.style.position = \"fixed\";\n    textArea.style.left = \"-999999px\";\n    textArea.style.top = \"-999999px\";\n    document.body.appendChild(textArea);\n    textArea.focus();\n    textArea.select();\n    const succeeded = document.execCommand(\"copy\");\n    textArea.remove();\n    return succeeded;\n  } catch {\n    return false;\n  }\n}\n",
          "type": "registry:lib",
          "target": "lib/utils.ts"
        }
      ]
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "aurora-background",
      "type": "registry:ui",
      "title": "Aurora",
      "author": "Rishabh Bose <https://theb0se.vercel.app/>",
      "description": "macOS-inspired northern lights background using 3 to 5 large 60px blurred color blobs with screen blend mode drifting on offset keyframe loops.",
      "dependencies": [
        "lucide-react",
        "clsx",
        "tailwind-merge"
      ],
      "files": [
        {
          "path": "components/ui/aurora-background.tsx",
          "content": "\"use client\";\n\nimport React, { useState } from \"react\";\nimport { Sparkles } from \"lucide-react\";\nimport { cn } from \"@/lib/utils\";\n\nexport interface AuroraBackgroundProps {\n  /** Array of 3 to 5 aurora blob colors */\n  colors?: string[];\n  /** Animation speed multiplier (1 = default). Default: 1 */\n  speed?: number;\n  /** Opacity/glow intensity from 0.2 to 1. Default: 0.75 */\n  intensity?: number;\n  /** Optional foreground content */\n  children?: React.ReactNode;\n  className?: string;\n}\n\nconst DEFAULT_COLORS = [\n  \"#10B981\", // Emerald green\n  \"#06B6D4\", // Teal / Cyan\n  \"#8B5CF6\", // Violet\n  \"#3B82F6\", // Royal blue\n];\n\nconst PALETTE_PRESETS: Record<string, string[]> = {\n  Borealis: [\"#10B981\", \"#06B6D4\", \"#8B5CF6\", \"#3B82F6\"],\n  Sonoma: [\"#EC4899\", \"#8B5CF6\", \"#06B6D4\", \"#F59E0B\"],\n  Polar: [\"#2DD4BF\", \"#38BDF8\", \"#818CF8\", \"#C084FC\"],\n};\n\nexport function AuroraBackground({\n  colors = DEFAULT_COLORS,\n  speed = 1,\n  intensity = 0.75,\n  children,\n  className,\n}: AuroraBackgroundProps) {\n  const [activePreset, setActivePreset] = useState<string>(\"Borealis\");\n  const [customColors, setCustomColors] = useState<string[]>(colors);\n\n  const activeColors =\n     customColors.length >= 3 ? customColors : DEFAULT_COLORS;\n  const baseDuration = Math.max(4, 18 / Math.max(0.2, speed));\n\n  return (\n    <div\n      data-fullscreen-scroll\n      className={cn(\n        \"relative flex min-h-[360px] w-full flex-col justify-between overflow-hidden rounded-3xl border border-neutral-800 bg-[#04060E] p-6 text-white shadow-sm\",\n        className\n      )}\n    >\n      <style>{`\n        @keyframes bose-aurora-1 {\n          0%, 100% { transform: translate(0%, 0%) scale(1) rotate(0deg); }\n          33% { transform: translate(18%, -14%) scale(1.18) rotate(12deg); }\n          66% { transform: translate(-12%, 12%) scale(0.92) rotate(-8deg); }\n        }\n        @keyframes bose-aurora-2 {\n          0%, 100% { transform: translate(0%, 0%) scale(1.05) rotate(0deg); }\n          50% { transform: translate(-22%, 16%) scale(1.22) rotate(-15deg); }\n        }\n        @keyframes bose-aurora-3 {\n          0%, 100% { transform: translate(0%, 0%) scale(0.95); }\n          40% { transform: translate(15%, 20%) scale(1.15); }\n          80% { transform: translate(-16%, -12%) scale(1.05); }\n        }\n      `}</style>\n\n      {/* Blurred Screen-Blended Aurora Blobs */}\n      <div\n        aria-hidden=\"true\"\n        style={{ opacity: Math.max(0.15, Math.min(1, intensity)) }}\n        className=\"pointer-events-none absolute inset-0 overflow-hidden\"\n      >\n        {activeColors.map((color, idx) => {\n          const animName = `bose-aurora-${(idx % 3) + 1}`;\n          const duration = baseDuration + idx * 3.5;\n          const positions = [\n            \"left-[-10%] top-[-15%] h-[280px] w-[420px]\",\n            \"right-[-10%] top-[5%] h-[300px] w-[440px]\",\n            \"bottom-[-20%] left-[15%] h-[320px] w-[480px]\",\n            \"bottom-[5%] right-[10%] h-[260px] w-[380px]\",\n          ];\n\n          return (\n            <div\n              key={idx}\n              style={{\n                background: `radial-gradient(ellipse at center, ${color} 0%, transparent 70%)`,\n                filter: \"blur(60px)\",\n                mixBlendMode: \"screen\",\n                animation: `${animName} ${duration}s ease-in-out infinite`,\n                animationDelay: `${idx * -2.5}s`,\n              }}\n              className={cn(\n                \"absolute rounded-full\",\n                positions[idx % positions.length]\n              )}\n            />\n          );\n        })}\n      </div>\n\n      {/* Subtle Vignette */}\n      <div\n        aria-hidden=\"true\"\n        className=\"pointer-events-none absolute inset-0 bg-gradient-to-t from-[#04060E] via-transparent to-[#04060E]/60\"\n      />\n\n      {/* Foreground Content */}\n      <div className=\"relative z-10 flex flex-1 flex-col justify-between\">\n        {children ?? (\n          <>\n            <div className=\"flex flex-wrap items-center justify-between gap-2\">\n              <span className=\"inline-flex items-center gap-1.5 rounded-full border border-white/15 bg-white/10 px-3 py-1 font-mono text-[11px] font-medium text-white backdrop-blur-md\">\n                <Sparkles className=\"h-3.5 w-3.5 text-emerald-300\" />\n                Aurora · Screen Blend\n              </span>\n\n              <div className=\"flex items-center gap-1 rounded-full border border-white/15 bg-black/40 p-1 backdrop-blur-md\">\n                {Object.keys(PALETTE_PRESETS).map((name) => (\n                  <button\n                    key={name}\n                    type=\"button\"\n                    onClick={() => {\n                      setActivePreset(name);\n                      setCustomColors(PALETTE_PRESETS[name]);\n                    }}\n                    className={cn(\n                      \"rounded-full px-2.5 py-0.5 font-mono text-[10px] font-semibold transition-colors\",\n                      activePreset === name\n                        ? \"bg-white text-black\"\n                        : \"text-white/75 hover:text-white\"\n                    )}\n                  >\n                    {name}\n                  </button>\n                ))}\n              </div>\n            </div>\n\n            <div className=\"my-auto max-w-md py-8\">\n              <h3 className=\"text-2xl font-bold tracking-tight text-white sm:text-3xl\">\n                Northern Lights Diffusion\n              </h3>\n              <p className=\"mt-2 text-xs leading-relaxed text-white/75 sm:text-sm\">\n                Multi-layered radial blobs with 60px Gaussian blur and{\" \"}\n                <code className=\"font-mono text-white\">mix-blend-mode: screen</code>{\" \"}\n                drifting on offset harmonic keyframe loops.\n              </p>\n            </div>\n\n            {/* Color Swatches */}\n            <div className=\"flex items-center gap-2\">\n              {activeColors.map((col, i) => (\n                <span\n                  key={i}\n                  style={{ backgroundColor: col }}\n                  className=\"h-4 w-4 rounded-full border border-white/30 shadow-sm\"\n                  title={col}\n                />\n              ))}\n              <span className=\"ml-1 font-mono text-[11px] text-white/60\">\n                {activeColors.join(\" · \")}\n              </span>\n            </div>\n          </>\n        )}\n      </div>\n    </div>\n  );\n}\n\nexport default AuroraBackground;\n",
          "type": "registry:ui",
          "target": "components/ui/aurora-background.tsx"
        },
        {
          "path": "lib/utils.ts",
          "content": "import { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...inputs: ClassValue[]) {\n  return twMerge(clsx(inputs));\n}\n\nexport async function copyToClipboard(text: string): Promise<boolean> {\n  if (typeof window === \"undefined\") return false;\n\n  try {\n    if (navigator.clipboard && window.isSecureContext) {\n      await navigator.clipboard.writeText(text);\n      return true;\n    }\n\n    const textArea = document.createElement(\"textarea\");\n    textArea.value = text;\n    textArea.style.position = \"fixed\";\n    textArea.style.left = \"-999999px\";\n    textArea.style.top = \"-999999px\";\n    document.body.appendChild(textArea);\n    textArea.focus();\n    textArea.select();\n    const succeeded = document.execCommand(\"copy\");\n    textArea.remove();\n    return succeeded;\n  } catch {\n    return false;\n  }\n}\n",
          "type": "registry:lib",
          "target": "lib/utils.ts"
        }
      ]
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "aurora-flux-surface",
      "type": "registry:ui",
      "title": "Aurora Flux Surface",
      "author": "Rishabh Bose <https://theb0se.vercel.app/>",
      "description": "GPU-composited ambient aurora canvas where dual radial luminance fields with contrasting spring mass chase the pointer.",
      "dependencies": [
        "framer-motion",
        "lucide-react",
        "clsx",
        "tailwind-merge"
      ],
      "files": [
        {
          "path": "components/ui/aurora-flux-surface.tsx",
          "content": "\"use client\";\n\nimport React, { useRef } from \"react\";\nimport {\n  motion,\n  useMotionTemplate,\n  useMotionValue,\n  useSpring,\n  useReducedMotion,\n} from \"framer-motion\";\nimport { Sparkles } from \"lucide-react\";\nimport { cn } from \"@/lib/utils\";\n\nexport interface AuroraFluxSurfaceProps {\n  /** Radius of the primary luminance orb in pixels. Default: 260 */\n  orbRadius?: number;\n  /** Spring stiffness coefficient for the leading aurora orb. Default: 180 */\n  stiffness?: number;\n  /** Spring damping coefficient for the leading aurora orb. Default: 24 */\n  damping?: number;\n  /** Optional foreground content */\n  children?: React.ReactNode;\n  className?: string;\n}\n\nexport function AuroraFluxSurface({\n  orbRadius = 260,\n  stiffness = 180,\n  damping = 24,\n  children,\n  className,\n}: AuroraFluxSurfaceProps) {\n  const containerRef = useRef<HTMLDivElement | null>(null);\n  const shouldReduceMotion = useReducedMotion() ?? false;\n\n  const mouseX = useMotionValue(200);\n  const mouseY = useMotionValue(115);\n\n  // Primary low-mass orb\n  const orb1X = useSpring(mouseX, { stiffness, damping, mass: 0.4 });\n  const orb1Y = useSpring(mouseY, { stiffness, damping, mass: 0.4 });\n\n  // Secondary high-mass trailing orb\n  const orb2X = useSpring(mouseX, {\n    stiffness: Math.max(60, stiffness * 0.45),\n    damping: damping * 1.1,\n    mass: 1.4,\n  });\n  const orb2Y = useSpring(mouseY, {\n    stiffness: Math.max(60, stiffness * 0.45),\n    damping: damping * 1.1,\n    mass: 1.4,\n  });\n\n  const auroraGradient = useMotionTemplate`\n    radial-gradient(${orbRadius}px circle at ${orb1X}px ${orb1Y}px, rgba(120, 120, 120, 0.22), transparent 75%),\n    radial-gradient(${orbRadius * 1.25}px circle at ${orb2X}px ${orb2Y}px, rgba(160, 160, 160, 0.14), transparent 80%)\n  `;\n\n  const handleMouseMove = (e: React.MouseEvent<HTMLDivElement>) => {\n    if (shouldReduceMotion) return;\n    const el = containerRef.current;\n    if (!el) return;\n    const rect = el.getBoundingClientRect();\n    mouseX.set(e.clientX - rect.left);\n    mouseY.set(e.clientY - rect.top);\n  };\n\n  return (\n    <div\n      ref={containerRef}\n      onMouseMove={handleMouseMove}\n      className={cn(\n        \"relative flex min-h-[230px] w-full max-w-lg items-center justify-center overflow-hidden rounded-2xl border border-neutral-200 bg-white p-8 dark:border-[#222222] dark:bg-[#0A0A0A]\",\n        className\n      )}\n    >\n      {/* Dual-Spring Coupled Luminance Field */}\n      <motion.div\n        aria-hidden=\"true\"\n        style={{ background: auroraGradient }}\n        className=\"pointer-events-none absolute inset-0\"\n      />\n\n      {/* Subtle architectural dot texture */}\n      <div\n        aria-hidden=\"true\"\n        className=\"pointer-events-none absolute inset-0 bg-[radial-gradient(#d4d4d4_1px,transparent_1px)] [background-size:20px_20px] opacity-45 dark:bg-[radial-gradient(#242424_1px,transparent_1px)]\"\n      />\n\n      <div className=\"relative z-10 text-center\">\n        {children || (\n          <div className=\"inline-flex flex-col items-center rounded-2xl border border-neutral-200/90 bg-white/85 px-5 py-3.5 shadow-sm backdrop-blur-md dark:border-[#262626] dark:bg-[#111111]/85\">\n            <span className=\"inline-flex items-center gap-1.5 font-mono text-[10px] font-semibold uppercase tracking-widest text-neutral-500\">\n              <Sparkles className=\"h-3.5 w-3.5 text-black dark:text-white\" />\n              Coupled Luminance Flux\n            </span>\n            <span className=\"mt-1 text-xs font-semibold text-black dark:text-white\">\n              Dual-mass radial aurora chasing pointer\n            </span>\n          </div>\n        )}\n      </div>\n    </div>\n  );\n}\n\nexport default AuroraFluxSurface;\n",
          "type": "registry:ui",
          "target": "components/ui/aurora-flux-surface.tsx"
        },
        {
          "path": "lib/utils.ts",
          "content": "import { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...inputs: ClassValue[]) {\n  return twMerge(clsx(inputs));\n}\n\nexport async function copyToClipboard(text: string): Promise<boolean> {\n  if (typeof window === \"undefined\") return false;\n\n  try {\n    if (navigator.clipboard && window.isSecureContext) {\n      await navigator.clipboard.writeText(text);\n      return true;\n    }\n\n    const textArea = document.createElement(\"textarea\");\n    textArea.value = text;\n    textArea.style.position = \"fixed\";\n    textArea.style.left = \"-999999px\";\n    textArea.style.top = \"-999999px\";\n    document.body.appendChild(textArea);\n    textArea.focus();\n    textArea.select();\n    const succeeded = document.execCommand(\"copy\");\n    textArea.remove();\n    return succeeded;\n  } catch {\n    return false;\n  }\n}\n",
          "type": "registry:lib",
          "target": "lib/utils.ts"
        }
      ]
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "autocomplete",
      "type": "registry:ui",
      "title": "Autocomplete",
      "author": "Rishabh Bose <https://theb0se.vercel.app/>",
      "description": "Customizable search combobox with instant filtering, grouped categories, keyboard navigation, and spring-animated dropdown results.",
      "dependencies": [
        "framer-motion",
        "lucide-react",
        "clsx",
        "tailwind-merge"
      ],
      "files": [
        {
          "path": "components/ui/autocomplete.tsx",
          "content": "\"use client\";\n\nimport React, { useState, useRef, useEffect, useMemo, useId } from \"react\";\nimport { AnimatePresence, motion, useReducedMotion } from \"framer-motion\";\nimport { Check, ChevronDown, Search, X } from \"lucide-react\";\nimport { cn } from \"@/lib/utils\";\n\nexport interface AutocompleteOption {\n  value: string;\n  label: string;\n  description?: string;\n  category?: string;\n  icon?: React.ReactNode;\n  disabled?: boolean;\n}\n\nexport interface AutocompleteProps {\n  /** Array of selectable options */\n  options?: AutocompleteOption[];\n  /** Currently selected value (controlled) */\n  value?: string;\n  /** Default selected value (uncontrolled) */\n  defaultValue?: string;\n  /** Callback fired when an option is selected */\n  onChange?: (value: string, option: AutocompleteOption | null) => void;\n  /** Input placeholder text */\n  placeholder?: string;\n  /** Optional label displayed above the control */\n  label?: string;\n  /** Text displayed when no options match the query */\n  emptyMessage?: string;\n  /** Allow clearing the current selection */\n  clearable?: boolean;\n  /** Disable the entire input */\n  disabled?: boolean;\n  /** Additional container class names */\n  className?: string;\n}\n\nconst DEFAULT_OPTIONS: AutocompleteOption[] = [\n  {\n    value: \"nextjs\",\n    label: \"Next.js 14\",\n    category: \"Frameworks\",\n    description: \"App Router, Server Components & Actions\",\n  },\n  {\n    value: \"react\",\n    label: \"React 18\",\n    category: \"Frameworks\",\n    description: \"Concurrent UI library with Hooks\",\n  },\n  {\n    value: \"tailwind\",\n    label: \"Tailwind CSS\",\n    category: \"Styling\",\n    description: \"Utility-first CSS framework\",\n  },\n  {\n    value: \"framer\",\n    label: \"Framer Motion\",\n    category: \"Animation\",\n    description: \"Production-ready spring physics for React\",\n  },\n  {\n    value: \"typescript\",\n    label: \"TypeScript\",\n    category: \"Language\",\n    description: \"Strongly typed JavaScript at any scale\",\n  },\n];\n\nexport function Autocomplete({\n  options = DEFAULT_OPTIONS,\n  value: controlledValue,\n  defaultValue = \"\",\n  onChange,\n  placeholder = \"Search options...\",\n  label,\n  emptyMessage = \"No matching results found.\",\n  clearable = true,\n  disabled = false,\n  className,\n}: AutocompleteProps) {\n  const shouldReduceMotion = useReducedMotion();\n  const listboxId = useId();\n  const [internalValue, setInternalValue] = useState(defaultValue);\n  const selectedValue =\n    controlledValue !== undefined ? controlledValue : internalValue;\n\n  const selectedOption = useMemo(\n    () => (options || []).find((o) => o.value === selectedValue) || null,\n    [options, selectedValue]\n  );\n\n  const [open, setOpen] = useState(false);\n  const [query, setQuery] = useState(\"\");\n  const [activeIndex, setActiveIndex] = useState(0);\n\n  const containerRef = useRef<HTMLDivElement>(null);\n  const inputRef = useRef<HTMLInputElement>(null);\n  const listRef = useRef<HTMLDivElement>(null);\n\n  const filteredOptions = useMemo(() => {\n    const safeOptions = options || [];\n    const q = query.trim().toLowerCase();\n    if (!q) return safeOptions;\n    return safeOptions.filter(\n      (opt) =>\n        opt.label.toLowerCase().includes(q) ||\n        opt.value.toLowerCase().includes(q) ||\n        (opt.description && opt.description.toLowerCase().includes(q)) ||\n        (opt.category && opt.category.toLowerCase().includes(q))\n    );\n  }, [options, query]);\n\n  const groupedOptions = useMemo(() => {\n    const groups = new Map<string, AutocompleteOption[]>();\n    for (const opt of filteredOptions) {\n      const cat = opt.category || \"Options\";\n      if (!groups.has(cat)) groups.set(cat, []);\n      groups.get(cat)!.push(opt);\n    }\n    return Array.from(groups.entries());\n  }, [filteredOptions]);\n\n  useEffect(() => {\n    setActiveIndex(0);\n  }, [query, open]);\n\n  useEffect(() => {\n    if (!open || !listRef.current) return;\n    const activeEl = listRef.current.querySelector<HTMLElement>(\n      `[data-option-index=\"${activeIndex}\"]`\n    );\n    activeEl?.scrollIntoView({ block: \"nearest\" });\n  }, [activeIndex, open]);\n\n  useEffect(() => {\n    if (!open) return;\n    const handleOutside = (e: MouseEvent) => {\n      if (\n        containerRef.current &&\n        !containerRef.current.contains(e.target as Node)\n      ) {\n        setOpen(false);\n        setQuery(\"\");\n      }\n    };\n    document.addEventListener(\"mousedown\", handleOutside);\n    return () => document.removeEventListener(\"mousedown\", handleOutside);\n  }, [open]);\n\n  const handleSelect = (opt: AutocompleteOption) => {\n    if (opt.disabled) return;\n    if (controlledValue === undefined) {\n      setInternalValue(opt.value);\n    }\n    onChange?.(opt.value, opt);\n    setOpen(false);\n    setQuery(\"\");\n  };\n\n  const handleClear = (e: React.MouseEvent) => {\n    e.stopPropagation();\n    if (controlledValue === undefined) {\n      setInternalValue(\"\");\n    }\n    onChange?.(\"\", null);\n    setQuery(\"\");\n    inputRef.current?.focus();\n  };\n\n  const handleKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {\n    if (!open && (e.key === \"ArrowDown\" || e.key === \"Enter\")) {\n      e.preventDefault();\n      setOpen(true);\n      return;\n    }\n\n    if (!open) return;\n\n    if (e.key === \"ArrowDown\") {\n      e.preventDefault();\n      setActiveIndex((prev) =>\n        filteredOptions.length > 0 ? (prev + 1) % filteredOptions.length : 0\n      );\n    } else if (e.key === \"ArrowUp\") {\n      e.preventDefault();\n      setActiveIndex((prev) =>\n        filteredOptions.length > 0\n          ? (prev - 1 + filteredOptions.length) % filteredOptions.length\n          : 0\n      );\n    } else if (e.key === \"Enter\") {\n      e.preventDefault();\n      const target = filteredOptions[activeIndex];\n      if (target && !target.disabled) {\n        handleSelect(target);\n      }\n    } else if (e.key === \"Escape\") {\n      e.preventDefault();\n      setOpen(false);\n      setQuery(\"\");\n      inputRef.current?.blur();\n    }\n  };\n\n  return (\n    <div ref={containerRef} className={cn(\"relative w-full max-w-sm\", className)}>\n      {label && (\n        <label className=\"mb-1.5 block text-xs font-medium text-neutral-700 dark:text-neutral-300\">\n          {label}\n        </label>\n      )}\n\n      {/* Input trigger container */}\n      <div\n        onClick={() => {\n          if (!disabled) {\n            setOpen(true);\n            inputRef.current?.focus();\n          }\n        }}\n        className={cn(\n          \"flex h-10 w-full items-center gap-2 rounded-xl border bg-white px-3 text-sm transition-colors dark:bg-[#0A0A0A]\",\n          open\n            ? \"border-black ring-2 ring-black/10 dark:border-white dark:ring-white/10\"\n            : \"border-neutral-200 hover:border-neutral-400 dark:border-[#262626] dark:hover:border-neutral-600\",\n          disabled && \"cursor-not-allowed opacity-50\"\n        )}\n      >\n        <Search className=\"h-3.5 w-3.5 shrink-0 text-neutral-400\" />\n\n        <input\n          ref={inputRef}\n          type=\"text\"\n          role=\"combobox\"\n          aria-expanded={open}\n          aria-autocomplete=\"list\"\n          aria-controls={listboxId}\n          disabled={disabled}\n          value={open ? query : selectedOption?.label || \"\"}\n          placeholder={selectedOption ? selectedOption.label : placeholder}\n          onChange={(e) => {\n            setQuery(e.target.value);\n            if (!open) setOpen(true);\n          }}\n          onFocus={() => !disabled && setOpen(true)}\n          onKeyDown={handleKeyDown}\n          className=\"h-full w-full bg-transparent text-xs text-black placeholder:text-neutral-400 focus:outline-none dark:text-white dark:placeholder:text-neutral-500\"\n        />\n\n        {clearable && selectedOption && !disabled && (\n          <button\n            type=\"button\"\n            onClick={handleClear}\n            aria-label=\"Clear selection\"\n            className=\"cursor-pointer rounded p-0.5 text-neutral-400 transition-colors hover:text-black dark:hover:text-white\"\n          >\n            <X className=\"h-3.5 w-3.5\" />\n          </button>\n        )}\n\n        <ChevronDown\n          className={cn(\n            \"h-3.5 w-3.5 shrink-0 text-neutral-400 transition-transform duration-200\",\n            open && \"rotate-180 text-black dark:text-white\"\n          )}\n        />\n      </div>\n\n      {/* Dropdown Listbox */}\n      <AnimatePresence>\n        {open && (\n          <motion.div\n            ref={listRef}\n            id={listboxId}\n            role=\"listbox\"\n            initial={\n              shouldReduceMotion ? { opacity: 0 } : { opacity: 0, y: -6, scale: 0.98 }\n            }\n            animate={\n              shouldReduceMotion ? { opacity: 1 } : { opacity: 1, y: 0, scale: 1 }\n            }\n            exit={\n              shouldReduceMotion ? { opacity: 0 } : { opacity: 0, y: -4, scale: 0.98 }\n            }\n            transition={{\n              type: \"spring\",\n              stiffness: 420,\n              damping: 28,\n            }}\n            className=\"absolute left-0 right-0 top-[calc(100%+6px)] z-50 max-h-60 overflow-y-auto rounded-xl border border-neutral-200 bg-white p-1.5 shadow-2xl dark:border-[#262626] dark:bg-[#0A0A0A]\"\n          >\n            {filteredOptions.length === 0 ? (\n              <div className=\"px-3 py-6 text-center text-xs text-neutral-500\">\n                {emptyMessage}\n              </div>\n            ) : (\n              groupedOptions.map(([category, items]) => (\n                <div key={category} className=\"mb-1 last:mb-0\">\n                  {groupedOptions.length > 1 && (\n                    <div className=\"px-2.5 py-1 font-mono text-[10px] uppercase tracking-wider text-neutral-400 dark:text-neutral-500\">\n                      {category}\n                    </div>\n                  )}\n                  {items.map((opt) => {\n                    const flatIndex = filteredOptions.indexOf(opt);\n                    const isActive = flatIndex === activeIndex;\n                    const isSelected = opt.value === selectedValue;\n\n                    return (\n                      <button\n                        key={opt.value}\n                        type=\"button\"\n                        role=\"option\"\n                        data-option-index={flatIndex}\n                        aria-selected={isSelected}\n                        disabled={opt.disabled}\n                        onMouseEnter={() => setActiveIndex(flatIndex)}\n                        onMouseDown={(e) => e.preventDefault()}\n                        onClick={() => handleSelect(opt)}\n                        className={cn(\n                          \"flex w-full cursor-pointer items-center justify-between gap-2 rounded-lg px-2.5 py-2 text-left text-xs transition-colors\",\n                          isActive\n                            ? \"bg-neutral-100 text-black dark:bg-[#161616] dark:text-white\"\n                            : \"text-neutral-700 dark:text-neutral-300\",\n                          opt.disabled && \"cursor-not-allowed opacity-40\"\n                        )}\n                      >\n                        <div className=\"min-w-0 flex-1\">\n                          <div className=\"flex items-center gap-2 font-medium\">\n                            {opt.icon && (\n                              <span className=\"shrink-0 text-neutral-400\">\n                                {opt.icon}\n                              </span>\n                            )}\n                            <span className=\"truncate\">{opt.label}</span>\n                          </div>\n                          {opt.description && (\n                            <p className=\"mt-0.5 truncate text-[11px] text-neutral-500 dark:text-neutral-400\">\n                              {opt.description}\n                            </p>\n                          )}\n                        </div>\n\n                        {isSelected && (\n                          <Check className=\"h-3.5 w-3.5 shrink-0 text-black dark:text-white\" />\n                        )}\n                      </button>\n                    );\n                  })}\n                </div>\n              ))\n            )}\n          </motion.div>\n        )}\n      </AnimatePresence>\n    </div>\n  );\n}\n\nexport default Autocomplete;\n",
          "type": "registry:ui",
          "target": "components/ui/autocomplete.tsx"
        },
        {
          "path": "lib/utils.ts",
          "content": "import { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...inputs: ClassValue[]) {\n  return twMerge(clsx(inputs));\n}\n\nexport async function copyToClipboard(text: string): Promise<boolean> {\n  if (typeof window === \"undefined\") return false;\n\n  try {\n    if (navigator.clipboard && window.isSecureContext) {\n      await navigator.clipboard.writeText(text);\n      return true;\n    }\n\n    const textArea = document.createElement(\"textarea\");\n    textArea.value = text;\n    textArea.style.position = \"fixed\";\n    textArea.style.left = \"-999999px\";\n    textArea.style.top = \"-999999px\";\n    document.body.appendChild(textArea);\n    textArea.focus();\n    textArea.select();\n    const succeeded = document.execCommand(\"copy\");\n    textArea.remove();\n    return succeeded;\n  } catch {\n    return false;\n  }\n}\n",
          "type": "registry:lib",
          "target": "lib/utils.ts"
        }
      ]
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "autoplay-story-carousel",
      "type": "registry:ui",
      "title": "Autoplay Story Carousel",
      "author": "Rishabh Bose <https://theb0se.vercel.app/>",
      "description": "Apple News and Instagram-style interactive story carousel featuring segmented pill progress bars, directional half-card tap navigation, hover-to-pause gestures, and fluid slide transitions.",
      "dependencies": [
        "framer-motion",
        "lucide-react",
        "clsx",
        "tailwind-merge"
      ],
      "files": [
        {
          "path": "components/ui/autoplay-story-carousel.tsx",
          "content": "\"use client\";\n\nimport React, { useState, useEffect, useRef, useCallback } from \"react\";\nimport { motion, AnimatePresence } from \"framer-motion\";\nimport {\n  Volume2,\n  VolumeX,\n  Pause,\n  Play,\n  ChevronLeft,\n  ChevronRight,\n  Sparkles,\n  ExternalLink,\n  Layers,\n} from \"lucide-react\";\nimport { cn } from \"@/lib/utils\";\n\nexport interface StorySlide {\n  id: string;\n  tag: string;\n  title: string;\n  subtitle: string;\n  accentColor: string;\n  gradient: string;\n  badge: string;\n  stats?: { label: string; value: string }[];\n  date: string;\n}\n\nexport interface AutoplayStoryCarouselProps {\n  /** List of story slides */\n  slides?: StorySlide[];\n  /** Duration in milliseconds per story slide */\n  duration?: number;\n  /** Initial slide index */\n  defaultIndex?: number;\n  /** Whether autoplay is initially running */\n  autoPlay?: boolean;\n  /** On slide change callback */\n  onSlideChange?: (index: number) => void;\n  /** Whether to show header bar (defaults to true) */\n  showHeader?: boolean;\n  /** Whether to show bottom controls bar (defaults to true) */\n  showControls?: boolean;\n  /** Container className */\n  className?: string;\n}\n\nconst DEFAULT_SLIDES: StorySlide[] = [\n  {\n    id: \"apple-intelligence\",\n    tag: \"Intelligence\",\n    title: \"Apple Intelligence Integrated\",\n    subtitle: \"Personal intelligence system combining generative AI models with deep personal context.\",\n    accentColor: \"#38BDF8\",\n    gradient: \"from-sky-500/30 via-indigo-500/20 to-purple-600/30\",\n    badge: \"iOS 18.2\",\n    date: \"October 2026\",\n    stats: [\n      { label: \"Neural Engine\", value: \"38 TOPS\" },\n      { label: \"Privacy Core\", value: \"On-Device\" },\n    ],\n  },\n  {\n    id: \"m4-max-silicon\",\n    tag: \"Silicon\",\n    title: \"M4 Max Hardware Raytracing\",\n    subtitle: \"Built on second-generation 3nm technology for extreme pro workflows and 3D rendering.\",\n    accentColor: \"#F59E0B\",\n    gradient: \"from-amber-500/30 via-orange-500/20 to-rose-600/30\",\n    badge: \"Apple Silicon\",\n    date: \"October 2026\",\n    stats: [\n      { label: \"Unified Memory\", value: \"Up to 128GB\" },\n      { label: \"Memory Bandwidth\", value: \"546 GB/s\" },\n    ],\n  },\n  {\n    id: \"spatial-computing\",\n    tag: \"visionOS\",\n    title: \"visionOS Spatial Computing\",\n    subtitle: \"Navigate using your eyes, hands, and voice with ultra-high-resolution custom micro-OLED displays.\",\n    accentColor: \"#EC4899\",\n    gradient: \"from-pink-500/30 via-rose-500/20 to-purple-600/30\",\n    badge: \"Spatial OS\",\n    date: \"October 2026\",\n    stats: [\n      { label: \"Display Clustered\", value: \"23M Pixels\" },\n      { label: \"Latency Response\", value: \"12ms Realtime\" },\n    ],\n  },\n  {\n    id: \"titanium-craft\",\n    tag: \"Design\",\n    title: \"Grade 5 Titanium Architecture\",\n    subtitle: \"Lightest, strongest Pro models ever created with micro-blasted continuous tactile rails.\",\n    accentColor: \"#10B981\",\n    gradient: \"from-emerald-500/30 via-teal-500/20 to-cyan-600/30\",\n    badge: \"Industrial Design\",\n    date: \"October 2026\",\n    stats: [\n      { label: \"Material Alloy\", value: \"Ti-6Al-4V\" },\n      { label: \"Thermal Band\", value: \"Sub-structure\" },\n    ],\n  },\n];\n\nexport function AutoplayStoryCarousel({\n  slides = DEFAULT_SLIDES,\n  duration = 5000,\n  defaultIndex = 0,\n  autoPlay = true,\n  onSlideChange,\n  showHeader = true,\n  showControls = true,\n  className,\n}: AutoplayStoryCarouselProps) {\n  const [currentIndex, setCurrentIndex] = useState(defaultIndex);\n  const [isPlaying, setIsPlaying] = useState(autoPlay);\n  const [isMuted, setIsMuted] = useState(true);\n  const [progress, setProgress] = useState(0);\n  const [slideDuration, setSlideDuration] = useState(duration);\n  const [direction, setDirection] = useState(1);\n\n  const isPausedRef = useRef(false);\n  const progressStartTimeRef = useRef(Date.now());\n  const elapsedBeforePauseRef = useRef(0);\n\n  const total = slides.length;\n  const currentSlide = slides[currentIndex];\n\n  const nextSlide = useCallback(() => {\n    setDirection(1);\n    setProgress(0);\n    elapsedBeforePauseRef.current = 0;\n    progressStartTimeRef.current = Date.now();\n    setCurrentIndex((prev) => {\n      const next = (prev + 1) % total;\n      onSlideChange?.(next);\n      return next;\n    });\n  }, [total, onSlideChange]);\n\n  const prevSlide = useCallback(() => {\n    setDirection(-1);\n    setProgress(0);\n    elapsedBeforePauseRef.current = 0;\n    progressStartTimeRef.current = Date.now();\n    setCurrentIndex((prev) => {\n      const next = (prev - 1 + total) % total;\n      onSlideChange?.(next);\n      return next;\n    });\n  }, [total, onSlideChange]);\n\n  // Autoplay ticker loop with high-resolution timestamp calculation\n  useEffect(() => {\n    if (!isPlaying) return;\n\n    let animId: number;\n    progressStartTimeRef.current = Date.now() - elapsedBeforePauseRef.current;\n\n    const loop = () => {\n      if (!isPausedRef.current) {\n        const elapsed = Date.now() - progressStartTimeRef.current;\n        const currentP = Math.min(100, (elapsed / slideDuration) * 100);\n        setProgress(currentP);\n\n        if (elapsed >= slideDuration) {\n          nextSlide();\n          return;\n        }\n      }\n      animId = requestAnimationFrame(loop);\n    };\n\n    animId = requestAnimationFrame(loop);\n    return () => cancelAnimationFrame(animId);\n  }, [currentIndex, isPlaying, slideDuration, nextSlide]);\n\n  const handlePointerDown = () => {\n    isPausedRef.current = true;\n    elapsedBeforePauseRef.current = (progress / 100) * slideDuration;\n  };\n\n  const handlePointerUp = () => {\n    isPausedRef.current = false;\n    progressStartTimeRef.current = Date.now() - elapsedBeforePauseRef.current;\n  };\n\n  const handleContainerClick = (e: React.MouseEvent<HTMLDivElement>) => {\n    const rect = e.currentTarget.getBoundingClientRect();\n    const clickX = e.clientX - rect.left;\n    if (clickX < rect.width * 0.4) {\n      prevSlide();\n    } else {\n      nextSlide();\n    }\n  };\n\n  // Jump to specific slide\n  const goToSlide = (index: number) => {\n    setDirection(index > currentIndex ? 1 : -1);\n    setProgress(0);\n    elapsedBeforePauseRef.current = 0;\n    progressStartTimeRef.current = Date.now();\n    setCurrentIndex(index);\n    onSlideChange?.(index);\n  };\n\n  // Slide transition variants\n  const slideVariants = {\n    enter: (dir: number) => ({\n      x: dir > 0 ? 120 : -120,\n      opacity: 0,\n      scale: 0.95,\n    }),\n    center: {\n      x: 0,\n      opacity: 1,\n      scale: 1,\n      transition: {\n        x: { type: \"spring\", stiffness: 350, damping: 30 },\n        opacity: { duration: 0.28 },\n        scale: { duration: 0.28 },\n      },\n    },\n    exit: (dir: number) => ({\n      x: dir > 0 ? -120 : 120,\n      opacity: 0,\n      scale: 0.95,\n      transition: {\n        x: { type: \"spring\", stiffness: 350, damping: 30 },\n        opacity: { duration: 0.22 },\n      },\n    }),\n  };\n\n  return (\n    <div\n      data-fullscreen-scroll\n      className={cn(\n        \"relative w-full min-h-[520px] overflow-hidden rounded-2xl border border-neutral-200/80 bg-[#07090E] p-6 text-neutral-100 shadow-2xl transition-all dark:border-neutral-800\",\n        className\n      )}\n    >\n      {/* Dynamic Ambient Background Bloom matching active slide accent */}\n      <div\n        className=\"pointer-events-none absolute inset-0 transition-all duration-700 opacity-30\"\n        style={{\n          background: `radial-gradient(circle 700px at 50% 40%, ${currentSlide.accentColor}, transparent 70%)`,\n        }}\n      />\n\n      {/* Top Header & Overview */}\n      {showHeader && (\n        <div className=\"relative z-10 flex flex-wrap items-center justify-between gap-4 border-b border-white/10 pb-4\">\n          <div>\n            <div className=\"inline-flex items-center gap-2 rounded-full border border-white/15 bg-white/10 px-3 py-1 text-xs font-medium text-white backdrop-blur-md\">\n              <Sparkles className=\"h-3 w-3 text-sky-400\" />\n              Apple News Interactive Stories\n            </div>\n            <h2 className=\"mt-2 text-xl font-semibold tracking-tight text-white\">\n              Autoplay Story Carousel\n            </h2>\n            <p className=\"text-xs text-neutral-400\">\n              Sequential progress bars, half-card tap navigation, hover pause, and sound controls\n            </p>\n          </div>\n\n          {/* Play/Pause & Sound Action Buttons */}\n          <div className=\"flex items-center gap-2\">\n            <button\n              type=\"button\"\n              onClick={() => setIsPlaying(!isPlaying)}\n              className=\"flex items-center gap-1.5 rounded-xl border border-white/15 bg-white/10 px-3 py-1.5 text-xs font-medium text-white shadow-sm backdrop-blur-md transition hover:bg-white/20 active:scale-95\"\n              aria-label={isPlaying ? \"Pause story autoplay\" : \"Play story autoplay\"}\n            >\n              {isPlaying ? (\n                <>\n                  <Pause className=\"h-3.5 w-3.5\" />\n                  <span>Pause</span>\n                </>\n              ) : (\n                <>\n                  <Play className=\"h-3.5 w-3.5 text-emerald-400\" />\n                  <span>Play</span>\n                </>\n              )}\n            </button>\n\n            <button\n              type=\"button\"\n              onClick={() => setIsMuted(!isMuted)}\n              className={cn(\n                \"flex items-center gap-1.5 rounded-xl border px-3 py-1.5 text-xs font-medium backdrop-blur-md transition active:scale-95\",\n                !isMuted\n                  ? \"border-sky-500/50 bg-sky-500/20 text-sky-300\"\n                  : \"border-white/15 bg-white/10 text-neutral-300 hover:bg-white/20 hover:text-white\"\n              )}\n              aria-label={isMuted ? \"Unmute audio\" : \"Mute audio\"}\n            >\n              {!isMuted ? (\n                <>\n                  <Volume2 className=\"h-3.5 w-3.5 text-sky-400\" />\n                  <span>Audio On</span>\n                </>\n              ) : (\n                <>\n                  <VolumeX className=\"h-3.5 w-3.5 text-neutral-400\" />\n                  <span>Muted</span>\n                </>\n              )}\n            </button>\n          </div>\n        </div>\n      )}\n\n      {/* Main Interactive Story Card Frame */}\n      <div className=\"relative z-10 flex min-h-[360px] items-center justify-center py-6 select-none\">\n        <div\n          onMouseEnter={handlePointerDown}\n          onMouseLeave={handlePointerUp}\n          onMouseDown={handlePointerDown}\n          onMouseUp={handlePointerUp}\n          onClick={handleContainerClick}\n          className=\"group relative h-[360px] w-full max-w-md cursor-pointer overflow-hidden rounded-3xl border border-white/20 bg-neutral-900/90 shadow-[0_25px_60px_rgba(0,0,0,0.8)] backdrop-blur-xl ring-1 ring-white/10\"\n        >\n          {/* Top Sequential Pill Progress Bars */}\n          <div className=\"absolute inset-x-0 top-0 z-30 flex items-center gap-1.5 p-3.5\">\n            {slides.map((s, idx) => {\n              let fillPercent = 0;\n              if (idx < currentIndex) fillPercent = 100;\n              else if (idx === currentIndex) fillPercent = progress;\n\n              return (\n                <div\n                  key={s.id}\n                  onClick={(e) => {\n                    e.stopPropagation();\n                    goToSlide(idx);\n                  }}\n                  className=\"relative h-1 flex-1 overflow-hidden rounded-full bg-white/25 transition hover:h-1.5\"\n                >\n                  <div\n                    className=\"h-full rounded-full bg-white shadow-[0_0_8px_rgba(255,255,255,0.8)] transition-all ease-linear\"\n                    style={{\n                      width: `${fillPercent}%`,\n                      transitionDuration: idx === currentIndex ? \"50ms\" : \"0ms\",\n                    }}\n                  />\n                </div>\n              );\n            })}\n          </div>\n\n          {/* Left/Right Click Nav Hints */}\n          <div className=\"pointer-events-none absolute inset-y-0 left-0 flex w-16 items-center justify-start pl-2 z-20 opacity-0 transition-opacity group-hover:opacity-40\">\n            <ChevronLeft className=\"h-6 w-6 text-white\" />\n          </div>\n          <div className=\"pointer-events-none absolute inset-y-0 right-0 flex w-16 items-center justify-end pr-2 z-20 opacity-0 transition-opacity group-hover:opacity-40\">\n            <ChevronRight className=\"h-6 w-6 text-white\" />\n          </div>\n\n          {/* Fluid Slide Transitions Container */}\n          <AnimatePresence custom={direction} mode=\"wait\">\n            <motion.div\n              key={currentSlide.id}\n              custom={direction}\n              variants={slideVariants}\n              initial=\"enter\"\n              animate=\"center\"\n              exit=\"exit\"\n              className={cn(\n                \"relative flex h-full w-full flex-col justify-between p-7 pt-12\",\n                `bg-gradient-to-b ${currentSlide.gradient}`\n              )}\n            >\n              {/* Header Badges */}\n              <div className=\"flex items-center justify-between\">\n                <span className=\"rounded-full border border-white/20 bg-white/15 px-3 py-1 text-[11px] font-semibold uppercase tracking-wider text-white backdrop-blur-md\">\n                  {currentSlide.tag}\n                </span>\n\n                <span className=\"text-[11px] font-mono text-white/70\">\n                  {currentSlide.date}\n                </span>\n              </div>\n\n              {/* Main Content Body */}\n              <div className=\"space-y-3\">\n                <div className=\"inline-block rounded-md bg-white/10 px-2 py-0.5 text-[10px] font-mono text-white/90\">\n                  {currentSlide.badge}\n                </div>\n                <h3 className=\"text-2xl font-bold tracking-tight text-white drop-shadow\">\n                  {currentSlide.title}\n                </h3>\n                <p className=\"text-xs leading-relaxed text-white/80\">\n                  {currentSlide.subtitle}\n                </p>\n              </div>\n\n              {/* Slide Technical Metrics Footnote */}\n              {currentSlide.stats && (\n                <div className=\"grid grid-cols-2 gap-2 rounded-2xl border border-white/15 bg-black/40 p-3 backdrop-blur-md\">\n                  {currentSlide.stats.map((stat) => (\n                    <div key={stat.label}>\n                      <span className=\"block text-[9px] uppercase tracking-wider text-white/60\">\n                        {stat.label}\n                      </span>\n                      <span className=\"font-mono text-xs font-bold text-white\">\n                        {stat.value}\n                      </span>\n                    </div>\n                  ))}\n                </div>\n              )}\n            </motion.div>\n          </AnimatePresence>\n\n          {/* Hold to Pause Indicator Tag */}\n          <div className=\"pointer-events-none absolute bottom-2 inset-x-0 text-center opacity-0 transition-opacity group-hover:opacity-75 z-30\">\n            <span className=\"text-[10px] text-white/80 font-mono\">\n              Hold pointer to pause • Click left / right to skip\n            </span>\n          </div>\n        </div>\n      </div>\n\n      {/* Bottom Controls Bar */}\n      {showControls && (\n        <div className=\"relative z-10 mt-2 flex flex-wrap items-center justify-between gap-3 rounded-xl border border-white/10 bg-black/40 p-3.5 backdrop-blur-md\">\n          {/* Slide Duration Picker */}\n          <div className=\"flex items-center gap-2 text-xs\">\n            <span className=\"text-neutral-400\">Duration:</span>\n            {[3000, 5000, 8000].map((dur) => (\n              <button\n                key={dur}\n                type=\"button\"\n                onClick={() => setSlideDuration(dur)}\n                className={cn(\n                  \"rounded-lg px-2.5 py-1 text-xs font-medium transition\",\n                  slideDuration === dur\n                    ? \"bg-white/20 text-white shadow-sm ring-1 ring-white/20\"\n                    : \"text-neutral-400 hover:text-white\"\n                )}\n              >\n                {dur / 1000}s\n              </button>\n            ))}\n          </div>\n\n          {/* Slide Counter Dots */}\n          <div className=\"flex items-center gap-2\">\n            <span className=\"text-xs font-mono text-neutral-400\">\n              Story {currentIndex + 1} of {total}\n            </span>\n            <div className=\"flex items-center gap-1.5\">\n              {slides.map((_, i) => (\n                <button\n                  key={i}\n                  type=\"button\"\n                  onClick={() => goToSlide(i)}\n                  className={cn(\n                    \"h-1.5 rounded-full transition-all\",\n                    i === currentIndex\n                      ? \"w-5 bg-white shadow-sm\"\n                      : \"w-1.5 bg-white/30 hover:bg-white/60\"\n                  )}\n                  aria-label={`Jump to slide ${i + 1}`}\n                />\n              ))}\n            </div>\n          </div>\n        </div>\n      )}\n    </div>\n  );\n}\n\nexport default AutoplayStoryCarousel;\n",
          "type": "registry:ui",
          "target": "components/ui/autoplay-story-carousel.tsx"
        },
        {
          "path": "lib/utils.ts",
          "content": "import { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...inputs: ClassValue[]) {\n  return twMerge(clsx(inputs));\n}\n\nexport async function copyToClipboard(text: string): Promise<boolean> {\n  if (typeof window === \"undefined\") return false;\n\n  try {\n    if (navigator.clipboard && window.isSecureContext) {\n      await navigator.clipboard.writeText(text);\n      return true;\n    }\n\n    const textArea = document.createElement(\"textarea\");\n    textArea.value = text;\n    textArea.style.position = \"fixed\";\n    textArea.style.left = \"-999999px\";\n    textArea.style.top = \"-999999px\";\n    document.body.appendChild(textArea);\n    textArea.focus();\n    textArea.select();\n    const succeeded = document.execCommand(\"copy\");\n    textArea.remove();\n    return succeeded;\n  } catch {\n    return false;\n  }\n}\n",
          "type": "registry:lib",
          "target": "lib/utils.ts"
        }
      ]
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "avatar-stack-presence",
      "type": "registry:ui",
      "title": "Avatar Stack Presence",
      "author": "Rishabh Bose <https://theb0se.vercel.app/>",
      "description": "Slack and Figma-style overlapping user avatar stack with live online/idle/offline status indicator dots, +N overflow chip, rich member profile popover cards with timezone and quick ping, and full team drawer directory.",
      "dependencies": [
        "framer-motion",
        "lucide-react",
        "clsx",
        "tailwind-merge"
      ],
      "files": [
        {
          "path": "components/ui/avatar-stack-presence.tsx",
          "content": "\"use client\";\n\nimport React, { useState } from \"react\";\nimport { motion, AnimatePresence } from \"framer-motion\";\nimport {\n  Users,\n  Clock,\n  Send,\n  Plus,\n  Check,\n  Filter,\n  Sparkles,\n  X,\n  ExternalLink,\n} from \"lucide-react\";\nimport { cn } from \"@/lib/utils\";\n\nexport type PresenceStatus = \"online\" | \"idle\" | \"offline\";\n\nexport interface TeamMember {\n  id: string;\n  name: string;\n  role: string;\n  initials: string;\n  avatarBg: string;\n  status: PresenceStatus;\n  timezone: string;\n  recentActivity: string;\n}\n\nexport interface AvatarStackPresenceProps {\n  members?: TeamMember[];\n  maxVisible?: number;\n  size?: \"sm\" | \"md\" | \"lg\";\n  className?: string;\n}\n\nconst DEFAULT_MEMBERS: TeamMember[] = [\n  {\n    id: \"m-1\",\n    name: \"Alexander Vance\",\n    role: \"Staff Design Technologist\",\n    initials: \"AV\",\n    avatarBg: \"from-indigo-500 to-purple-600\",\n    status: \"online\",\n    timezone: \"San Francisco (UTC-7)\",\n    recentActivity: \"Editing design token repository\",\n  },\n  {\n    id: \"m-2\",\n    name: \"Elena Rostova\",\n    role: \"VP of Product Engineering\",\n    initials: \"ER\",\n    avatarBg: \"from-pink-500 to-rose-600\",\n    status: \"online\",\n    timezone: \"New York (UTC-4)\",\n    recentActivity: \"Reviewed smart contract telemetry\",\n  },\n  {\n    id: \"m-3\",\n    name: \"Marcus Chen\",\n    role: \"Lead Crypto Architect\",\n    initials: \"MC\",\n    avatarBg: \"from-cyan-500 to-blue-600\",\n    status: \"idle\",\n    timezone: \"Singapore (UTC+8)\",\n    recentActivity: \"Away for 20 minutes\",\n  },\n  {\n    id: \"m-4\",\n    name: \"Sarah Jenkins\",\n    role: \"Security & Auditing Lead\",\n    initials: \"SJ\",\n    avatarBg: \"from-emerald-500 to-teal-600\",\n    status: \"online\",\n    timezone: \"London (UTC+1)\",\n    recentActivity: \"Deployed v2.4 consensus bridge\",\n  },\n  {\n    id: \"m-5\",\n    name: \"Liam Vance\",\n    role: \"Mobile Platform Engineer\",\n    initials: \"LV\",\n    avatarBg: \"from-amber-500 to-orange-600\",\n    status: \"offline\",\n    timezone: \"Berlin (UTC+2)\",\n    recentActivity: \"Active 4 hours ago\",\n  },\n  {\n    id: \"m-6\",\n    name: \"Chloe Dupont\",\n    role: \"Fintech Compliance Strategist\",\n    initials: \"CD\",\n    avatarBg: \"from-violet-500 to-fuchsia-600\",\n    status: \"online\",\n    timezone: \"Paris (UTC+2)\",\n    recentActivity: \"Drafting SOC2 report\",\n  },\n  {\n    id: \"m-7\",\n    name: \"Daisuke Sato\",\n    role: \"High-Frequency Systems Core\",\n    initials: \"DS\",\n    avatarBg: \"from-red-500 to-rose-700\",\n    status: \"idle\",\n    timezone: \"Tokyo (UTC+9)\",\n    recentActivity: \"Benchmarking RPC endpoints\",\n  },\n];\n\nexport function AvatarStackPresence({\n  members: initialMembers = DEFAULT_MEMBERS,\n  maxVisible: initialMax = 5,\n  size = \"md\",\n  className,\n}: AvatarStackPresenceProps) {\n  const [members, setMembers] = useState<TeamMember[]>(initialMembers);\n  const [maxVisible, setMaxVisible] = useState(initialMax);\n  const [filterStatus, setFilterStatus] = useState<PresenceStatus | \"all\">(\"all\");\n  const [hoveredMember, setHoveredMember] = useState<TeamMember | null>(null);\n  const [isDrawerOpen, setIsDrawerOpen] = useState(false);\n  const [pingedUsers, setPingedUsers] = useState<Set<string>>(new Set());\n\n  // Filter members\n  const filteredMembers = members.filter((m) => {\n    if (filterStatus === \"all\") return true;\n    return m.status === filterStatus;\n  });\n\n  const visibleMembers = filteredMembers.slice(0, maxVisible);\n  const overflowCount = Math.max(0, filteredMembers.length - maxVisible);\n\n  // Size styling maps\n  const sizeClasses = {\n    sm: \"h-8 w-8 text-xs\",\n    md: \"h-10 w-10 text-sm\",\n    lg: \"h-12 w-12 text-base\",\n  }[size];\n\n  const dotSizeClasses = {\n    sm: \"h-2.5 w-2.5 border-[1.5px]\",\n    md: \"h-3 w-3 border-2\",\n    lg: \"h-3.5 w-3.5 border-2\",\n  }[size];\n\n  const handlePing = (id: string) => {\n    setPingedUsers((prev) => new Set(prev).add(id));\n    setTimeout(() => {\n      setPingedUsers((prev) => {\n        const next = new Set(prev);\n        next.delete(id);\n        return next;\n      });\n    }, 2000);\n  };\n\n  const getStatusColor = (status: PresenceStatus) => {\n    switch (status) {\n      case \"online\":\n        return \"bg-emerald-500\";\n      case \"idle\":\n        return \"bg-amber-400\";\n      case \"offline\":\n        return \"bg-neutral-500\";\n    }\n  };\n\n  const getStatusLabel = (status: PresenceStatus) => {\n    switch (status) {\n      case \"online\":\n        return \"Active Now\";\n      case \"idle\":\n        return \"Away / Idle\";\n      case \"offline\":\n        return \"Offline\";\n    }\n  };\n\n  return (\n    <div\n      data-fullscreen-scroll\n      className={cn(\n        \"relative w-full min-h-[520px] overflow-hidden rounded-2xl border border-neutral-200/80 bg-neutral-950 p-6 text-neutral-100 shadow-xl dark:border-neutral-800 flex flex-col justify-between\",\n        className\n      )}\n    >\n      {/* Background ambient lighting */}\n      <div className=\"pointer-events-none absolute -top-32 left-1/4 h-80 w-80 rounded-full bg-emerald-500/10 blur-[120px]\" />\n\n      {/* Top Header & Filter Controls */}\n      <div className=\"relative z-10 flex flex-col sm:flex-row items-start sm:items-center justify-between gap-4 border-b border-neutral-800/80 pb-4\">\n        <div className=\"flex items-center gap-2\">\n          <Users className=\"h-5 w-5 text-neutral-400\" />\n          <span className=\"font-semibold text-sm text-white\">\n            Team Presence Stack\n          </span>\n          <span className=\"rounded-full bg-neutral-800 border border-neutral-700/80 px-2 py-0.5 text-[10px] font-mono text-neutral-400\">\n            {members.filter((m) => m.status === \"online\").length} Online\n          </span>\n        </div>\n\n        {/* Filter Pills */}\n        <div className=\"flex items-center gap-1 rounded-xl border border-neutral-800 bg-neutral-900/90 p-1\">\n          {([\"all\", \"online\", \"idle\", \"offline\"] as const).map((st) => (\n            <button\n              key={st}\n              type=\"button\"\n              onClick={() => setFilterStatus(st)}\n              className={cn(\n                \"rounded-lg px-2.5 py-1 text-xs font-medium capitalize transition-colors\",\n                filterStatus === st\n                  ? \"bg-neutral-800 text-white font-semibold shadow-sm\"\n                  : \"text-neutral-400 hover:text-neutral-200\"\n              )}\n            >\n              {st}\n            </button>\n          ))}\n        </div>\n      </div>\n\n      {/* Center Interactive Avatar Stack Stage */}\n      <div className=\"relative my-10 flex flex-col items-center justify-center\">\n        <p className=\"mb-6 text-xs text-neutral-400 font-mono text-center\">\n          Hover individual avatars for detailed status cards • Click +N for full roster\n        </p>\n\n        {/* Overlapping Avatar Stack */}\n        <div className=\"relative flex items-center -space-x-3\">\n          {visibleMembers.map((member, idx) => (\n            <div\n              key={member.id}\n              className=\"relative group\"\n              onMouseEnter={() => setHoveredMember(member)}\n              onMouseLeave={() => setHoveredMember(null)}\n            >\n              <motion.div\n                whileHover={{ y: -6, scale: 1.12, zIndex: 30 }}\n                transition={{ type: \"spring\", stiffness: 450, damping: 25 }}\n                className={cn(\n                  \"relative rounded-full ring-2 ring-neutral-950 bg-gradient-to-tr p-0.5 cursor-pointer shadow-lg transition-shadow\",\n                  member.avatarBg,\n                  sizeClasses\n                )}\n              >\n                <div className=\"h-full w-full rounded-full bg-neutral-950 flex items-center justify-center font-bold font-mono text-white\">\n                  {member.initials}\n                </div>\n\n                {/* Status Dot Indicator */}\n                <span\n                  className={cn(\n                    \"absolute bottom-0 right-0 rounded-full border-neutral-950\",\n                    getStatusColor(member.status),\n                    dotSizeClasses,\n                    member.status === \"online\" && \"animate-pulse\"\n                  )}\n                />\n              </motion.div>\n\n              {/* Hover Popover Card */}\n              <AnimatePresence>\n                {hoveredMember?.id === member.id && (\n                  <motion.div\n                    initial={{ opacity: 0, y: 8, scale: 0.95 }}\n                    animate={{ opacity: 1, y: 0, scale: 1 }}\n                    exit={{ opacity: 0, scale: 0.95 }}\n                    transition={{ duration: 0.15 }}\n                    className=\"absolute bottom-full left-1/2 -translate-x-1/2 mb-3 z-40 w-64 rounded-2xl border border-neutral-700/80 bg-neutral-900/95 p-4 shadow-2xl backdrop-blur-xl\"\n                  >\n                    <div className=\"flex items-start justify-between\">\n                      <div className=\"flex items-center gap-2\">\n                        <div\n                          className={cn(\n                            \"h-9 w-9 rounded-full bg-gradient-to-tr flex items-center justify-center text-xs font-bold text-white shadow-inner\",\n                            member.avatarBg\n                          )}\n                        >\n                          {member.initials}\n                        </div>\n                        <div>\n                          <p className=\"font-semibold text-xs text-white\">\n                            {member.name}\n                          </p>\n                          <p className=\"text-[10px] text-neutral-400\">\n                            {member.role}\n                          </p>\n                        </div>\n                      </div>\n\n                      <span\n                        className={cn(\n                          \"inline-flex items-center gap-1 rounded-full px-2 py-0.5 text-[9px] font-semibold uppercase\",\n                          member.status === \"online\"\n                            ? \"bg-emerald-500/10 text-emerald-400 border border-emerald-500/20\"\n                            : member.status === \"idle\"\n                            ? \"bg-amber-500/10 text-amber-400 border border-amber-500/20\"\n                            : \"bg-neutral-800 text-neutral-400 border border-neutral-700\"\n                        )}\n                      >\n                        <span\n                          className={cn(\n                            \"h-1.5 w-1.5 rounded-full\",\n                            getStatusColor(member.status)\n                          )}\n                        />\n                        {getStatusLabel(member.status)}\n                      </span>\n                    </div>\n\n                    <div className=\"mt-3 space-y-1.5 border-t border-neutral-800 pt-2 text-[11px] text-neutral-300\">\n                      <div className=\"flex items-center gap-1.5 text-neutral-400\">\n                        <Clock className=\"h-3 w-3\" />\n                        <span>{member.timezone}</span>\n                      </div>\n                      <p className=\"text-[11px] text-neutral-300 italic\">\n                        \"{member.recentActivity}\"\n                      </p>\n                    </div>\n\n                    {/* Quick ping button */}\n                    <div className=\"mt-3 border-t border-neutral-800 pt-2 flex items-center justify-end\">\n                      <button\n                        type=\"button\"\n                        onClick={() => handlePing(member.id)}\n                        className=\"inline-flex items-center gap-1 rounded-lg bg-indigo-600 px-2.5 py-1 text-[11px] font-medium text-white hover:bg-indigo-500 transition-colors shadow-sm\"\n                      >\n                        {pingedUsers.has(member.id) ? (\n                          <>\n                            <Check className=\"h-3 w-3\" />\n                            <span>Pinged!</span>\n                          </>\n                        ) : (\n                          <>\n                            <Send className=\"h-3 w-3\" />\n                            <span>Send Ping</span>\n                          </>\n                        )}\n                      </button>\n                    </div>\n                  </motion.div>\n                )}\n              </AnimatePresence>\n            </div>\n          ))}\n\n          {/* +N Overflow Pill Chip */}\n          {overflowCount > 0 && (\n            <motion.button\n              whileHover={{ scale: 1.1, zIndex: 25 }}\n              whileTap={{ scale: 0.95 }}\n              type=\"button\"\n              onClick={() => setIsDrawerOpen(true)}\n              className={cn(\n                \"relative rounded-full ring-2 ring-neutral-950 bg-neutral-800 border border-neutral-700 font-mono font-bold text-neutral-200 flex items-center justify-center hover:bg-neutral-700 hover:text-white transition-colors cursor-pointer shadow-lg\",\n                sizeClasses\n              )}\n            >\n              +{overflowCount}\n            </motion.button>\n          )}\n        </div>\n      </div>\n\n      {/* Expanded Team Drawer Modal */}\n      <AnimatePresence>\n        {isDrawerOpen && (\n          <motion.div\n            initial={{ opacity: 0 }}\n            animate={{ opacity: 1 }}\n            exit={{ opacity: 0 }}\n            className=\"absolute inset-0 z-50 bg-neutral-950/80 backdrop-blur-md flex items-center justify-center p-6\"\n          >\n            <motion.div\n              initial={{ scale: 0.95, y: 10 }}\n              animate={{ scale: 1, y: 0 }}\n              exit={{ scale: 0.95, y: 10 }}\n              className=\"w-full max-w-md rounded-2xl border border-neutral-800 bg-neutral-900 p-5 shadow-2xl\"\n            >\n              <div className=\"flex items-center justify-between border-b border-neutral-800 pb-3\">\n                <div className=\"flex items-center gap-2\">\n                  <Users className=\"h-4 w-4 text-indigo-400\" />\n                  <span className=\"font-semibold text-sm text-white\">\n                    Full Team Directory ({filteredMembers.length})\n                  </span>\n                </div>\n                <button\n                  type=\"button\"\n                  onClick={() => setIsDrawerOpen(false)}\n                  className=\"rounded-lg p-1 text-neutral-400 hover:text-white hover:bg-neutral-800\"\n                >\n                  <X className=\"h-4 w-4\" />\n                </button>\n              </div>\n\n              <div className=\"mt-3 max-h-64 overflow-y-auto space-y-2 pr-1\">\n                {filteredMembers.map((m) => (\n                  <div\n                    key={m.id}\n                    className=\"flex items-center justify-between rounded-xl border border-neutral-800/80 bg-neutral-950/60 p-2.5\"\n                  >\n                    <div className=\"flex items-center gap-2.5\">\n                      <div\n                        className={cn(\n                          \"relative h-8 w-8 rounded-full bg-gradient-to-tr flex items-center justify-center text-xs font-bold text-white\",\n                          m.avatarBg\n                        )}\n                      >\n                        {m.initials}\n                        <span\n                          className={cn(\n                            \"absolute bottom-0 right-0 h-2.5 w-2.5 rounded-full border border-neutral-950\",\n                            getStatusColor(m.status)\n                          )}\n                        />\n                      </div>\n                      <div>\n                        <p className=\"text-xs font-semibold text-white\">\n                          {m.name}\n                        </p>\n                        <p className=\"text-[10px] text-neutral-400\">{m.role}</p>\n                      </div>\n                    </div>\n\n                    <button\n                      type=\"button\"\n                      onClick={() => handlePing(m.id)}\n                      className=\"rounded-md border border-neutral-800 bg-neutral-900 px-2 py-1 text-[10px] font-medium text-neutral-300 hover:bg-neutral-800 transition-colors\"\n                    >\n                      {pingedUsers.has(m.id) ? \"Sent ✓\" : \"Ping\"}\n                    </button>\n                  </div>\n                ))}\n              </div>\n            </motion.div>\n          </motion.div>\n        )}\n      </AnimatePresence>\n\n      {/* Footer Settings Bar */}\n      <div className=\"relative z-10 flex flex-wrap items-center justify-between gap-3 border-t border-neutral-800/80 pt-4 text-xs text-neutral-400\">\n        <div className=\"flex items-center gap-3\">\n          <span className=\"text-neutral-500 font-mono\">Visible Limit:</span>\n          {[3, 5, 7].map((num) => (\n            <button\n              key={num}\n              type=\"button\"\n              onClick={() => setMaxVisible(num)}\n              className={cn(\n                \"rounded px-2 py-0.5 text-xs font-mono transition-colors\",\n                maxVisible === num\n                  ? \"bg-neutral-800 text-white font-semibold\"\n                  : \"text-neutral-400 hover:text-neutral-200\"\n              )}\n            >\n              {num}\n            </button>\n          ))}\n        </div>\n\n        <button\n          type=\"button\"\n          onClick={() => {\n            const newMember: TeamMember = {\n              id: `m-${Date.now()}`,\n              name: \"Jordan Sparks\",\n              role: \"Design Systems Engineer\",\n              initials: \"JS\",\n              avatarBg: \"from-teal-500 to-emerald-600\",\n              status: \"online\",\n              timezone: \"Austin (UTC-5)\",\n              recentActivity: \"Joined the workspace session\",\n            };\n            setMembers((prev) => [...prev, newMember]);\n          }}\n          className=\"flex items-center gap-1 rounded-lg border border-neutral-800 bg-neutral-900 px-2.5 py-1 text-xs text-neutral-300 hover:bg-neutral-800 hover:text-white transition-colors\"\n        >\n          <Plus className=\"h-3.5 w-3.5\" />\n          <span>Add Teammate</span>\n        </button>\n      </div>\n    </div>\n  );\n}\n\nexport default AvatarStackPresence;\n",
          "type": "registry:ui",
          "target": "components/ui/avatar-stack-presence.tsx"
        },
        {
          "path": "lib/utils.ts",
          "content": "import { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...inputs: ClassValue[]) {\n  return twMerge(clsx(inputs));\n}\n\nexport async function copyToClipboard(text: string): Promise<boolean> {\n  if (typeof window === \"undefined\") return false;\n\n  try {\n    if (navigator.clipboard && window.isSecureContext) {\n      await navigator.clipboard.writeText(text);\n      return true;\n    }\n\n    const textArea = document.createElement(\"textarea\");\n    textArea.value = text;\n    textArea.style.position = \"fixed\";\n    textArea.style.left = \"-999999px\";\n    textArea.style.top = \"-999999px\";\n    document.body.appendChild(textArea);\n    textArea.focus();\n    textArea.select();\n    const succeeded = document.execCommand(\"copy\");\n    textArea.remove();\n    return succeeded;\n  } catch {\n    return false;\n  }\n}\n",
          "type": "registry:lib",
          "target": "lib/utils.ts"
        }
      ]
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "black-hole",
      "type": "registry:ui",
      "title": "Black Hole",
      "author": "Rishabh Bose <https://theb0se.vercel.app/>",
      "description": "Interstellar-inspired gravitational lensing black hole background powered by a WebGL relativistic ray-marching shader with a pitch-black event horizon, incandescent photon ring, bent upper and lower lensing arcs, and Doppler-beamed accretion plasma.",
      "dependencies": [
        "lucide-react",
        "clsx",
        "tailwind-merge"
      ],
      "files": [
        {
          "path": "components/ui/black-hole.tsx",
          "content": "\"use client\";\n\nimport React, { useEffect, useRef, useState } from \"react\";\nimport { Orbit, Sparkles, Sliders, RotateCcw } from \"lucide-react\";\nimport { cn } from \"@/lib/utils\";\n\nexport interface BlackHoleProps {\n  /** Radius of the central event horizon void in pixels (default: 95) */\n  size?: number;\n  /** Primary color of the relativistic accretion disk (default: \"#FF7A18\") */\n  diskColor?: string;\n  /** Angular velocity multiplier for orbiting matter (default: 1.2) */\n  spinSpeed?: number;\n  /** Filament density / particle resolution in the accretion disk (default: 260) */\n  particleCount?: number;\n  /** Radial inward gravitational pull rate & spacetime curvature (default: 0.35) */\n  pull?: number;\n  /** Whether to enable full relativistic gravitational lensing ray bending (default: true) */\n  lensing?: boolean;\n  /** Optional overlay content rendered above the canvas */\n  children?: React.ReactNode;\n  /** Additional CSS classes for the root container */\n  className?: string;\n}\n\nfunction hexToNormalizedRgb(hex: string): [number, number, number] {\n  const cleaned = hex.replace(\"#\", \"\").trim();\n  const full =\n    cleaned.length === 3\n      ? cleaned\n          .split(\"\")\n          .map((c) => c + c)\n          .join(\"\")\n      : cleaned.padEnd(6, \"0\").slice(0, 6);\n  const num = parseInt(full, 16);\n  if (Number.isNaN(num)) return [1.0, 0.48, 0.09];\n  return [\n    ((num >> 16) & 255) / 255,\n    ((num >> 8) & 255) / 255,\n    (num & 255) / 255,\n  ];\n}\n\nconst VERTEX_SHADER = `\nattribute vec2 a_position;\nvoid main() {\n  gl_Position = vec4(a_position, 0.0, 1.0);\n}\n`;\n\nconst FRAGMENT_SHADER = `\nprecision highp float;\n\nuniform vec2 u_resolution;\nuniform float u_time;\nuniform float u_size;\nuniform vec3 u_diskColor;\nuniform float u_spinSpeed;\nuniform float u_density;\nuniform float u_pull;\nuniform float u_lensing;\nuniform vec2 u_pointer;\n\nfloat hash21(vec2 p) {\n  p = fract(p * vec2(234.34, 435.345));\n  p += dot(p, p + 34.23);\n  return fract(p.x * p.y);\n}\n\nfloat noise(vec2 p) {\n  vec2 i = floor(p);\n  vec2 f = fract(p);\n  vec2 u = f * f * (3.0 - 2.0 * f);\n  return mix(\n    mix(hash21(i), hash21(i + vec2(1.0, 0.0)), u.x),\n    mix(hash21(i + vec2(0.0, 1.0)), hash21(i + vec2(1.0, 1.0)), u.x),\n    u.y\n  );\n}\n\nfloat fbm(vec2 p) {\n  float v = 0.0;\n  float a = 0.5;\n  mat2 rot = mat2(0.8, -0.6, 0.6, 0.8);\n  for (int i = 0; i < 5; i++) {\n    v += a * noise(p);\n    p = rot * p * 2.02 + vec2(13.4, 7.1);\n    a *= 0.5;\n  }\n  return v;\n}\n\n// Starfield lookup on escaped ray direction\nvec3 sampleStarfield(vec3 dir, float time) {\n  vec2 uv = vec2(atan(dir.z, dir.x) * 1.5, dir.y * 3.0);\n  vec2 grid = floor(uv * 28.0);\n  vec2 f = fract(uv * 28.0) - 0.5;\n  float rnd = hash21(grid);\n  vec3 stars = vec3(0.0);\n\n  if (rnd > 0.72) {\n    vec2 offset = (vec2(hash21(grid + 1.3), hash21(grid + 7.9)) - 0.5) * 0.65;\n    float d = length(f - offset);\n    float twinkle = 0.7 + 0.3 * sin(time * (1.5 + rnd * 4.0) + rnd * 6.28);\n    float star = smoothstep(0.18 * (rnd - 0.65), 0.0, d) * twinkle;\n    float core = exp(-d * 38.0) * twinkle;\n    vec3 tint = mix(vec3(0.75, 0.88, 1.0), vec3(1.0, 0.9, 0.75), fract(rnd * 13.7));\n    stars += tint * (star * 0.65 + core * 1.25);\n  }\n\n  // Subtle deep cosmic dust nebula\n  float neb = fbm(uv * 1.6 + vec2(0.2, -0.1));\n  stars += u_diskColor * pow(max(0.0, neb - 0.35), 2.4) * 0.14;\n  return stars;\n}\n\nvoid main() {\n  float minDim = min(u_resolution.x, u_resolution.y);\n  vec2 uv = (gl_FragCoord.xy - 0.5 * u_resolution.xy) / minDim;\n\n  // Map pixel size prop to normalized Schwarzschild horizon scale\n  float rScale = clamp(u_size / (minDim * 0.24), 0.45, 1.55);\n  uv /= rScale;\n\n  // Camera setup with subtle orbital tilt and roll (Interstellar Gargantua framing)\n  float rollAngle = -0.15 + u_pointer.x * 0.08;\n  float cRoll = cos(rollAngle);\n  float sRoll = sin(rollAngle);\n  uv = mat2(cRoll, -sRoll, sRoll, cRoll) * uv;\n\n  float camPitch = 0.145 + u_pointer.y * 0.06;\n  vec3 ro = vec3(0.0, sin(camPitch) * 6.2, -cos(camPitch) * 6.2);\n  vec3 forward = normalize(-ro);\n  vec3 right = normalize(cross(vec3(0.0, 1.0, 0.0), forward));\n  vec3 up = cross(forward, right);\n  vec3 rd = normalize(forward * 1.75 + right * uv.x + up * uv.y);\n\n  // Schwarzschild & Kerr relativistic ray marching parameters\n  float rs = 0.52; // Event horizon radius\n  float innerDisk = rs * 1.42; // ISCO (Innermost Stable Circular Orbit)\n  float outerDisk = rs * 6.8;\n  float gravStrength = mix(0.0, 0.195 * (0.75 + u_pull * 0.75), u_lensing);\n\n  vec3 pos = ro;\n  vec3 dir = rd;\n  vec3 accumGlow = vec3(0.0);\n  float transmittance = 1.0;\n  bool hitHorizon = false;\n  float minApproach = 100.0;\n\n  // Geodesic light-bending integration loop\n  for (int step = 0; step < 88; step++) {\n    float r = length(pos);\n    minApproach = min(minApproach, r);\n\n    if (r < rs) {\n      hitHorizon = true;\n      break;\n    }\n    if (r > 9.5 && step > 18) {\n      break;\n    }\n\n    // Adaptive step size: fine near photon sphere & equatorial plane, larger far away\n    float distPlane = abs(pos.y);\n    float dt = clamp(min(r - rs * 0.85, distPlane * 0.75 + 0.045) * 0.35, 0.025, 0.22);\n\n    // Gravitational deflection acceleration (-1.5 * rs * L^2 / r^5 approximation)\n    vec3 accel = -pos * (gravStrength / (r * r * r + 0.004));\n    vec3 nextDir = normalize(dir + accel * dt);\n    vec3 nextPos = pos + nextDir * dt;\n\n    // Check if ray crosses or grazes the equatorial accretion disk slab\n    float slabHalfHeight = 0.055 + 0.025 * smoothstep(innerDisk, outerDisk, r);\n    if (min(abs(pos.y), abs(nextPos.y)) < slabHalfHeight || pos.y * nextPos.y <= 0.0) {\n      float tCross = (pos.y * nextPos.y <= 0.0)\n        ? clamp(abs(pos.y) / (abs(pos.y - nextPos.y) + 0.0001), 0.0, 1.0)\n        : 0.5;\n      vec3 hitPos = mix(pos, nextPos, tCross);\n      float diskR = length(hitPos.xz);\n\n      if (diskR > innerDisk && diskR < outerDisk) {\n        float radialNorm = (diskR - innerDisk) / (outerDisk - innerDisk);\n        float radialProfile = smoothstep(0.0, 0.09, radialNorm) *\n                              pow(1.0 - radialNorm, 1.45);\n\n        // Relativistic differential Keplerian rotation (omega ~ r^-1.5)\n        float angle = atan(hitPos.z, hitPos.x);\n        float omega = u_spinSpeed * 1.65 / pow(diskR, 1.15);\n        float spiralPhase = angle + omega * u_time + (u_pull * 4.5) / (diskR + 0.15);\n\n        // Multi-octave spiraling plasma filaments + fine rings\n        float filamentScale = clamp(u_density / 260.0, 0.5, 2.0);\n        vec2 polarUv = vec2(diskR * 5.5 * filamentScale - u_time * u_pull * 0.8, spiralPhase * 2.0);\n        float n1 = fbm(polarUv);\n        float n2 = fbm(vec2(diskR * 14.0 * filamentScale, spiralPhase * 4.0 - n1 * 2.2));\n        float rings = 0.55 + 0.45 * sin(diskR * 36.0 * filamentScale + n1 * 5.0);\n        float plasmaDensity = radialProfile * mix(n1, n2, 0.55) * rings;\n\n        // Relativistic Doppler beaming & gravitational redshift\n        vec3 tangentVel = normalize(vec3(-hitPos.z, 0.0, hitPos.x));\n        float beta = clamp(0.52 * sqrt(rs / diskR) * clamp(u_spinSpeed, 0.2, 2.5), 0.0, 0.72);\n        float cosTheta = dot(nextDir, tangentVel);\n        float doppler = 1.0 / max(0.28, 1.0 - beta * cosTheta);\n        float beaming = pow(doppler, 2.65);\n\n        // Temperature color gradient: white-hot ISCO + Doppler blueshift vs crimson outer redshift\n        vec3 hotCore = vec3(1.0, 0.97, 0.90);\n        vec3 midTone = u_diskColor;\n        vec3 coolOuter = u_diskColor * vec3(0.65, 0.22, 0.08);\n\n        float tempFactor = clamp((1.0 - radialNorm * 0.75) * pow(doppler, 0.85), 0.0, 1.6);\n        vec3 localColor = mix(coolOuter, midTone, smoothstep(0.0, 0.65, tempFactor));\n        localColor = mix(localColor, hotCore, smoothstep(0.65, 1.35, tempFactor));\n\n        // Subtle blue-white shift on extreme approaching side\n        localColor = mix(localColor, vec3(0.82, 0.93, 1.0), smoothstep(1.3, 1.9, doppler) * 0.35);\n\n        float verticalFade = exp(-pow(hitPos.y / slabHalfHeight, 2.0) * 2.2);\n        float stepEmission = plasmaDensity * verticalFade * beaming * 1.15;\n\n        accumGlow += transmittance * localColor * stepEmission;\n        transmittance *= exp(-plasmaDensity * verticalFade * 0.65);\n      }\n    }\n\n    pos = nextPos;\n    dir = nextDir;\n  }\n\n  vec3 finalColor = vec3(0.0);\n\n  // Escaped rays sample the gravitationally lensed starfield\n  if (!hitHorizon) {\n    finalColor += transmittance * sampleStarfield(dir, u_time);\n  }\n\n  // Razor-sharp incandescent Photon Ring at the critical impact parameter\n  float photonRingDist = abs(minApproach - rs * 1.045);\n  float photonRing = exp(-photonRingDist * 46.0) * 1.35 + exp(-photonRingDist * 12.0) * 0.32;\n  vec3 photonColor = mix(u_diskColor, vec3(1.0, 0.96, 0.86), 0.72);\n  finalColor += photonColor * photonRing * (hitHorizon ? 0.45 : 1.0);\n\n  // Add accumulated volumetric accretion disk & lensed upper/lower arches\n  finalColor += accumGlow;\n\n  // Ambient relativistic corona bloom\n  float screenR = length(uv);\n  float ambientCorona = exp(-max(0.0, screenR - rs * 0.9) * 2.1) * 0.16;\n  finalColor += u_diskColor * ambientCorona;\n\n  // ACES-inspired filmic tone mapping & gamma correction\n  finalColor = (finalColor * (2.51 * finalColor + 0.03)) / (finalColor * (2.43 * finalColor + 0.59) + 0.14);\n  finalColor = pow(clamp(finalColor, 0.0, 1.0), vec3(0.92));\n\n  // Subtle dither to prevent 8-bit banding in deep space gradients\n  finalColor += (hash21(gl_FragCoord.xy + fract(u_time)) - 0.5) / 255.0;\n\n  gl_FragColor = vec4(finalColor, 1.0);\n}\n`;\n\nconst PRESETS = [\n  {\n    name: \"Gargantua\",\n    diskColor: \"#FF7A18\",\n    size: 95,\n    spinSpeed: 1.2,\n    pull: 0.35,\n    lensing: true,\n  },\n  {\n    name: \"Quasar Jet\",\n    diskColor: \"#38BDF8\",\n    size: 85,\n    spinSpeed: 1.85,\n    pull: 0.55,\n    lensing: true,\n  },\n  {\n    name: \"Crimson Singularity\",\n    diskColor: \"#F43F5E\",\n    size: 105,\n    spinSpeed: 0.9,\n    pull: 0.25,\n    lensing: true,\n  },\n] as const;\n\nexport function BlackHole({\n  size = 95,\n  diskColor = \"#FF7A18\",\n  spinSpeed = 1.2,\n  particleCount = 260,\n  pull = 0.35,\n  lensing = true,\n  children,\n  className,\n}: BlackHoleProps) {\n  const containerRef = useRef<HTMLDivElement>(null);\n  const canvasRef = useRef<HTMLCanvasElement>(null);\n\n  const [activeSize, setActiveSize] = useState(size);\n  const [activeColor, setActiveColor] = useState(diskColor);\n  const [activeSpin, setActiveSpin] = useState(spinSpeed);\n  const [activePull, setActivePull] = useState(pull);\n  const [activeLensing, setActiveLensing] = useState(lensing);\n  const pointerRef = useRef<{ x: number; y: number; tx: number; ty: number }>({\n    x: 0,\n    y: 0,\n    tx: 0,\n    ty: 0,\n  });\n\n  useEffect(() => {\n    setActiveSize(size);\n  }, [size]);\n  useEffect(() => {\n    setActiveColor(diskColor);\n  }, [diskColor]);\n  useEffect(() => {\n    setActiveSpin(spinSpeed);\n  }, [spinSpeed]);\n  useEffect(() => {\n    setActivePull(pull);\n  }, [pull]);\n  useEffect(() => {\n    setActiveLensing(lensing);\n  }, [lensing]);\n\n  const paramsRef = useRef({\n    size: activeSize,\n    color: hexToNormalizedRgb(activeColor),\n    spinSpeed: activeSpin,\n    particleCount,\n    pull: activePull,\n    lensing: activeLensing ? 1.0 : 0.0,\n  });\n\n  useEffect(() => {\n    paramsRef.current = {\n      size: activeSize,\n      color: hexToNormalizedRgb(activeColor),\n      spinSpeed: activeSpin,\n      particleCount,\n      pull: activePull,\n      lensing: activeLensing ? 1.0 : 0.0,\n    };\n  }, [activeSize, activeColor, activeSpin, particleCount, activePull, activeLensing]);\n\n  useEffect(() => {\n    const container = containerRef.current;\n    const canvas = canvasRef.current;\n    if (!container || !canvas) return;\n\n    const gl = canvas.getContext(\"webgl\", {\n      alpha: false,\n      antialias: false,\n      preserveDrawingBuffer: false,\n    });\n    if (!gl) return;\n\n    const compileShader = (type: number, source: string) => {\n      const shader = gl.createShader(type);\n      if (!shader) return null;\n      gl.shaderSource(shader, source);\n      gl.compileShader(shader);\n      if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {\n        gl.deleteShader(shader);\n        return null;\n      }\n      return shader;\n    };\n\n    const vs = compileShader(gl.VERTEX_SHADER, VERTEX_SHADER);\n    const fs = compileShader(gl.FRAGMENT_SHADER, FRAGMENT_SHADER);\n    if (!vs || !fs) return;\n\n    const program = gl.createProgram();\n    if (!program) return;\n    gl.attachShader(program, vs);\n    gl.attachShader(program, fs);\n    gl.linkProgram(program);\n\n    if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {\n      gl.deleteProgram(program);\n      return;\n    }\n\n    gl.useProgram(program);\n\n    const buffer = gl.createBuffer();\n    gl.bindBuffer(gl.ARRAY_BUFFER, buffer);\n    gl.bufferData(\n      gl.ARRAY_BUFFER,\n      new Float32Array([-1, -1, 1, -1, -1, 1, -1, 1, 1, -1, 1, 1]),\n      gl.STATIC_DRAW\n    );\n\n    const posLoc = gl.getAttribLocation(program, \"a_position\");\n    gl.enableVertexAttribArray(posLoc);\n    gl.vertexAttribPointer(posLoc, 2, gl.FLOAT, false, 0, 0);\n\n    const uResolution = gl.getUniformLocation(program, \"u_resolution\");\n    const uTime = gl.getUniformLocation(program, \"u_time\");\n    const uSize = gl.getUniformLocation(program, \"u_size\");\n    const uDiskColor = gl.getUniformLocation(program, \"u_diskColor\");\n    const uSpinSpeed = gl.getUniformLocation(program, \"u_spinSpeed\");\n    const uDensity = gl.getUniformLocation(program, \"u_density\");\n    const uPull = gl.getUniformLocation(program, \"u_pull\");\n    const uLensing = gl.getUniformLocation(program, \"u_lensing\");\n    const uPointer = gl.getUniformLocation(program, \"u_pointer\");\n\n    let dpr = Math.min(window.devicePixelRatio || 1, 1.75);\n    const resizeCanvas = () => {\n      if (!container || !canvas) return;\n      dpr = Math.min(window.devicePixelRatio || 1, 1.75);\n      const w = Math.max(1, Math.floor((container.clientWidth || 800) * dpr));\n      const h = Math.max(1, Math.floor((container.clientHeight || 520) * dpr));\n      canvas.width = w;\n      canvas.height = h;\n      gl.viewport(0, 0, w, h);\n    };\n\n    resizeCanvas();\n    const observer = new ResizeObserver(resizeCanvas);\n    observer.observe(container);\n\n    let rafId = 0;\n    let accumTime = 0;\n    let lastNow = performance.now();\n\n    const render = (now: number) => {\n      const dt = Math.min(0.1, (now - lastNow) * 0.001);\n      lastNow = now;\n      accumTime += dt;\n\n      const p = paramsRef.current;\n      const ptr = pointerRef.current;\n      ptr.x += (ptr.tx - ptr.x) * 0.06;\n      ptr.y += (ptr.ty - ptr.y) * 0.06;\n\n      gl.uniform2f(uResolution, canvas.width, canvas.height);\n      gl.uniform1f(uTime, accumTime);\n      gl.uniform1f(uSize, p.size * dpr);\n      gl.uniform3f(uDiskColor, p.color[0], p.color[1], p.color[2]);\n      gl.uniform1f(uSpinSpeed, p.spinSpeed);\n      gl.uniform1f(uDensity, p.particleCount);\n      gl.uniform1f(uPull, p.pull);\n      gl.uniform1f(uLensing, p.lensing);\n      gl.uniform2f(uPointer, ptr.x, ptr.y);\n\n      gl.drawArrays(gl.TRIANGLES, 0, 6);\n      rafId = requestAnimationFrame(render);\n    };\n\n    rafId = requestAnimationFrame(render);\n\n    return () => {\n      cancelAnimationFrame(rafId);\n      observer.disconnect();\n      gl.deleteBuffer(buffer);\n      gl.deleteProgram(program);\n      gl.deleteShader(vs);\n      gl.deleteShader(fs);\n    };\n  }, []);\n\n  const handlePointerMove = (e: React.PointerEvent<HTMLDivElement>) => {\n    if (!containerRef.current) return;\n    const rect = containerRef.current.getBoundingClientRect();\n    pointerRef.current.tx = ((e.clientX - rect.left) / rect.width - 0.5) * 2;\n    pointerRef.current.ty = ((e.clientY - rect.top) / rect.height - 0.5) * 2;\n  };\n\n  const handlePointerLeave = () => {\n    pointerRef.current.tx = 0;\n    pointerRef.current.ty = 0;\n  };\n\n  return (\n    <div\n      ref={containerRef}\n      data-fullscreen-scroll\n      onPointerMove={handlePointerMove}\n      onPointerLeave={handlePointerLeave}\n      className={cn(\n        \"relative w-full min-h-[520px] overflow-hidden rounded-2xl bg-[#020308] text-white select-none\",\n        className\n      )}\n    >\n      <canvas\n        ref={canvasRef}\n        aria-hidden=\"true\"\n        className=\"pointer-events-none absolute inset-0 h-full w-full\"\n      />\n\n      {/* Subtle radial vignette */}\n      <div\n        aria-hidden=\"true\"\n        className=\"pointer-events-none absolute inset-0 bg-[radial-gradient(circle_at_center,transparent_48%,rgba(2,3,8,0.72)_100%)]\"\n      />\n\n      {children && (\n        <div className=\"relative z-10 flex min-h-[520px] w-full flex-col\">\n          {children}\n        </div>\n      )}\n    </div>\n  );\n}\n\nexport default BlackHole;\n",
          "type": "registry:ui",
          "target": "components/ui/black-hole.tsx"
        },
        {
          "path": "lib/utils.ts",
          "content": "import { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...inputs: ClassValue[]) {\n  return twMerge(clsx(inputs));\n}\n\nexport async function copyToClipboard(text: string): Promise<boolean> {\n  if (typeof window === \"undefined\") return false;\n\n  try {\n    if (navigator.clipboard && window.isSecureContext) {\n      await navigator.clipboard.writeText(text);\n      return true;\n    }\n\n    const textArea = document.createElement(\"textarea\");\n    textArea.value = text;\n    textArea.style.position = \"fixed\";\n    textArea.style.left = \"-999999px\";\n    textArea.style.top = \"-999999px\";\n    document.body.appendChild(textArea);\n    textArea.focus();\n    textArea.select();\n    const succeeded = document.execCommand(\"copy\");\n    textArea.remove();\n    return succeeded;\n  } catch {\n    return false;\n  }\n}\n",
          "type": "registry:lib",
          "target": "lib/utils.ts"
        }
      ]
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "carousel-with-dots",
      "type": "registry:ui",
      "title": "Carousel with Dots",
      "author": "Rishabh Bose <https://theb0se.vercel.app/>",
      "description": "Horizontally snapping card carousel with swipe gesture physics, a pill-shaped morphing dot indicator, keyboard arrow support, and circular navigation buttons.",
      "dependencies": [
        "framer-motion",
        "lucide-react",
        "clsx",
        "tailwind-merge"
      ],
      "files": [
        {
          "path": "components/ui/carousel-with-dots.tsx",
          "content": "\"use client\";\n\nimport React, { useState, useEffect, useCallback } from \"react\";\nimport { motion, useReducedMotion, type PanInfo } from \"framer-motion\";\nimport { ChevronLeft, ChevronRight, Sparkles, Cpu, Shield, Zap } from \"lucide-react\";\nimport { cn } from \"@/lib/utils\";\n\nexport interface CarouselSlide {\n  id: string;\n  eyebrow: string;\n  title: string;\n  description: string;\n  stat: string;\n}\n\nexport interface CarouselWithDotsProps {\n  /** Array of slide items */\n  slides?: CarouselSlide[];\n  /** Initial active slide index. Default: 0 */\n  defaultIndex?: number;\n  /** Enable automatic slide rotation. Default: false */\n  autoPlay?: boolean;\n  /** Auto-play interval in milliseconds. Default: 4500 */\n  interval?: number;\n  /** Callback fired when the active slide changes */\n  onSlideChange?: (index: number) => void;\n  className?: string;\n}\n\nconst DEFAULT_SLIDES: CarouselSlide[] = [\n  {\n    id: \"display\",\n    eyebrow: \"ProMotion 120Hz\",\n    title: \"Adaptive refresh rates that match your gesture velocity.\",\n    description:\n      \"Every swipe and drag calculates release velocity to settle naturally without abrupt stops.\",\n    stat: \"120 FPS\",\n  },\n  {\n    id: \"acoustics\",\n    eyebrow: \"Spatial Audio Engine\",\n    title: \"Studio-grade acoustic isolation in a minimal enclosure.\",\n    description:\n      \"Precision-milled internals reduce harmonic distortion across the entire frequency spectrum.\",\n    stat: \"48 kHz\",\n  },\n  {\n    id: \"battery\",\n    eyebrow: \"All-Day Efficiency\",\n    title: \"Up to 22 hours of continuous workflow on a single charge.\",\n    description:\n      \"Fast-charge architecture restores 50% capacity in just 25 minutes over USB-C.\",\n    stat: \"22 HRS\",\n  },\n  {\n    id: \"security\",\n    eyebrow: \"Hardware Enclave\",\n    title: \"End-to-end encryption verified at silicon startup.\",\n    description:\n      \"Dedicated cryptographic keys remain isolated from the main application processor.\",\n    stat: \"256-BIT\",\n  },\n];\n\nexport function CarouselWithDots({\n  slides = DEFAULT_SLIDES,\n  defaultIndex = 0,\n  autoPlay = false,\n  interval = 4500,\n  onSlideChange,\n  className,\n}: CarouselWithDotsProps) {\n  const shouldReduceMotion = useReducedMotion() ?? false;\n  const [currentIndex, setCurrentIndex] = useState(defaultIndex);\n\n  const total = slides.length;\n\n  const goTo = useCallback(\n    (index: number) => {\n      const next = (index + total) % total;\n      setCurrentIndex(next);\n      onSlideChange?.(next);\n    },\n    [total, onSlideChange]\n  );\n\n  useEffect(() => {\n    if (!autoPlay || total <= 1) return;\n    const timer = setInterval(() => {\n      goTo(currentIndex + 1);\n    }, interval);\n    return () => clearInterval(timer);\n  }, [autoPlay, interval, currentIndex, total, goTo]);\n\n  const handleDragEnd = (\n    _: MouseEvent | TouchEvent | PointerEvent,\n    info: PanInfo\n  ) => {\n    const swipeThreshold = 40;\n    if (info.offset.x < -swipeThreshold || info.velocity.x < -300) {\n      goTo(currentIndex + 1);\n    } else if (info.offset.x > swipeThreshold || info.velocity.x > 300) {\n      goTo(currentIndex - 1);\n    }\n  };\n\n  const icons = [\n    <Sparkles key=\"0\" className=\"h-4 w-4\" />,\n    <Zap key=\"1\" className=\"h-4 w-4\" />,\n    <Cpu key=\"2\" className=\"h-4 w-4\" />,\n    <Shield key=\"3\" className=\"h-4 w-4\" />,\n  ];\n\n  return (\n    <div\n      role=\"region\"\n      aria-roledescription=\"carousel\"\n      aria-label=\"Feature highlights carousel\"\n      onKeyDown={(e) => {\n        if (e.key === \"ArrowLeft\") {\n          e.preventDefault();\n          goTo(currentIndex - 1);\n        } else if (e.key === \"ArrowRight\") {\n          e.preventDefault();\n          goTo(currentIndex + 1);\n        }\n      }}\n      tabIndex={0}\n      className={cn(\n        \"w-full max-w-lg select-none focus-visible:outline-none\",\n        className\n      )}\n    >\n      {/* Viewport Track */}\n      <div className=\"overflow-hidden rounded-[28px] border border-neutral-200 bg-white shadow-sm dark:border-neutral-800 dark:bg-[#0A0A0A]\">\n        <motion.div\n          drag=\"x\"\n          dragConstraints={{ left: 0, right: 0 }}\n          dragElastic={0.2}\n          onDragEnd={handleDragEnd}\n          animate={{ x: `-${currentIndex * 100}%` }}\n          transition={\n            shouldReduceMotion\n              ? { duration: 0 }\n              : { type: \"spring\", stiffness: 320, damping: 32 }\n          }\n          className=\"flex cursor-grab active:cursor-grabbing\"\n        >\n          {slides.map((slide, idx) => (\n            <div\n              key={slide.id}\n              role=\"group\"\n              aria-roledescription=\"slide\"\n              aria-label={`${idx + 1} of ${total}`}\n              className=\"w-full shrink-0 p-6 sm:p-8\"\n            >\n              <div className=\"flex items-center justify-between\">\n                <span className=\"inline-flex items-center gap-1.5 rounded-full border border-neutral-200 bg-neutral-50 px-3 py-1 font-mono text-[11px] font-medium text-neutral-700 dark:border-neutral-800 dark:bg-neutral-900 dark:text-neutral-300\">\n                  {icons[idx % icons.length]}\n                  {slide.eyebrow}\n                </span>\n                <span className=\"font-mono text-xs font-bold tracking-tight text-neutral-400 dark:text-neutral-500\">\n                  {slide.stat}\n                </span>\n              </div>\n\n              <h3 className=\"mt-5 text-xl font-bold tracking-tight text-neutral-950 dark:text-white sm:text-2xl\">\n                {slide.title}\n              </h3>\n\n              <p className=\"mt-2.5 text-xs leading-relaxed text-neutral-600 dark:text-neutral-400 sm:text-sm\">\n                {slide.description}\n              </p>\n            </div>\n          ))}\n        </motion.div>\n      </div>\n\n      {/* Bottom Controls: Pill-Shaped Page Indicator + Circular Arrow Controls */}\n      <div className=\"mt-4 flex items-center justify-between px-1\">\n        {/* Pill-Shaped Page Indicator */}\n        <div\n          role=\"tablist\"\n          aria-label=\"Slide indicators\"\n          className=\"inline-flex items-center gap-2 rounded-full border border-neutral-200 bg-neutral-100/90 px-3.5 py-2 backdrop-blur-md dark:border-neutral-800 dark:bg-neutral-900/90\"\n        >\n          {slides.map((slide, idx) => {\n            const isActive = idx === currentIndex;\n            return (\n              <button\n                key={slide.id}\n                type=\"button\"\n                role=\"tab\"\n                aria-selected={isActive}\n                aria-label={`Go to slide ${idx + 1}: ${slide.eyebrow}`}\n                onClick={() => goTo(idx)}\n                className=\"relative flex h-2 items-center justify-center focus-visible:outline-none\"\n              >\n                <motion.span\n                  animate={{\n                    width: isActive ? 22 : 6,\n                    opacity: isActive ? 1 : 0.4,\n                  }}\n                  transition={{ type: \"spring\", stiffness: 400, damping: 28 }}\n                  className=\"h-1.5 rounded-full bg-neutral-900 dark:bg-white\"\n                />\n              </button>\n            );\n          })}\n        </div>\n\n        {/* Arrow Controls */}\n        <div className=\"flex items-center gap-2\">\n          <button\n            type=\"button\"\n            aria-label=\"Previous slide\"\n            onClick={() => goTo(currentIndex - 1)}\n            className=\"flex h-9 w-9 items-center justify-center rounded-full border border-neutral-200 bg-white text-neutral-700 shadow-2xs transition-all hover:border-neutral-900 hover:text-neutral-950 active:scale-95 dark:border-neutral-800 dark:bg-neutral-900 dark:text-neutral-300 dark:hover:border-white dark:hover:text-white\"\n          >\n            <ChevronLeft className=\"h-4 w-4\" />\n          </button>\n\n          <button\n            type=\"button\"\n            aria-label=\"Next slide\"\n            onClick={() => goTo(currentIndex + 1)}\n            className=\"flex h-9 w-9 items-center justify-center rounded-full border border-neutral-200 bg-white text-neutral-700 shadow-2xs transition-all hover:border-neutral-900 hover:text-neutral-950 active:scale-95 dark:border-neutral-800 dark:bg-neutral-900 dark:text-neutral-300 dark:hover:border-white dark:hover:text-white\"\n          >\n            <ChevronRight className=\"h-4 w-4\" />\n          </button>\n        </div>\n      </div>\n    </div>\n  );\n}\n\nexport default CarouselWithDots;\n",
          "type": "registry:ui",
          "target": "components/ui/carousel-with-dots.tsx"
        },
        {
          "path": "lib/utils.ts",
          "content": "import { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...inputs: ClassValue[]) {\n  return twMerge(clsx(inputs));\n}\n\nexport async function copyToClipboard(text: string): Promise<boolean> {\n  if (typeof window === \"undefined\") return false;\n\n  try {\n    if (navigator.clipboard && window.isSecureContext) {\n      await navigator.clipboard.writeText(text);\n      return true;\n    }\n\n    const textArea = document.createElement(\"textarea\");\n    textArea.value = text;\n    textArea.style.position = \"fixed\";\n    textArea.style.left = \"-999999px\";\n    textArea.style.top = \"-999999px\";\n    document.body.appendChild(textArea);\n    textArea.focus();\n    textArea.select();\n    const succeeded = document.execCommand(\"copy\");\n    textArea.remove();\n    return succeeded;\n  } catch {\n    return false;\n  }\n}\n",
          "type": "registry:lib",
          "target": "lib/utils.ts"
        }
      ]
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "category-filter-scroller",
      "type": "registry:ui",
      "title": "Category Filter Scroller",
      "author": "Rishabh Bose <https://theb0se.vercel.app/>",
      "description": "Airbnb-style horizontal scrolling category filter bar with edge gradient fade masks, spring active underline indicator, and tactile left/right chevron navigation.",
      "dependencies": [
        "framer-motion",
        "lucide-react",
        "clsx",
        "tailwind-merge"
      ],
      "files": [
        {
          "path": "components/ui/category-filter-scroller.tsx",
          "content": "\"use client\";\n\nimport React, { useState, useRef, useEffect, useCallback } from \"react\";\nimport { motion, AnimatePresence } from \"framer-motion\";\nimport {\n  ChevronLeft,\n  ChevronRight,\n  Flame,\n  Palmtree,\n  Home,\n  Waves,\n  MountainSnow,\n  TreePine,\n  Castle,\n  Tent,\n  Sun,\n  Sparkles,\n  Building,\n  Coffee,\n  SlidersHorizontal,\n  Compass,\n  Star,\n  Heart,\n  Check,\n} from \"lucide-react\";\nimport { cn } from \"@/lib/utils\";\n\nexport interface CategoryItem {\n  id: string;\n  label: string;\n  icon: React.ComponentType<{ className?: string }>;\n  tagline: string;\n  badge?: string;\n}\n\nexport interface CategoryFilterScrollerProps {\n  /** Initial selected category ID */\n  defaultCategory?: string;\n  /** Callback on category select */\n  onSelectCategory?: (category: CategoryItem) => void;\n  /** Extra container className */\n  className?: string;\n}\n\nconst CATEGORIES: CategoryItem[] = [\n  { id: \"trending\", label: \"Trending\", icon: Flame, tagline: \"Most booked destinations worldwide\", badge: \"Hot\" },\n  { id: \"beachfront\", label: \"Beachfront\", icon: Waves, tagline: \"Steps away from white sand & turquoise water\" },\n  { id: \"cabins\", label: \"Cabins\", icon: Home, tagline: \"Secluded wood cabins with wood stoves\" },\n  { id: \"mansions\", label: \"Mansions\", icon: Building, tagline: \"Luxury estates with private infinity pools\" },\n  { id: \"lakefront\", label: \"Lakefront\", icon: Compass, tagline: \"Private docks and calm morning waters\" },\n  { id: \"tiny-homes\", label: \"Tiny homes\", icon: Sparkles, tagline: \"Architectural wonders in compact footprints\" },\n  { id: \"islands\", label: \"Islands\", icon: Palmtree, tagline: \"Exclusive private island sanctuaries\" },\n  { id: \"skiing\", label: \"Ski-in/out\", icon: MountainSnow, tagline: \"Direct alpine access on premier peaks\" },\n  { id: \"treehouses\", label: \"Treehouses\", icon: TreePine, tagline: \"Canopy living nestled high in old-growth pine\" },\n  { id: \"castles\", label: \"Castles\", icon: Castle, tagline: \"Historic stone towers and royal countryside keeps\" },\n  { id: \"camping\", label: \"Camping\", icon: Tent, tagline: \"Luxury yurt and geodesic dome glamping\" },\n  { id: \"desert\", label: \"Desert\", icon: Sun, tagline: \"Stargazing retreats in Joshua Tree and Sedona\" },\n  { id: \"bed-breakfast\", label: \"B & B\", icon: Coffee, tagline: \"Charming countryside homesteads with breakfast\" },\n];\n\nconst CATEGORY_SHOWCASES: Record<\n  string,\n  Array<{\n    id: string;\n    title: string;\n    location: string;\n    price: string;\n    rating: number;\n    dates: string;\n    gradient: string;\n  }>\n> = {\n  trending: [\n    { id: \"t1\", title: \"Glass Pavilion Over Sea\", location: \"Positano, Italy\", price: \"$520\", rating: 4.97, dates: \"May 12–17\", gradient: \"from-blue-600/40 via-sky-500/30 to-amber-200/20\" },\n    { id: \"t2\", title: \"Nordic Minimalist Fjord\", location: \"Bergen, Norway\", price: \"$340\", rating: 4.99, dates: \"Jun 1–6\", gradient: \"from-slate-700/50 via-teal-800/30 to-emerald-900/20\" },\n    { id: \"t3\", title: \"High-Desert Mirrored Cube\", location: \"Sedona, AZ\", price: \"$410\", rating: 4.95, dates: \"Apr 20–25\", gradient: \"from-amber-600/40 via-rose-600/30 to-indigo-900/30\" },\n  ],\n  beachfront: [\n    { id: \"b1\", title: \"Bioluminescent Lagoon Villa\", location: \"Vieques, Puerto Rico\", price: \"$640\", rating: 4.98, dates: \"Jul 4–9\", gradient: \"from-cyan-600/40 via-teal-500/30 to-emerald-400/20\" },\n    { id: \"b2\", title: \"Overwater Bungalow\", location: \"Bora Bora, French Polynesia\", price: \"$1,120\", rating: 5.0, dates: \"Aug 15–20\", gradient: \"from-blue-500/40 via-cyan-400/30 to-sky-200/20\" },\n    { id: \"b3\", title: \"Sunset Cliffside Bungalow\", location: \"Santorini, Greece\", price: \"$590\", rating: 4.94, dates: \"Sep 2–7\", gradient: \"from-sky-700/50 via-indigo-600/30 to-rose-300/20\" },\n  ],\n  cabins: [\n    { id: \"c1\", title: \"Whispering Pines A-Frame\", location: \"Mount Rainier, WA\", price: \"$280\", rating: 4.96, dates: \"Jun 10–15\", gradient: \"from-emerald-800/50 via-amber-900/30 to-stone-800/40\" },\n    { id: \"c2\", title: \"Nordic Cedar Sauna Haven\", location: \"Lapland, Finland\", price: \"$390\", rating: 4.99, dates: \"Dec 3–8\", gradient: \"from-blue-900/50 via-slate-800/40 to-cyan-900/30\" },\n    { id: \"c3\", title: \"Redwood Ridge Hideout\", location: \"Big Sur, CA\", price: \"$440\", rating: 4.92, dates: \"May 22–27\", gradient: \"from-orange-800/40 via-amber-700/30 to-stone-900/30\" },\n  ],\n};\n\nexport function CategoryFilterScroller({\n  defaultCategory = \"trending\",\n  onSelectCategory,\n  className,\n}: CategoryFilterScrollerProps) {\n  const [selectedId, setSelectedId] = useState(defaultCategory);\n  const [canScrollLeft, setCanScrollLeft] = useState(false);\n  const [canScrollRight, setCanScrollRight] = useState(true);\n  const [favorites, setFavorites] = useState<Record<string, boolean>>({});\n  const [showFilterDrawer, setShowFilterDrawer] = useState(false);\n\n  const scrollContainerRef = useRef<HTMLDivElement>(null);\n\n  const activeCategory = CATEGORIES.find((c) => c.id === selectedId) || CATEGORIES[0];\n\n  const checkScrollBounds = useCallback(() => {\n    const el = scrollContainerRef.current;\n    if (!el) return;\n    const { scrollLeft, scrollWidth, clientWidth } = el;\n    setCanScrollLeft(scrollLeft > 6);\n    setCanScrollRight(scrollLeft < scrollWidth - clientWidth - 6);\n  }, []);\n\n  useEffect(() => {\n    checkScrollBounds();\n    const el = scrollContainerRef.current;\n    if (!el) return;\n\n    el.addEventListener(\"scroll\", checkScrollBounds, { passive: true });\n    window.addEventListener(\"resize\", checkScrollBounds);\n\n    return () => {\n      el.removeEventListener(\"scroll\", checkScrollBounds);\n      window.removeEventListener(\"resize\", checkScrollBounds);\n    };\n  }, [checkScrollBounds]);\n\n  const scrollByOffset = (direction: \"left\" | \"right\") => {\n    const el = scrollContainerRef.current;\n    if (!el) return;\n    const offset = direction === \"left\" ? -280 : 280;\n    el.scrollBy({ left: offset, behavior: \"smooth\" });\n  };\n\n  const handleSelect = (category: CategoryItem) => {\n    setSelectedId(category.id);\n    onSelectCategory?.(category);\n  };\n\n  const toggleFavorite = (cardId: string) => {\n    setFavorites((prev) => ({ ...prev, [cardId]: !prev[cardId] }));\n  };\n\n  const showcaseCards = CATEGORY_SHOWCASES[selectedId] || CATEGORY_SHOWCASES.trending;\n\n  return (\n    <div\n      data-fullscreen-scroll\n      className={cn(\n        \"relative flex min-h-[520px] w-full flex-col justify-between overflow-hidden rounded-2xl border border-neutral-200 bg-white p-4 sm:p-8 dark:border-neutral-800 dark:bg-neutral-950\",\n        className\n      )}\n    >\n      {/* Header bar */}\n      <div className=\"relative z-10 flex flex-wrap items-center justify-between gap-3 pb-3\">\n        <div className=\"flex items-center gap-3\">\n          <div className=\"flex h-9 w-9 items-center justify-center rounded-xl bg-neutral-100 text-neutral-800 dark:bg-neutral-800 dark:text-neutral-200\">\n            <Compass className=\"h-4 w-4\" />\n          </div>\n          <div>\n            <div className=\"flex items-center gap-2\">\n              <span className=\"text-sm font-semibold tracking-tight text-neutral-900 dark:text-neutral-100\">\n                Airbnb Category Filter Scroller\n              </span>\n              <span className=\"rounded-full bg-neutral-100 px-2 py-0.5 text-[10px] font-medium text-neutral-600 dark:bg-neutral-800 dark:text-neutral-400\">\n                {CATEGORIES.length} Categories\n              </span>\n            </div>\n            <p className=\"text-xs text-neutral-500 dark:text-neutral-400\">\n              Edge fade masks, spring active underline, and tactile scroll navigation\n            </p>\n          </div>\n        </div>\n\n        <button\n          type=\"button\"\n          onClick={() => setShowFilterDrawer(!showFilterDrawer)}\n          className={cn(\n            \"flex items-center gap-2 rounded-xl border px-3 py-1.5 text-xs font-medium transition shadow-xs\",\n            showFilterDrawer\n              ? \"border-neutral-900 bg-neutral-900 text-white dark:border-white dark:bg-white dark:text-neutral-900\"\n              : \"border-neutral-200 bg-white text-neutral-700 hover:bg-neutral-50 dark:border-neutral-800 dark:bg-neutral-900 dark:text-neutral-300 dark:hover:bg-neutral-800\"\n          )}\n        >\n          <SlidersHorizontal className=\"h-3.5 w-3.5\" />\n          <span>Filters</span>\n        </button>\n      </div>\n\n      {/* Main Filter Scroller Bar */}\n      <div className=\"relative z-10 my-2 w-full\">\n        {/* Left Scroll Button */}\n        <AnimatePresence>\n          {canScrollLeft && (\n            <motion.div\n              initial={{ opacity: 0, scale: 0.8 }}\n              animate={{ opacity: 1, scale: 1 }}\n              exit={{ opacity: 0, scale: 0.8 }}\n              transition={{ duration: 0.15 }}\n              className=\"absolute -left-2 top-1/2 z-30 -translate-y-1/2 sm:-left-3\"\n            >\n              <button\n                type=\"button\"\n                onClick={() => scrollByOffset(\"left\")}\n                aria-label=\"Scroll left\"\n                className=\"flex h-8 w-8 items-center justify-center rounded-full border border-neutral-300 bg-white text-neutral-700 shadow-md transition hover:scale-105 hover:bg-neutral-50 active:scale-95 dark:border-neutral-700 dark:bg-neutral-900 dark:text-neutral-200\"\n              >\n                <ChevronLeft className=\"h-4 w-4\" />\n              </button>\n            </motion.div>\n          )}\n        </AnimatePresence>\n\n        {/* Left edge fade mask */}\n        {canScrollLeft && (\n          <div className=\"pointer-events-none absolute bottom-0 left-0 top-0 z-20 w-12 bg-gradient-to-r from-white via-white/80 to-transparent dark:from-neutral-950 dark:via-neutral-950/80\" />\n        )}\n\n        {/* Scroll Container */}\n        <div\n          ref={scrollContainerRef}\n          className=\"no-scrollbar flex items-center gap-6 overflow-x-auto scroll-smooth px-3 py-2\"\n          style={{ scrollbarWidth: \"none\", msOverflowStyle: \"none\" }}\n        >\n          {CATEGORIES.map((cat) => {\n            const Icon = cat.icon;\n            const isSelected = cat.id === selectedId;\n\n            return (\n              <button\n                key={cat.id}\n                type=\"button\"\n                onClick={() => handleSelect(cat)}\n                className={cn(\n                  \"group relative flex shrink-0 cursor-pointer flex-col items-center gap-1.5 pb-2.5 pt-1 text-center transition focus-visible:outline-none\",\n                  isSelected\n                    ? \"text-neutral-900 dark:text-white font-semibold\"\n                    : \"text-neutral-500 hover:text-neutral-800 dark:text-neutral-400 dark:hover:text-neutral-200 font-medium\"\n                )}\n              >\n                <div className=\"relative\">\n                  <Icon\n                    className={cn(\n                      \"h-6 w-6 transition-transform duration-200 group-hover:scale-110\",\n                      isSelected ? \"scale-105\" : \"opacity-80 group-hover:opacity-100\"\n                    )}\n                  />\n                  {cat.badge && (\n                    <span className=\"absolute -right-2 -top-1 rounded-full bg-rose-500 px-1 text-[8px] font-bold text-white uppercase leading-tight\">\n                      {cat.badge}\n                    </span>\n                  )}\n                </div>\n\n                <span className=\"text-[11px] whitespace-nowrap tracking-tight\">\n                  {cat.label}\n                </span>\n\n                {/* Sliding active underline indicator */}\n                {isSelected && (\n                  <motion.div\n                    layoutId=\"category-underline\"\n                    transition={{ type: \"spring\", stiffness: 450, damping: 35 }}\n                    className=\"absolute -bottom-0.5 inset-x-0 h-0.5 rounded-full bg-neutral-900 dark:bg-white\"\n                  />\n                )}\n              </button>\n            );\n          })}\n        </div>\n\n        {/* Right edge fade mask */}\n        {canScrollRight && (\n          <div className=\"pointer-events-none absolute bottom-0 right-0 top-0 z-20 w-12 bg-gradient-to-l from-white via-white/80 to-transparent dark:from-neutral-950 dark:via-neutral-950/80\" />\n        )}\n\n        {/* Right Scroll Button */}\n        <AnimatePresence>\n          {canScrollRight && (\n            <motion.div\n              initial={{ opacity: 0, scale: 0.8 }}\n              animate={{ opacity: 1, scale: 1 }}\n              exit={{ opacity: 0, scale: 0.8 }}\n              transition={{ duration: 0.15 }}\n              className=\"absolute -right-2 top-1/2 z-30 -translate-y-1/2 sm:-right-3\"\n            >\n              <button\n                type=\"button\"\n                onClick={() => scrollByOffset(\"right\")}\n                aria-label=\"Scroll right\"\n                className=\"flex h-8 w-8 items-center justify-center rounded-full border border-neutral-300 bg-white text-neutral-700 shadow-md transition hover:scale-105 hover:bg-neutral-50 active:scale-95 dark:border-neutral-700 dark:bg-neutral-900 dark:text-neutral-200\"\n              >\n                <ChevronRight className=\"h-4 w-4\" />\n              </button>\n            </motion.div>\n          )}\n        </AnimatePresence>\n      </div>\n\n      {/* Filter drawer preview (interactive toggle) */}\n      <AnimatePresence>\n        {showFilterDrawer && (\n          <motion.div\n            initial={{ opacity: 0, height: 0 }}\n            animate={{ opacity: 1, height: \"auto\" }}\n            exit={{ opacity: 0, height: 0 }}\n            className=\"relative z-20 my-2 overflow-hidden rounded-2xl border border-neutral-200 bg-neutral-50 p-4 dark:border-neutral-800 dark:bg-neutral-900\"\n          >\n            <div className=\"flex flex-wrap items-center justify-between gap-2 border-b border-neutral-200 pb-2.5 dark:border-neutral-800\">\n              <span className=\"text-xs font-semibold text-neutral-900 dark:text-neutral-100\">\n                Filter by Type &amp; Amenities\n              </span>\n              <button\n                type=\"button\"\n                onClick={() => setShowFilterDrawer(false)}\n                className=\"text-xs text-rose-500 hover:underline\"\n              >\n                Close\n              </button>\n            </div>\n            <div className=\"mt-3 flex flex-wrap gap-2\">\n              {[\"Superhost\", \"Self check-in\", \"Free Wi-Fi\", \"Dedicated workspace\", \"Pool\", \"Hot tub\", \"Pet friendly\"].map(\n                (filter, idx) => (\n                  <span\n                    key={idx}\n                    className=\"inline-flex cursor-pointer items-center gap-1.5 rounded-full border border-neutral-300 bg-white px-3 py-1 text-xs text-neutral-700 hover:border-neutral-900 dark:border-neutral-700 dark:bg-neutral-800 dark:text-neutral-300 dark:hover:border-white\"\n                  >\n                    <Check className=\"h-3 w-3 text-neutral-400\" />\n                    <span>{filter}</span>\n                  </span>\n                )\n              )}\n            </div>\n          </motion.div>\n        )}\n      </AnimatePresence>\n\n      {/* Selected Category Showcase Area */}\n      <div className=\"relative z-10 mt-4 flex flex-1 flex-col justify-center\">\n        <div className=\"mb-3 flex items-center justify-between\">\n          <div className=\"space-y-0.5\">\n            <h3 className=\"text-xs font-semibold text-neutral-900 dark:text-neutral-100\">\n              Showing {activeCategory.label}\n            </h3>\n            <p className=\"text-[11px] text-neutral-500 dark:text-neutral-400\">\n              {activeCategory.tagline}\n            </p>\n          </div>\n          <span className=\"font-mono text-[10px] text-neutral-400\">\n            {showcaseCards.length} verified stays\n          </span>\n        </div>\n\n        <div className=\"grid grid-cols-1 gap-3.5 sm:grid-cols-3\">\n          {showcaseCards.map((card) => {\n            const isFav = !!favorites[card.id];\n            return (\n              <div\n                key={card.id}\n                className=\"group relative flex flex-col justify-between overflow-hidden rounded-2xl border border-neutral-200/90 bg-white p-3 shadow-xs transition-all hover:shadow-md dark:border-neutral-800/90 dark:bg-neutral-900\"\n              >\n                {/* Visual Thumbnail */}\n                <div\n                  className={cn(\n                    \"relative h-28 w-full overflow-hidden rounded-xl bg-gradient-to-br transition group-hover:scale-[1.02]\",\n                    card.gradient\n                  )}\n                >\n                  <button\n                    type=\"button\"\n                    onClick={(e) => {\n                      e.stopPropagation();\n                      toggleFavorite(card.id);\n                    }}\n                    aria-label=\"Save to favorites\"\n                    className=\"absolute right-2 top-2 flex h-7 w-7 items-center justify-center rounded-full bg-black/40 text-white backdrop-blur-md transition hover:scale-110 active:scale-90\"\n                  >\n                    <Heart\n                      className={cn(\n                        \"h-4 w-4 transition-colors\",\n                        isFav ? \"fill-rose-500 text-rose-500\" : \"text-white\"\n                      )}\n                    />\n                  </button>\n                </div>\n\n                {/* Card Details */}\n                <div className=\"mt-2.5\">\n                  <div className=\"flex items-center justify-between\">\n                    <span className=\"truncate text-xs font-semibold text-neutral-900 dark:text-neutral-100\">\n                      {card.location}\n                    </span>\n                    <div className=\"flex items-center gap-1 font-mono text-[11px] font-medium text-neutral-600 dark:text-neutral-300\">\n                      <Star className=\"h-3 w-3 fill-amber-400 text-amber-400\" />\n                      <span>{card.rating.toFixed(2)}</span>\n                    </div>\n                  </div>\n                  <p className=\"line-clamp-1 text-[11px] text-neutral-500 dark:text-neutral-400\">\n                    {card.title}\n                  </p>\n                  <p className=\"text-[10px] text-neutral-400 dark:text-neutral-500\">\n                    {card.dates}\n                  </p>\n                </div>\n\n                <div className=\"mt-2 border-t border-neutral-100 pt-2 flex items-baseline gap-1 dark:border-neutral-800\">\n                  <span className=\"text-xs font-bold text-neutral-900 dark:text-neutral-100\">\n                    {card.price}\n                  </span>\n                  <span className=\"text-[10px] text-neutral-500\">/ night</span>\n                </div>\n              </div>\n            );\n          })}\n        </div>\n      </div>\n\n      {/* Footer quick category switch buttons */}\n      <div className=\"relative z-10 mt-4 flex flex-wrap items-center justify-between gap-2 border-t border-neutral-200/80 pt-3 dark:border-neutral-800/80\">\n        <span className=\"text-xs text-neutral-500\">Jump directly to:</span>\n        <div className=\"flex flex-wrap gap-1.5\">\n          {[\"beachfront\", \"cabins\", \"islands\", \"skiing\"].map((catId) => {\n            const target = CATEGORIES.find((c) => c.id === catId);\n            if (!target) return null;\n            return (\n              <button\n                key={catId}\n                type=\"button\"\n                onClick={() => handleSelect(target)}\n                className=\"rounded-md border border-neutral-200 bg-neutral-50 px-2 py-0.5 text-[11px] font-medium text-neutral-700 transition hover:bg-neutral-100 dark:border-neutral-800 dark:bg-neutral-900 dark:text-neutral-300 dark:hover:bg-neutral-800\"\n              >\n                {target.label}\n              </button>\n            );\n          })}\n        </div>\n      </div>\n    </div>\n  );\n}\n\nexport default CategoryFilterScroller;\n",
          "type": "registry:ui",
          "target": "components/ui/category-filter-scroller.tsx"
        },
        {
          "path": "lib/utils.ts",
          "content": "import { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...inputs: ClassValue[]) {\n  return twMerge(clsx(inputs));\n}\n\nexport async function copyToClipboard(text: string): Promise<boolean> {\n  if (typeof window === \"undefined\") return false;\n\n  try {\n    if (navigator.clipboard && window.isSecureContext) {\n      await navigator.clipboard.writeText(text);\n      return true;\n    }\n\n    const textArea = document.createElement(\"textarea\");\n    textArea.value = text;\n    textArea.style.position = \"fixed\";\n    textArea.style.left = \"-999999px\";\n    textArea.style.top = \"-999999px\";\n    document.body.appendChild(textArea);\n    textArea.focus();\n    textArea.select();\n    const succeeded = document.execCommand(\"copy\");\n    textArea.remove();\n    return succeeded;\n  } catch {\n    return false;\n  }\n}\n",
          "type": "registry:lib",
          "target": "lib/utils.ts"
        }
      ]
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "cipher-scramble-text",
      "type": "registry:ui",
      "title": "Cipher Scramble Text",
      "author": "Rishabh Bose <https://theb0se.vercel.app/>",
      "description": "Cryptographic matrix text decoder that permutes characters through a high-frequency glyph wave on pointer hover, focus, or click.",
      "dependencies": [
        "framer-motion",
        "lucide-react",
        "clsx",
        "tailwind-merge"
      ],
      "files": [
        {
          "path": "components/ui/cipher-scramble-text.tsx",
          "content": "\"use client\";\n\nimport React, { useCallback, useEffect, useRef, useState } from \"react\";\nimport { motion, useReducedMotion } from \"framer-motion\";\nimport { Terminal, RefreshCw } from \"lucide-react\";\nimport { cn } from \"@/lib/utils\";\n\nexport interface CipherScrambleTextProps {\n  /** Target decoded text string. Default: \"ZERO-DEPENDENCY KINETIC PRIMITIVES\" */\n  text?: string;\n  /** Pool of cipher characters used during scramble permutation. */\n  charset?: string;\n  /** Duration of each scramble frame tick in milliseconds. Default: 28 */\n  frameInterval?: number;\n  /** Number of scramble cycles per character before locking in. Default: 2 */\n  cyclesPerChar?: number;\n  className?: string;\n}\n\nconst DEFAULT_CHARSET = \"ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789#$%&*+<>?\";\n\nexport function CipherScrambleText({\n  text = \"ZERO-DEPENDENCY KINETIC PRIMITIVES\",\n  charset = DEFAULT_CHARSET,\n  frameInterval = 28,\n  cyclesPerChar = 2,\n  className,\n}: CipherScrambleTextProps) {\n  const shouldReduceMotion = useReducedMotion() ?? false;\n  const [displayed, setDisplayed] = useState<string>(text);\n  const [isScrambling, setIsScrambling] = useState(false);\n  const timerRef = useRef<ReturnType<typeof setInterval> | null>(null);\n\n  const stopScramble = useCallback(() => {\n    if (timerRef.current) {\n      clearInterval(timerRef.current);\n      timerRef.current = null;\n    }\n    setIsScrambling(false);\n  }, []);\n\n  const triggerScramble = useCallback(() => {\n    if (shouldReduceMotion) {\n      setDisplayed(text);\n      return;\n    }\n\n    stopScramble();\n    setIsScrambling(true);\n\n    let step = 0;\n    const totalSteps = text.length * cyclesPerChar;\n\n    timerRef.current = setInterval(() => {\n      step += 1;\n      const lockedCount = Math.floor(step / cyclesPerChar);\n\n      const nextStr = text\n        .split(\"\")\n        .map((char, idx) => {\n          if (char === \" \") return \" \";\n          if (idx < lockedCount) return char;\n          const randomIndex = Math.floor(Math.random() * charset.length);\n          return charset[randomIndex] || char;\n        })\n        .join(\"\");\n\n      setDisplayed(nextStr);\n\n      if (step >= totalSteps) {\n        setDisplayed(text);\n        stopScramble();\n      }\n    }, frameInterval);\n  }, [text, charset, frameInterval, cyclesPerChar, shouldReduceMotion, stopScramble]);\n\n  useEffect(() => {\n    setDisplayed(text);\n    return () => stopScramble();\n  }, [text, stopScramble]);\n\n  return (\n    <motion.button\n      type=\"button\"\n      onClick={triggerScramble}\n      onMouseEnter={triggerScramble}\n      onFocus={triggerScramble}\n      whileTap={shouldReduceMotion ? undefined : { scale: 0.985 }}\n      transition={{ type: \"spring\", stiffness: 360, damping: 24 }}\n      className={cn(\n        \"group relative inline-flex w-full max-w-lg flex-col items-start justify-between gap-3 rounded-2xl border border-neutral-200 bg-white p-6 text-left transition-colors hover:border-black focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-black dark:border-[#222222] dark:bg-[#0A0A0A] dark:hover:border-white dark:focus-visible:ring-white\",\n        className\n      )}\n    >\n      {/* Screen-reader stable text */}\n      <span className=\"sr-only\">{text}</span>\n\n      <div className=\"flex w-full items-center justify-between text-[11px] font-medium uppercase tracking-widest text-neutral-400\">\n        <span className=\"inline-flex items-center gap-1.5 font-mono\">\n          <Terminal className=\"h-3.5 w-3.5 text-black dark:text-white\" />\n          {isScrambling ? \"DECODING_STREAM...\" : \"CIPHER_LOCKED\"}\n        </span>\n        <RefreshCw\n          aria-hidden=\"true\"\n          className={cn(\n            \"h-3.5 w-3.5 transition-transform duration-300\",\n            isScrambling && \"rotate-180 text-black dark:text-white\"\n          )}\n        />\n      </div>\n\n      <div\n        aria-hidden=\"true\"\n        className=\"font-mono text-base font-bold tracking-tight text-black sm:text-lg dark:text-white\"\n      >\n        {displayed}\n      </div>\n\n      <div className=\"text-[11px] text-neutral-500 dark:text-neutral-400\">\n        Hover, focus, or click to trigger cryptographic glyph wave\n      </div>\n    </motion.button>\n  );\n}\n\nexport default CipherScrambleText;\n",
          "type": "registry:ui",
          "target": "components/ui/cipher-scramble-text.tsx"
        },
        {
          "path": "lib/utils.ts",
          "content": "import { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...inputs: ClassValue[]) {\n  return twMerge(clsx(inputs));\n}\n\nexport async function copyToClipboard(text: string): Promise<boolean> {\n  if (typeof window === \"undefined\") return false;\n\n  try {\n    if (navigator.clipboard && window.isSecureContext) {\n      await navigator.clipboard.writeText(text);\n      return true;\n    }\n\n    const textArea = document.createElement(\"textarea\");\n    textArea.value = text;\n    textArea.style.position = \"fixed\";\n    textArea.style.left = \"-999999px\";\n    textArea.style.top = \"-999999px\";\n    document.body.appendChild(textArea);\n    textArea.focus();\n    textArea.select();\n    const succeeded = document.execCommand(\"copy\");\n    textArea.remove();\n    return succeeded;\n  } catch {\n    return false;\n  }\n}\n",
          "type": "registry:lib",
          "target": "lib/utils.ts"
        }
      ]
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "clouds-drift",
      "type": "registry:ui",
      "title": "Clouds Drift",
      "author": "Rishabh Bose <https://theb0se.vercel.app/>",
      "description": "Seamless multi-layer CSS cloud parallax background where far, mid, and near cloud formations drift horizontally at independent speeds.",
      "dependencies": [
        "lucide-react",
        "clsx",
        "tailwind-merge"
      ],
      "files": [
        {
          "path": "components/ui/clouds-drift.tsx",
          "content": "\"use client\";\n\nimport React, { useState } from \"react\";\nimport { Cloud } from \"lucide-react\";\nimport { cn } from \"@/lib/utils\";\n\nexport type SkyVariant = \"day\" | \"sunset\" | \"night\";\n\nexport interface CloudsDriftProps {\n  /** Drift speed multiplier (1 = default). Default: 1 */\n  speed?: number;\n  /** Cloud layer opacity multiplier (0.2 to 1). Default: 0.85 */\n  opacity?: number;\n  /** Sky color theme. Default: \"day\" */\n  variant?: SkyVariant;\n  /** Optional foreground content */\n  children?: React.ReactNode;\n  className?: string;\n}\n\nconst SKY_THEMES: Record<\n  SkyVariant,\n  { bg: string; cloudFill: string; label: string }\n> = {\n  day: {\n    bg: \"bg-gradient-to-b from-sky-600 via-sky-400 to-sky-200\",\n    cloudFill: \"rgba(255, 255, 255, 0.82)\",\n    label: \"Daylight Cumulus\",\n  },\n  sunset: {\n    bg: \"bg-gradient-to-b from-indigo-950 via-rose-700 to-amber-300\",\n    cloudFill: \"rgba(254, 215, 170, 0.72)\",\n    label: \"Golden Hour\",\n  },\n  night: {\n    bg: \"bg-gradient-to-b from-[#040711] via-[#0B1528] to-[#1E293B]\",\n    cloudFill: \"rgba(148, 163, 184, 0.35)\",\n    label: \"Moonlit Stratus\",\n  },\n};\n\nexport function CloudsDrift({\n  speed = 1,\n  opacity = 0.85,\n  variant = \"day\",\n  children,\n  className,\n}: CloudsDriftProps) {\n  const [activeVariant, setActiveVariant] = useState<SkyVariant>(variant);\n  const theme = SKY_THEMES[activeVariant] ?? SKY_THEMES.day;\n\n  const baseDuration = Math.max(8, 36 / Math.max(0.2, speed));\n\n  const layers = [\n    {\n      id: \"far\",\n      duration: baseDuration * 1.6,\n      top: \"12%\",\n      scale: 0.75,\n      blur: \"blur-xl\",\n      alpha: 0.45 * opacity,\n    },\n    {\n      id: \"mid\",\n      duration: baseDuration * 1.15,\n      top: \"36%\",\n      scale: 1,\n      blur: \"blur-lg\",\n      alpha: 0.7 * opacity,\n    },\n    {\n      id: \"near\",\n      duration: baseDuration * 0.75,\n      top: \"58%\",\n      scale: 1.25,\n      blur: \"blur-md\",\n      alpha: 0.9 * opacity,\n    },\n  ];\n\n  return (\n    <div\n      data-fullscreen-scroll\n      className={cn(\n        \"relative flex min-h-[360px] w-full flex-col justify-between overflow-hidden rounded-3xl border border-neutral-200 p-6 text-white shadow-sm dark:border-neutral-800\",\n        theme.bg,\n        className\n      )}\n    >\n      <style>{`\n        @keyframes bose-cloud-loop {\n          0% { transform: translate3d(0%, 0, 0); }\n          100% { transform: translate3d(-50%, 0, 0); }\n        }\n      `}</style>\n\n      {/* Seamless Looping Parallax Cloud Layers */}\n      <div\n        aria-hidden=\"true\"\n        className=\"pointer-events-none absolute inset-0 overflow-hidden\"\n      >\n        {layers.map((layer) => (\n          <div\n            key={layer.id}\n            style={{\n              top: layer.top,\n              opacity: layer.alpha,\n              animation: `bose-cloud-loop ${layer.duration}s linear infinite`,\n            }}\n            className={cn(\"absolute left-0 flex w-[200%]\", layer.blur)}\n          >\n            {[0, 1].map((dup) => (\n              <div\n                key={dup}\n                className=\"relative flex h-36 w-1/2 items-center justify-around\"\n              >\n                {/* Cloud Formation A */}\n                <div\n                  style={{\n                    background: theme.cloudFill,\n                    transform: `scale(${layer.scale})`,\n                  }}\n                  className=\"h-16 w-48 rounded-full shadow-2xl\"\n                />\n                {/* Cloud Formation B */}\n                <div\n                  style={{\n                    background: theme.cloudFill,\n                    transform: `scale(${layer.scale * 1.15})`,\n                  }}\n                  className=\"-mt-8 h-20 w-64 rounded-full shadow-2xl\"\n                />\n                {/* Cloud Formation C */}\n                <div\n                  style={{\n                    background: theme.cloudFill,\n                    transform: `scale(${layer.scale * 0.9})`,\n                  }}\n                  className=\"mt-6 h-14 w-44 rounded-full shadow-2xl\"\n                />\n              </div>\n            ))}\n          </div>\n        ))}\n      </div>\n\n      {/* Foreground Content */}\n      <div className=\"relative z-10 flex flex-1 flex-col justify-between\">\n        {children ?? (\n          <>\n            <div className=\"flex flex-wrap items-center justify-between gap-2\">\n              <span className=\"inline-flex items-center gap-1.5 rounded-full border border-white/25 bg-black/25 px-3 py-1 font-mono text-[11px] font-medium text-white backdrop-blur-md\">\n                <Cloud className=\"h-3.5 w-3.5\" />\n                Clouds Drift · {theme.label}\n              </span>\n\n              <div className=\"flex items-center gap-1 rounded-full border border-white/25 bg-black/25 p-1 backdrop-blur-md\">\n                {([\"day\", \"sunset\", \"night\"] as SkyVariant[]).map((v) => (\n                  <button\n                    key={v}\n                    type=\"button\"\n                    onClick={() => setActiveVariant(v)}\n                    className={cn(\n                      \"rounded-full px-2.5 py-0.5 font-mono text-[10px] font-semibold uppercase transition-colors\",\n                      activeVariant === v\n                        ? \"bg-white text-black\"\n                        : \"text-white/80 hover:text-white\"\n                    )}\n                  >\n                    {v}\n                  </button>\n                ))}\n              </div>\n            </div>\n\n            <div className=\"my-auto max-w-md py-8\">\n              <h3 className=\"text-2xl font-bold tracking-tight text-white drop-shadow-sm sm:text-3xl\">\n                Parallax Cloud Layers\n              </h3>\n              <p className=\"mt-2 text-xs leading-relaxed text-white/90 drop-shadow-xs sm:text-sm\">\n                Three altitude layers of soft diffused cloud ellipses moving at\n                independent <code className=\"font-mono\">translate3d</code>{\" \"}\n                velocities for seamless infinite drift.\n              </p>\n            </div>\n\n            <div className=\"font-mono text-[11px] text-white/75\">\n              Pure CSS · 3 Parallax Layers · Seamless Loop\n            </div>\n          </>\n        )}\n      </div>\n    </div>\n  );\n}\n\nexport default CloudsDrift;\n",
          "type": "registry:ui",
          "target": "components/ui/clouds-drift.tsx"
        },
        {
          "path": "lib/utils.ts",
          "content": "import { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...inputs: ClassValue[]) {\n  return twMerge(clsx(inputs));\n}\n\nexport async function copyToClipboard(text: string): Promise<boolean> {\n  if (typeof window === \"undefined\") return false;\n\n  try {\n    if (navigator.clipboard && window.isSecureContext) {\n      await navigator.clipboard.writeText(text);\n      return true;\n    }\n\n    const textArea = document.createElement(\"textarea\");\n    textArea.value = text;\n    textArea.style.position = \"fixed\";\n    textArea.style.left = \"-999999px\";\n    textArea.style.top = \"-999999px\";\n    document.body.appendChild(textArea);\n    textArea.focus();\n    textArea.select();\n    const succeeded = document.execCommand(\"copy\");\n    textArea.remove();\n    return succeeded;\n  } catch {\n    return false;\n  }\n}\n",
          "type": "registry:lib",
          "target": "lib/utils.ts"
        }
      ]
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "color-finish-picker",
      "type": "registry:ui",
      "title": "Color Finish Picker",
      "author": "Rishabh Bose <https://theb0se.vercel.app/>",
      "description": "Apple-style device finish selector featuring concentric selection rings, synchronized ambient page background tinting, crossfading vector hardware graphics, and technical metallurgy specifications.",
      "dependencies": [
        "framer-motion",
        "lucide-react",
        "clsx",
        "tailwind-merge"
      ],
      "files": [
        {
          "path": "components/ui/color-finish-picker.tsx",
          "content": "\"use client\";\n\nimport React, { useState } from \"react\";\nimport { motion, AnimatePresence } from \"framer-motion\";\nimport { Sparkles, Shield, Cpu, Info, Check, Eye } from \"lucide-react\";\nimport { cn } from \"@/lib/utils\";\n\nexport interface ColorFinish {\n  id: string;\n  name: string;\n  tagline: string;\n  hex: string;\n  secondaryHex: string;\n  ambientRgba: string;\n  specs: {\n    alloy: string;\n    coating: string;\n    reflectance: string;\n    finishTone: string;\n  };\n}\n\nexport interface ColorFinishPickerProps {\n  /** Array of available color finishes */\n  finishes?: ColorFinish[];\n  /** Default selected finish ID */\n  defaultFinishId?: string;\n  /** Callback when finish changes */\n  onChange?: (finish: ColorFinish) => void;\n  /** Whether to show the top header and angle toggle */\n  showHeader?: boolean;\n  /** Custom container class names */\n  className?: string;\n}\n\nconst DEFAULT_FINISHES: ColorFinish[] = [\n  {\n    id: \"natural-titanium\",\n    name: \"Natural Titanium\",\n    tagline: \"Raw aerospace metallurgy with warm industrial character\",\n    hex: \"#9B9994\",\n    secondaryHex: \"#777570\",\n    ambientRgba: \"rgba(155, 153, 148, 0.16)\",\n    specs: {\n      alloy: \"Grade 5 (Ti-6Al-4V)\",\n      coating: \"Sub-micron PVD satin etch\",\n      reflectance: \"14% Diffuse Metallic\",\n      finishTone: \"Warm Pewter Neutral\",\n    },\n  },\n  {\n    id: \"desert-titanium\",\n    name: \"Desert Titanium\",\n    tagline: \"Golden bronze iridescence inspired by desert quartz formations\",\n    hex: \"#C4AFA0\",\n    secondaryHex: \"#9E8575\",\n    ambientRgba: \"rgba(196, 175, 160, 0.22)\",\n    specs: {\n      alloy: \"Grade 5 (Ti-6Al-4V)\",\n      coating: \"Gold-Zirconium ion bond\",\n      reflectance: \"18% Luminous Sheen\",\n      finishTone: \"Warm Amber Champagne\",\n    },\n  },\n  {\n    id: \"white-titanium\",\n    name: \"White Titanium\",\n    tagline: \"Pure pristine silver-white with hyper-clarity ceramic glass\",\n    hex: \"#E5E5E7\",\n    secondaryHex: \"#B8B8BC\",\n    ambientRgba: \"rgba(229, 229, 231, 0.20)\",\n    specs: {\n      alloy: \"Grade 5 (Ti-6Al-4V)\",\n      coating: \"Optically clear nano-ceramic seal\",\n      reflectance: \"26% Specular Reflection\",\n      finishTone: \"Cool Glacial Platinum\",\n    },\n  },\n  {\n    id: \"black-titanium\",\n    name: \"Black Titanium\",\n    tagline: \"Deep space carbon-dark alloy with light-absorbing micro-texture\",\n    hex: \"#343438\",\n    secondaryHex: \"#1E1E22\",\n    ambientRgba: \"rgba(52, 52, 56, 0.35)\",\n    specs: {\n      alloy: \"Grade 5 (Ti-6Al-4V)\",\n      coating: \"Diamond-Like Carbon (DLC)\",\n      reflectance: \"4% Deep Matte Absorptive\",\n      finishTone: \"Midnight Obsidian\",\n    },\n  },\n];\n\nexport function ColorFinishPicker({\n  finishes = DEFAULT_FINISHES,\n  defaultFinishId = \"natural-titanium\",\n  onChange,\n  showHeader = true,\n  className,\n}: ColorFinishPickerProps) {\n  const [selectedId, setSelectedId] = useState(defaultFinishId);\n  const [viewAngle, setViewAngle] = useState<\"rear\" | \"profile\" | \"camera\">(\"rear\");\n  const [showSpecs, setShowSpecs] = useState(true);\n\n  const activeFinish =\n    finishes.find((f) => f.id === selectedId) || finishes[0];\n\n  const handleSelect = (finish: ColorFinish) => {\n    setSelectedId(finish.id);\n    onChange?.(finish);\n  };\n\n  return (\n    <div\n      data-fullscreen-scroll\n      className={cn(\n        \"relative w-full min-h-[520px] overflow-hidden rounded-2xl border border-neutral-200/80 bg-neutral-950 p-6 text-neutral-100 shadow-2xl transition-all dark:border-neutral-800\",\n        className\n      )}\n    >\n      {/* Dynamic Synchronized Ambient Page Tinting */}\n      <div\n        className=\"pointer-events-none absolute inset-0 transition-all duration-700 ease-out\"\n        style={{\n          background: `radial-gradient(circle 700px at 50% 38%, ${activeFinish.ambientRgba}, transparent 70%),\n                       radial-gradient(circle 500px at 80% 85%, ${activeFinish.ambientRgba}, transparent 65%)`,\n        }}\n      />\n\n      {/* Header Bar */}\n      {showHeader && (\n        <div className=\"relative z-10 flex flex-wrap items-center justify-between gap-4 border-b border-neutral-800/80 pb-4\">\n          <div>\n            <div className=\"inline-flex items-center gap-2 rounded-full border border-neutral-800 bg-neutral-900/90 px-3 py-1 text-xs font-medium text-neutral-300 backdrop-blur-md\">\n              <Sparkles className=\"h-3 w-3 text-amber-400\" />\n              Finish & Material Studio\n            </div>\n            <h2 className=\"mt-2 text-xl font-semibold tracking-tight text-white\">\n              Apple Titanium Finishes\n            </h2>\n            <p className=\"text-xs text-neutral-400\">\n              Select a metallic finish to crossfade precision aerospace graphics and synchronized ambient lighting\n            </p>\n          </div>\n\n          {/* View Angle Toggle */}\n          <div className=\"flex items-center gap-1.5 rounded-xl border border-neutral-800 bg-neutral-900/90 p-1\">\n            {([\"rear\", \"profile\", \"camera\"] as const).map((view) => (\n              <button\n                key={view}\n                type=\"button\"\n                onClick={() => setViewAngle(view)}\n                className={cn(\n                  \"rounded-lg px-2.5 py-1 text-xs font-medium capitalize transition\",\n                  viewAngle === view\n                    ? \"bg-neutral-800 text-white shadow-sm\"\n                    : \"text-neutral-400 hover:text-white\"\n                )}\n              >\n                {view} view\n              </button>\n            ))}\n          </div>\n        </div>\n      )}\n\n      {/* Main Interactive Stage */}\n      <div className=\"relative z-10 grid grid-cols-1 items-center gap-8 py-6 lg:grid-cols-12\">\n        {/* Left / Center Graphic: Crossfading Device Model */}\n        <div className=\"flex min-h-[340px] items-center justify-center lg:col-span-7\">\n          <AnimatePresence mode=\"wait\">\n            <motion.div\n              key={`${activeFinish.id}-${viewAngle}`}\n              initial={{ opacity: 0, scale: 0.94, filter: \"blur(6px)\" }}\n              animate={{ opacity: 1, scale: 1, filter: \"blur(0px)\" }}\n              exit={{ opacity: 0, scale: 1.04, filter: \"blur(6px)\" }}\n              transition={{ duration: 0.45, ease: [0.16, 1, 0.3, 1] }}\n              className=\"relative flex items-center justify-center\"\n            >\n              <svg\n                width=\"280\"\n                height=\"340\"\n                viewBox=\"0 0 280 340\"\n                className=\"overflow-visible filter drop-shadow-[0_25px_40px_rgba(0,0,0,0.8)]\"\n              >\n                <defs>\n                  {/* Active finish metallic chassis gradient */}\n                  <linearGradient id={`frameGrad-${activeFinish.id}`} x1=\"0%\" y1=\"0%\" x2=\"100%\" y2=\"100%\">\n                    <stop offset=\"0%\" stopColor={activeFinish.hex} />\n                    <stop offset=\"25%\" stopColor=\"#ffffff\" stopOpacity={0.6} />\n                    <stop offset=\"50%\" stopColor={activeFinish.secondaryHex} />\n                    <stop offset=\"80%\" stopColor={activeFinish.hex} />\n                    <stop offset=\"100%\" stopColor={activeFinish.secondaryHex} />\n                  </linearGradient>\n\n                  {/* Back glass matte gradient */}\n                  <linearGradient id={`glassGrad-${activeFinish.id}`} x1=\"0%\" y1=\"0%\" x2=\"70%\" y2=\"100%\">\n                    <stop offset=\"0%\" stopColor={activeFinish.hex} stopOpacity={0.85} />\n                    <stop offset=\"100%\" stopColor={activeFinish.secondaryHex} stopOpacity={0.95} />\n                  </linearGradient>\n\n                  {/* Camera plateau frosted gradient */}\n                  <linearGradient id={`plateauGrad-${activeFinish.id}`} x1=\"0%\" y1=\"0%\" x2=\"100%\" y2=\"100%\">\n                    <stop offset=\"0%\" stopColor={activeFinish.hex} stopOpacity={0.95} />\n                    <stop offset=\"100%\" stopColor={activeFinish.secondaryHex} stopOpacity={0.7} />\n                  </linearGradient>\n                </defs>\n\n                {/* Render Based on Selected View Angle */}\n                {viewAngle === \"rear\" && (\n                  <g transform=\"translate(140, 170)\">\n                    {/* Device Chassis Outer Frame */}\n                    <rect\n                      x=\"-100\"\n                      y=\"-155\"\n                      width=\"200\"\n                      height=\"310\"\n                      rx=\"42\"\n                      fill={`url(#frameGrad-${activeFinish.id})`}\n                      stroke=\"rgba(255,255,255,0.2)\"\n                      strokeWidth=\"2\"\n                    />\n\n                    {/* Back Matte Glass Texture */}\n                    <rect\n                      x=\"-96\"\n                      y=\"-151\"\n                      width=\"192\"\n                      height=\"302\"\n                      rx=\"38\"\n                      fill={`url(#glassGrad-${activeFinish.id})`}\n                    />\n\n                    {/* Apple Logo Silhouette in Finish Sheen */}\n                    <path\n                      d=\"M 0,-15 C 3,-15 7,-18 7,-23 C 2,-23 -2,-18 0,-15 Z M 9,-8 C 4,-9 0,-5 0,-5 C 0,-5 -4,-9 -9,-8 C -14,-7 -17, -2 -17, 8 C -17, 19 -9, 28 0, 28 C 9, 28 17, 19 17, 8 C 17,-2 14,-7 9,-8 Z\"\n                      fill=\"rgba(255,255,255,0.25)\"\n                      transform=\"translate(0, 15) scale(0.65)\"\n                    />\n\n                    {/* Camera Island Plateau */}\n                    <rect\n                      x=\"-84\"\n                      y=\"-138\"\n                      width=\"92\"\n                      height=\"92\"\n                      rx=\"24\"\n                      fill={`url(#plateauGrad-${activeFinish.id})`}\n                      stroke=\"rgba(255,255,255,0.25)\"\n                      strokeWidth=\"1.5\"\n                    />\n\n                    {/* Three Pro Lens Rings */}\n                    {/* Top Lens (Main 48MP) */}\n                    <circle cx=\"-58\" cy=\"-114\" r=\"17\" fill=\"#0C0D10\" stroke={activeFinish.hex} strokeWidth=\"2.5\" />\n                    <circle cx=\"-58\" cy=\"-114\" r=\"11\" fill=\"#141720\" stroke=\"#374151\" strokeWidth=\"1\" />\n                    <circle cx=\"-55\" cy=\"-117\" r=\"4\" fill=\"rgba(255,255,255,0.4)\" />\n\n                    {/* Bottom Lens (Ultra Wide) */}\n                    <circle cx=\"-58\" cy=\"-70\" r=\"17\" fill=\"#0C0D10\" stroke={activeFinish.hex} strokeWidth=\"2.5\" />\n                    <circle cx=\"-58\" cy=\"-70\" r=\"11\" fill=\"#141720\" stroke=\"#374151\" strokeWidth=\"1\" />\n                    <circle cx=\"-55\" cy=\"-73\" r=\"4\" fill=\"rgba(255,255,255,0.4)\" />\n\n                    {/* Right Lens (5x Telephoto Tetraprism) */}\n                    <circle cx=\"-16\" cy=\"-92\" r=\"17\" fill=\"#0C0D10\" stroke={activeFinish.hex} strokeWidth=\"2.5\" />\n                    <circle cx=\"-16\" cy=\"-92\" r=\"11\" fill=\"#141720\" stroke=\"#374151\" strokeWidth=\"1\" />\n                    <circle cx=\"-13\" cy=\"-95\" r=\"4\" fill=\"rgba(255,255,255,0.4)\" />\n\n                    {/* True Tone Flash & LiDAR */}\n                    <circle cx=\"-16\" cy=\"-122\" r=\"6\" fill=\"#FDE68A\" stroke=\"#D97706\" strokeWidth=\"1\" />\n                    <circle cx=\"-16\" cy=\"-62\" r=\"4\" fill=\"#1F2937\" stroke=\"#111827\" strokeWidth=\"1\" />\n                  </g>\n                )}\n\n                {viewAngle === \"profile\" && (\n                  <g transform=\"translate(140, 170)\">\n                    {/* Profile Edge: Micro-blasted titanium rail */}\n                    <rect\n                      x=\"-14\"\n                      y=\"-155\"\n                      width=\"28\"\n                      height=\"310\"\n                      rx=\"14\"\n                      fill={`url(#frameGrad-${activeFinish.id})`}\n                      stroke=\"rgba(255,255,255,0.3)\"\n                      strokeWidth=\"1.5\"\n                    />\n\n                    {/* Antenna Band lines */}\n                    <line x1=\"-14\" y1=\"-100\" x2=\"14\" y2=\"-100\" stroke=\"#1F2430\" strokeWidth=\"2\" />\n                    <line x1=\"-14\" y1=\"100\" x2=\"14\" y2=\"100\" stroke=\"#1F2430\" strokeWidth=\"2\" />\n\n                    {/* Action Button */}\n                    <rect x=\"12\" y=\"-70\" width=\"4\" height=\"24\" rx=\"2\" fill={activeFinish.secondaryHex} stroke=\"#FFFFFF\" strokeWidth=\"0.8\" />\n\n                    {/* Volume Up / Down Buttons */}\n                    <rect x=\"12\" y=\"-35\" width=\"4\" height=\"32\" rx=\"2\" fill={activeFinish.secondaryHex} />\n                    <rect x=\"12\" y=\"5\" width=\"4\" height=\"32\" rx=\"2\" fill={activeFinish.secondaryHex} />\n\n                    {/* Camera Plateau Profile Bump */}\n                    <path\n                      d=\"M -14,-135 L -26,-130 L -26,-55 L -14,-50 Z\"\n                      fill={`url(#plateauGrad-${activeFinish.id})`}\n                      stroke=\"rgba(255,255,255,0.2)\"\n                      strokeWidth=\"1.2\"\n                    />\n                  </g>\n                )}\n\n                {viewAngle === \"camera\" && (\n                  <g transform=\"translate(140, 170)\">\n                    {/* Macro Close-up Camera Plateau & Tetraprism ring */}\n                    <circle cx=\"0\" cy=\"0\" r=\"105\" fill={`url(#plateauGrad-${activeFinish.id})`} stroke=\"rgba(255,255,255,0.2)\" strokeWidth=\"2\" />\n                    \n                    {/* Concentric Macro Lens Ring */}\n                    <circle cx=\"0\" cy=\"0\" r=\"82\" fill=\"#0E1015\" stroke={activeFinish.hex} strokeWidth=\"7\" />\n                    <circle cx=\"0\" cy=\"0\" r=\"68\" fill=\"#171A24\" stroke=\"rgba(255,255,255,0.15)\" strokeWidth=\"1.5\" />\n                    <circle cx=\"0\" cy=\"0\" r=\"50\" fill=\"#08090C\" />\n                    <circle cx=\"0\" cy=\"0\" r=\"30\" fill=\"#0F172A\" stroke=\"#3B82F6\" strokeWidth=\"1\" opacity=\"0.6\" />\n\n                    {/* Specular glare arcs */}\n                    <path d=\"M -45 -45 A 64 64 0 0 1 45 -45\" fill=\"none\" stroke=\"rgba(255,255,255,0.4)\" strokeWidth=\"3\" strokeLinecap=\"round\" />\n                    <text x=\"0\" y=\"8\" fill=\"#9CA3AF\" fontSize=\"10\" textAnchor=\"middle\" fontFamily=\"monospace\">48MP • ƒ/1.78</text>\n                  </g>\n                )}\n              </svg>\n            </motion.div>\n          </AnimatePresence>\n        </div>\n\n        {/* Right Column: Swatches with Concentric Rings & Specs */}\n        <div className=\"space-y-6 lg:col-span-5\">\n          {/* Active Finish Title & Description */}\n          <div>\n            <span className=\"text-[11px] font-semibold uppercase tracking-wider text-neutral-400\">\n              Titanium Alloy Finish\n            </span>\n            <h3 className=\"mt-1 text-2xl font-bold tracking-tight text-white\">\n              {activeFinish.name}\n            </h3>\n            <p className=\"mt-1 text-xs text-neutral-400 leading-relaxed\">\n              {activeFinish.tagline}\n            </p>\n          </div>\n\n          {/* Circular Swatches with Apple-style Concentric Selection Rings */}\n          <div className=\"space-y-2\">\n            <label className=\"text-xs font-medium text-neutral-300\">\n              Select Finish\n            </label>\n            <div className=\"flex items-center gap-3.5 pt-1\">\n              {finishes.map((finish) => {\n                const isSelected = finish.id === activeFinish.id;\n                return (\n                  <button\n                    key={finish.id}\n                    type=\"button\"\n                    onClick={() => handleSelect(finish)}\n                    aria-label={`Select ${finish.name}`}\n                    className=\"group relative flex items-center justify-center p-1 focus:outline-none\"\n                  >\n                    {/* Concentric Selection Outer Ring */}\n                    <div\n                      className={cn(\n                        \"flex h-11 w-11 items-center justify-center rounded-full transition-all duration-300\",\n                        isSelected\n                          ? \"ring-2 ring-white ring-offset-2 ring-offset-neutral-950 scale-105\"\n                          : \"ring-1 ring-neutral-700/60 hover:ring-neutral-500 hover:scale-105\"\n                      )}\n                    >\n                      {/* Inner Color Swatch Circle */}\n                      <span\n                        className=\"h-8 w-8 rounded-full shadow-inner transition-transform group-hover:scale-95\"\n                        style={{\n                          backgroundColor: finish.hex,\n                          boxShadow: `inset 0 1px 2px rgba(255,255,255,0.4), inset 0 -2px 3px rgba(0,0,0,0.5)`,\n                        }}\n                      />\n                    </div>\n\n                    {/* Tooltip on Hover */}\n                    <span className=\"pointer-events-none absolute -bottom-7 whitespace-nowrap rounded-md bg-neutral-900 px-2 py-0.5 text-[10px] font-medium text-neutral-200 opacity-0 shadow-lg ring-1 ring-neutral-700 transition-opacity group-hover:opacity-100\">\n                      {finish.name}\n                    </span>\n                  </button>\n                );\n              })}\n            </div>\n          </div>\n\n          {/* Technical Material Specifications */}\n          <div className=\"rounded-xl border border-neutral-800/80 bg-neutral-900/60 p-4 backdrop-blur-md\">\n            <div className=\"flex items-center justify-between pb-3 border-b border-neutral-800/70\">\n              <span className=\"flex items-center gap-1.5 text-xs font-medium text-neutral-300\">\n                <Shield className=\"h-3.5 w-3.5 text-neutral-400\" />\n                Material Metallurgy\n              </span>\n              <span className=\"text-[11px] font-mono text-neutral-400\">\n                {activeFinish.specs.alloy}\n              </span>\n            </div>\n\n            <div className=\"mt-3 grid grid-cols-2 gap-3 text-xs\">\n              <div>\n                <span className=\"text-[10px] text-neutral-500 block uppercase tracking-wider\">\n                  Surface Treatment\n                </span>\n                <span className=\"font-medium text-neutral-200\">\n                  {activeFinish.specs.coating}\n                </span>\n              </div>\n              <div>\n                <span className=\"text-[10px] text-neutral-500 block uppercase tracking-wider\">\n                  Optical Sheen\n                </span>\n                <span className=\"font-medium text-neutral-200\">\n                  {activeFinish.specs.reflectance}\n                </span>\n              </div>\n              <div className=\"col-span-2 pt-1 border-t border-neutral-800/50\">\n                <span className=\"text-[10px] text-neutral-500 block uppercase tracking-wider\">\n                  Chroma Profile\n                </span>\n                <span className=\"font-medium text-neutral-200\">\n                  {activeFinish.specs.finishTone}\n                </span>\n              </div>\n            </div>\n          </div>\n        </div>\n      </div>\n    </div>\n  );\n}\n\nexport default ColorFinishPicker;\n",
          "type": "registry:ui",
          "target": "components/ui/color-finish-picker.tsx"
        },
        {
          "path": "lib/utils.ts",
          "content": "import { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...inputs: ClassValue[]) {\n  return twMerge(clsx(inputs));\n}\n\nexport async function copyToClipboard(text: string): Promise<boolean> {\n  if (typeof window === \"undefined\") return false;\n\n  try {\n    if (navigator.clipboard && window.isSecureContext) {\n      await navigator.clipboard.writeText(text);\n      return true;\n    }\n\n    const textArea = document.createElement(\"textarea\");\n    textArea.value = text;\n    textArea.style.position = \"fixed\";\n    textArea.style.left = \"-999999px\";\n    textArea.style.top = \"-999999px\";\n    document.body.appendChild(textArea);\n    textArea.focus();\n    textArea.select();\n    const succeeded = document.execCommand(\"copy\");\n    textArea.remove();\n    return succeeded;\n  } catch {\n    return false;\n  }\n}\n",
          "type": "registry:lib",
          "target": "lib/utils.ts"
        }
      ]
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "command-menu",
      "type": "registry:ui",
      "title": "Command Menu",
      "author": "Rishabh Bose <https://theb0se.vercel.app/>",
      "description": "Spotlight-style Cmd+K command palette portaled above the viewport with grouped actions, live keyword filtering, and full keyboard navigation.",
      "dependencies": [
        "framer-motion",
        "lucide-react",
        "clsx",
        "tailwind-merge"
      ],
      "files": [
        {
          "path": "components/ui/command-menu.tsx",
          "content": "\"use client\";\n\nimport React, { useState, useEffect, useMemo, useRef } from \"react\";\nimport { createPortal } from \"react-dom\";\nimport { AnimatePresence, motion, useReducedMotion } from \"framer-motion\";\nimport {\n  Search,\n  Command,\n  CornerDownLeft,\n  ArrowUp,\n  ArrowDown,\n  FileCode2,\n  Terminal,\n  Sparkles,\n  Settings,\n  Layers,\n  Moon,\n  Copy,\n  CheckCircle2,\n  X,\n} from \"lucide-react\";\nimport { cn } from \"@/lib/utils\";\n\nexport interface CommandItem {\n  id: string;\n  label: string;\n  group: string;\n  shortcut?: string;\n  keywords?: string[];\n  icon?: React.ReactNode;\n  onSelect?: () => void;\n}\n\nexport interface CommandMenuProps {\n  /** Array of command items grouped by their `group` property */\n  items?: CommandItem[];\n  /** Search input placeholder */\n  placeholder?: string;\n  /** Label on the trigger button */\n  triggerLabel?: string;\n  /** Enable global Cmd+K / Ctrl+K shortcut listener. Default: true */\n  enableGlobalShortcut?: boolean;\n  /** Controlled open state */\n  open?: boolean;\n  /** Callback when open state changes */\n  onOpenChange?: (open: boolean) => void;\n  /** Callback fired when any command item is selected */\n  onSelect?: (item: CommandItem) => void;\n  /** Empty state message when no commands match */\n  emptyMessage?: string;\n  className?: string;\n}\n\nconst DEFAULT_COMMANDS: CommandItem[] = [\n  {\n    id: \"new-component\",\n    label: \"Create New Component\",\n    group: \"Quick Actions\",\n    shortcut: \"⌘ N\",\n    keywords: [\"add\", \"generate\", \"ui\", \"template\"],\n    icon: <Sparkles className=\"h-4 w-4\" />,\n  },\n  {\n    id: \"copy-cli\",\n    label: \"Copy CLI Install Command\",\n    group: \"Quick Actions\",\n    shortcut: \"⌘ C\",\n    keywords: [\"npx\", \"shadcn\", \"registry\", \"terminal\"],\n    icon: <Terminal className=\"h-4 w-4\" />,\n  },\n  {\n    id: \"copy-theme\",\n    label: \"Copy Tailwind Config Tokens\",\n    group: \"Quick Actions\",\n    shortcut: \"⇧ ⌘ C\",\n    keywords: [\"css\", \"styles\", \"tokens\"],\n    icon: <Copy className=\"h-4 w-4\" />,\n  },\n  {\n    id: \"nav-components\",\n    label: \"Browse All Components\",\n    group: \"Navigation\",\n    shortcut: \"G C\",\n    keywords: [\"catalog\", \"gallery\", \"list\"],\n    icon: <Layers className=\"h-4 w-4\" />,\n  },\n  {\n    id: \"nav-docs\",\n    label: \"Open Documentation & Guides\",\n    group: \"Navigation\",\n    shortcut: \"G D\",\n    keywords: [\"help\", \"readme\", \"setup\"],\n    icon: <FileCode2 className=\"h-4 w-4\" />,\n  },\n  {\n    id: \"pref-theme\",\n    label: \"Toggle Dark / Light Appearance\",\n    group: \"Preferences\",\n    shortcut: \"⌘ J\",\n    keywords: [\"dark mode\", \"light mode\", \"theme\"],\n    icon: <Moon className=\"h-4 w-4\" />,\n  },\n  {\n    id: \"pref-settings\",\n    label: \"Workspace Settings\",\n    group: \"Preferences\",\n    shortcut: \"⌘ ,\",\n    keywords: [\"config\", \"account\", \"preferences\"],\n    icon: <Settings className=\"h-4 w-4\" />,\n  },\n];\n\nexport function CommandMenu({\n  items = DEFAULT_COMMANDS,\n  placeholder = \"Type a command or search...\",\n  triggerLabel = \"Search commands...\",\n  enableGlobalShortcut = true,\n  open: controlledOpen,\n  onOpenChange,\n  onSelect,\n  emptyMessage = \"No matching commands found.\",\n  className,\n}: CommandMenuProps) {\n  const shouldReduceMotion = useReducedMotion() ?? false;\n  const [mounted, setMounted] = useState(false);\n  const [internalOpen, setInternalOpen] = useState(false);\n  const [query, setQuery] = useState(\"\");\n  const [activeIndex, setActiveIndex] = useState(0);\n  const [lastExecuted, setLastExecuted] = useState<string | null>(null);\n\n  const inputRef = useRef<HTMLInputElement>(null);\n  const listRef = useRef<HTMLDivElement>(null);\n\n  const isControlled = controlledOpen !== undefined;\n  const isOpen = isControlled ? controlledOpen : internalOpen;\n\n  useEffect(() => {\n    setMounted(true);\n  }, []);\n\n  const setOpen = (next: boolean) => {\n    if (!isControlled) {\n      setInternalOpen(next);\n    }\n    if (!next) {\n      setQuery(\"\");\n      setActiveIndex(0);\n    }\n    onOpenChange?.(next);\n  };\n\n  const filteredItems = useMemo(() => {\n    const q = query.trim().toLowerCase();\n    if (!q) return items;\n    return items.filter(\n      (item) =>\n        item.label.toLowerCase().includes(q) ||\n        item.group.toLowerCase().includes(q) ||\n        (item.keywords?.some((k) => k.toLowerCase().includes(q)) ?? false)\n    );\n  }, [items, query]);\n\n  const groupedItems = useMemo(() => {\n    const groups: { group: string; entries: { item: CommandItem; flatIndex: number }[] }[] = [];\n    let counter = 0;\n\n    filteredItems.forEach((item) => {\n      let existing = groups.find((g) => g.group === item.group);\n      if (!existing) {\n        existing = { group: item.group, entries: [] };\n        groups.push(existing);\n      }\n      existing.entries.push({ item, flatIndex: counter });\n      counter += 1;\n    });\n\n    return groups;\n  }, [filteredItems]);\n\n  useEffect(() => {\n    setActiveIndex(0);\n  }, [query]);\n\n  // Global Cmd+K / Ctrl+K listener\n  useEffect(() => {\n    if (!enableGlobalShortcut) return;\n    const handleGlobalKeyDown = (e: KeyboardEvent) => {\n      if ((e.metaKey || e.ctrlKey) && e.key.toLowerCase() === \"k\") {\n        e.preventDefault();\n        setOpen(!isOpen);\n      }\n    };\n    window.addEventListener(\"keydown\", handleGlobalKeyDown);\n    return () => window.removeEventListener(\"keydown\", handleGlobalKeyDown);\n  }, [enableGlobalShortcut, isOpen]);\n\n  // Lock body scroll and focus input when open\n  useEffect(() => {\n    if (!isOpen) return;\n    const prevOverflow = document.body.style.overflow;\n    document.body.style.overflow = \"hidden\";\n    const timer = setTimeout(() => inputRef.current?.focus(), 20);\n    return () => {\n      document.body.style.overflow = prevOverflow;\n      clearTimeout(timer);\n    };\n  }, [isOpen]);\n\n  // Scroll active command into view\n  useEffect(() => {\n    if (!isOpen || !listRef.current) return;\n    const activeEl = listRef.current.querySelector<HTMLElement>(\n      `[data-cmd-index=\"${activeIndex}\"]`\n    );\n    activeEl?.scrollIntoView({ block: \"nearest\" });\n  }, [activeIndex, isOpen]);\n\n  const handleSelect = (item: CommandItem) => {\n    item.onSelect?.();\n    onSelect?.(item);\n    setLastExecuted(item.label);\n    setOpen(false);\n  };\n\n  const handleKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {\n    if (e.key === \"ArrowDown\") {\n      e.preventDefault();\n      if (filteredItems.length > 0) {\n        setActiveIndex((prev) => (prev + 1) % filteredItems.length);\n      }\n    } else if (e.key === \"ArrowUp\") {\n      e.preventDefault();\n      if (filteredItems.length > 0) {\n        setActiveIndex(\n          (prev) => (prev - 1 + filteredItems.length) % filteredItems.length\n        );\n      }\n    } else if (e.key === \"Enter\" && filteredItems[activeIndex]) {\n      e.preventDefault();\n      handleSelect(filteredItems[activeIndex]);\n    } else if (e.key === \"Escape\") {\n      e.preventDefault();\n      setOpen(false);\n    }\n  };\n\n  return (\n    <div className={cn(\"inline-flex flex-col items-center gap-2.5\", className)}>\n      {/* Search Bar Trigger */}\n      <button\n        type=\"button\"\n        onClick={() => setOpen(true)}\n        className=\"group flex h-11 w-full min-w-[260px] max-w-sm items-center justify-between gap-4 rounded-xl border border-neutral-200 bg-white px-3.5 text-xs text-neutral-500 shadow-sm transition-all hover:border-black hover:text-black focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-black dark:border-[#262626] dark:bg-[#0A0A0A] dark:text-neutral-400 dark:hover:border-white dark:hover:text-white dark:focus-visible:ring-white\"\n      >\n        <span className=\"flex items-center gap-2.5\">\n          <Search className=\"h-3.5 w-3.5 text-neutral-400 transition-colors group-hover:text-black dark:group-hover:text-white\" />\n          <span className=\"font-medium\">{triggerLabel}</span>\n        </span>\n        <kbd className=\"inline-flex items-center gap-0.5 rounded-md border border-neutral-200 bg-neutral-100 px-1.5 py-0.5 font-mono text-[10px] font-semibold text-neutral-600 dark:border-[#262626] dark:bg-[#141414] dark:text-neutral-400\">\n          <Command className=\"h-2.5 w-2.5\" />K\n        </kbd>\n      </button>\n\n      {lastExecuted && (\n        <div className=\"flex items-center gap-1.5 text-[11px] text-neutral-500 dark:text-neutral-400\">\n          <CheckCircle2 className=\"h-3.5 w-3.5 text-black dark:text-white\" />\n          <span>\n            Ran: <strong className=\"font-medium text-black dark:text-white\">{lastExecuted}</strong>\n          </span>\n        </div>\n      )}\n\n      {mounted &&\n        createPortal(\n          <AnimatePresence>\n            {isOpen && (\n              <div className=\"fixed inset-0 z-[9999] flex items-start justify-center p-4 pt-[12vh] sm:pt-[16vh]\">\n                {/* Backdrop */}\n                <motion.div\n                  initial={{ opacity: 0 }}\n                  animate={{ opacity: 1 }}\n                  exit={{ opacity: 0 }}\n                  onClick={() => setOpen(false)}\n                  className=\"fixed inset-0 bg-black/50 backdrop-blur-xs\"\n                />\n\n                {/* Command Palette Dialog */}\n                <motion.div\n                  role=\"dialog\"\n                  aria-modal=\"true\"\n                  aria-label=\"Command Menu\"\n                  initial={\n                    shouldReduceMotion\n                      ? { opacity: 0 }\n                      : { opacity: 0, scale: 0.95, y: -12 }\n                  }\n                  animate={{ opacity: 1, scale: 1, y: 0 }}\n                  exit={\n                    shouldReduceMotion\n                      ? { opacity: 0 }\n                      : { opacity: 0, scale: 0.96, y: -8 }\n                  }\n                  transition={{ type: \"spring\", stiffness: 420, damping: 30 }}\n                  className=\"relative z-10 flex w-full max-w-lg flex-col overflow-hidden rounded-2xl border border-neutral-200 bg-white shadow-2xl dark:border-[#262626] dark:bg-[#0A0A0A]\"\n                >\n                  {/* Search Input Header */}\n                  <div className=\"flex items-center gap-3 border-b border-neutral-200 px-4 py-3.5 dark:border-[#1A1A1A]\">\n                    <Search className=\"h-4 w-4 shrink-0 text-neutral-400\" />\n                    <input\n                      ref={inputRef}\n                      type=\"text\"\n                      value={query}\n                      onChange={(e) => setQuery(e.target.value)}\n                      onKeyDown={handleKeyDown}\n                      placeholder={placeholder}\n                      className=\"w-full bg-transparent text-sm text-black placeholder:text-neutral-400 focus:outline-none dark:text-white dark:placeholder:text-neutral-500\"\n                    />\n                    {query && (\n                      <button\n                        type=\"button\"\n                        aria-label=\"Clear search\"\n                        onClick={() => {\n                          setQuery(\"\");\n                          inputRef.current?.focus();\n                        }}\n                        className=\"rounded-md p-1 text-neutral-400 hover:bg-neutral-100 hover:text-black dark:hover:bg-[#161616] dark:hover:text-white\"\n                      >\n                        <X className=\"h-3.5 w-3.5\" />\n                      </button>\n                    )}\n                    <button\n                      type=\"button\"\n                      onClick={() => setOpen(false)}\n                      className=\"rounded-md border border-neutral-200 bg-neutral-100 px-1.5 py-0.5 font-mono text-[10px] font-medium text-neutral-500 hover:text-black dark:border-[#262626] dark:bg-[#141414] dark:text-neutral-400 dark:hover:text-white\"\n                    >\n                      ESC\n                    </button>\n                  </div>\n\n                  {/* Grouped Results List */}\n                  <div\n                    ref={listRef}\n                    role=\"listbox\"\n                    className=\"max-h-[320px] overflow-y-auto p-2\"\n                  >\n                    {groupedItems.length === 0 ? (\n                      <div className=\"py-10 text-center text-xs text-neutral-400\">\n                        {emptyMessage}\n                      </div>\n                    ) : (\n                      groupedItems.map((groupBlock) => (\n                        <div key={groupBlock.group} className=\"mb-2 last:mb-0\">\n                          <div className=\"px-2.5 py-1.5 font-mono text-[10px] font-semibold uppercase tracking-wider text-neutral-400 dark:text-neutral-500\">\n                            {groupBlock.group}\n                          </div>\n                          {groupBlock.entries.map(({ item, flatIndex }) => {\n                            const isActive = flatIndex === activeIndex;\n                            return (\n                              <button\n                                key={item.id}\n                                type=\"button\"\n                                role=\"option\"\n                                data-cmd-index={flatIndex}\n                                aria-selected={isActive}\n                                onMouseEnter={() => setActiveIndex(flatIndex)}\n                                onClick={() => handleSelect(item)}\n                                className={cn(\n                                  \"flex w-full items-center justify-between rounded-xl px-3 py-2.5 text-left text-sm transition-colors\",\n                                  isActive\n                                    ? \"bg-neutral-100 text-black dark:bg-[#161616] dark:text-white\"\n                                    : \"text-neutral-600 hover:bg-neutral-50 dark:text-neutral-400 dark:hover:bg-[#121212]\"\n                                )}\n                              >\n                                <span className=\"flex items-center gap-3 font-medium\">\n                                  <span\n                                    className={cn(\n                                      \"flex h-7 w-7 items-center justify-center rounded-lg border transition-colors\",\n                                      isActive\n                                        ? \"border-black bg-black text-white dark:border-white dark:bg-white dark:text-black\"\n                                        : \"border-neutral-200 bg-neutral-50 text-neutral-500 dark:border-[#262626] dark:bg-[#121212] dark:text-neutral-400\"\n                                    )}\n                                  >\n                                    {item.icon ?? <Command className=\"h-3.5 w-3.5\" />}\n                                  </span>\n                                  <span>{item.label}</span>\n                                </span>\n\n                                {item.shortcut && (\n                                  <kbd className=\"rounded-md border border-neutral-200 bg-white px-1.5 py-0.5 font-mono text-[10px] text-neutral-500 dark:border-[#262626] dark:bg-[#0A0A0A] dark:text-neutral-400\">\n                                    {item.shortcut}\n                                  </kbd>\n                                )}\n                              </button>\n                            );\n                          })}\n                        </div>\n                      ))\n                    )}\n                  </div>\n\n                  {/* Keyboard Hint Footer */}\n                  <div className=\"flex items-center justify-between border-t border-neutral-200 bg-neutral-50/70 px-4 py-2.5 text-[11px] text-neutral-400 dark:border-[#1A1A1A] dark:bg-[#0D0D0D]\">\n                    <div className=\"flex items-center gap-3\">\n                      <span className=\"inline-flex items-center gap-1\">\n                        <ArrowUp className=\"h-3 w-3\" />\n                        <ArrowDown className=\"h-3 w-3\" />\n                        Navigate\n                      </span>\n                      <span className=\"inline-flex items-center gap-1\">\n                        <CornerDownLeft className=\"h-3 w-3\" />\n                        Run\n                      </span>\n                    </div>\n                    <span className=\"font-mono text-[10px]\">\n                      {filteredItems.length} command{filteredItems.length === 1 ? \"\" : \"s\"}\n                    </span>\n                  </div>\n                </motion.div>\n              </div>\n            )}\n          </AnimatePresence>,\n          document.body\n        )}\n    </div>\n  );\n}\n\nexport default CommandMenu;\n",
          "type": "registry:ui",
          "target": "components/ui/command-menu.tsx"
        },
        {
          "path": "lib/utils.ts",
          "content": "import { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...inputs: ClassValue[]) {\n  return twMerge(clsx(inputs));\n}\n\nexport async function copyToClipboard(text: string): Promise<boolean> {\n  if (typeof window === \"undefined\") return false;\n\n  try {\n    if (navigator.clipboard && window.isSecureContext) {\n      await navigator.clipboard.writeText(text);\n      return true;\n    }\n\n    const textArea = document.createElement(\"textarea\");\n    textArea.value = text;\n    textArea.style.position = \"fixed\";\n    textArea.style.left = \"-999999px\";\n    textArea.style.top = \"-999999px\";\n    document.body.appendChild(textArea);\n    textArea.focus();\n    textArea.select();\n    const succeeded = document.execCommand(\"copy\");\n    textArea.remove();\n    return succeeded;\n  } catch {\n    return false;\n  }\n}\n",
          "type": "registry:lib",
          "target": "lib/utils.ts"
        }
      ]
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "constellation-map",
      "type": "registry:ui",
      "title": "Constellation Map",
      "author": "Rishabh Bose <https://theb0se.vercel.app/>",
      "description": "Astronomical SVG star chart plotting authentic geometries for Orion, Cassiopeia, Ursa Major, Cygnus, and Lyra over a celestial Right Ascension and Declination coordinate grid with animated stroke-dashoffset line tracing.",
      "dependencies": [
        "framer-motion",
        "lucide-react",
        "clsx",
        "tailwind-merge"
      ],
      "files": [
        {
          "path": "components/ui/constellation-map.tsx",
          "content": "\"use client\";\n\nimport React, { useEffect, useRef, useState } from \"react\";\nimport { motion } from \"framer-motion\";\nimport { Compass, Sparkles, Grid, Eye, RotateCcw } from \"lucide-react\";\nimport { cn } from \"@/lib/utils\";\n\nexport interface ConstellationMapProps {\n  /** Color of constellation connecting lines */\n  lineColor?: string;\n  /** Primary star node color */\n  starColor?: string;\n  /** Line drawing animation speed multiplier */\n  drawSpeed?: number;\n  /** Whether to display celestial RA/Dec coordinate grid */\n  showGrid?: boolean;\n  /** Whether to display constellation and star designation labels */\n  showLabels?: boolean;\n  /** Optional foreground content */\n  children?: React.ReactNode;\n  /** Additional container classes */\n  className?: string;\n}\n\ninterface StarNode {\n  id: string;\n  name: string;\n  designation: string;\n  spectralType: string;\n  spectralColor: string;\n  mag: string;\n  x: number; // normalized percentage 0-100\n  y: number; // normalized percentage 0-100\n  radius: number;\n}\n\ninterface ConstellationDef {\n  id: string;\n  name: string;\n  latin: string;\n  ra: string;\n  dec: string;\n  labelPos: { x: number; y: number };\n  stars: StarNode[];\n  edges: [string, string][];\n}\n\nconst CONSTELLATIONS: ConstellationDef[] = [\n  {\n    id: \"orion\",\n    name: \"ORION\",\n    latin: \"The Hunter\",\n    ra: \"05h 35m\",\n    dec: \"+05° 23′\",\n    labelPos: { x: 18, y: 21 },\n    stars: [\n      {\n        id: \"betelgeuse\",\n        name: \"Betelgeuse\",\n        designation: \"α Ori\",\n        spectralType: \"M1-2 Ia\",\n        spectralColor: \"#FB923C\",\n        mag: \"0.42\",\n        x: 16.5,\n        y: 30,\n        radius: 4.6,\n      },\n      {\n        id: \"bellatrix\",\n        name: \"Bellatrix\",\n        designation: \"γ Ori\",\n        spectralType: \"B2 III\",\n        spectralColor: \"#93C5FD\",\n        mag: \"1.64\",\n        x: 27.2,\n        y: 32.5,\n        radius: 3.5,\n      },\n      {\n        id: \"meissa\",\n        name: \"Meissa\",\n        designation: \"λ Ori\",\n        spectralType: \"O8 III\",\n        spectralColor: \"#BAE6FD\",\n        mag: \"3.33\",\n        x: 22.2,\n        y: 25.5,\n        radius: 2.6,\n      },\n      {\n        id: \"alnitak\",\n        name: \"Alnitak\",\n        designation: \"ζ Ori\",\n        spectralType: \"O9.5 Ib\",\n        spectralColor: \"#93C5FD\",\n        mag: \"1.77\",\n        x: 20.4,\n        y: 46.8,\n        radius: 3.1,\n      },\n      {\n        id: \"alnilam\",\n        name: \"Alnilam\",\n        designation: \"ε Ori\",\n        spectralType: \"B0 Ia\",\n        spectralColor: \"#BAE6FD\",\n        mag: \"1.69\",\n        x: 22.8,\n        y: 45.6,\n        radius: 3.3,\n      },\n      {\n        id: \"mintaka\",\n        name: \"Mintaka\",\n        designation: \"δ Ori\",\n        spectralType: \"O9.5 II\",\n        spectralColor: \"#93C5FD\",\n        mag: \"2.23\",\n        x: 25.2,\n        y: 44.5,\n        radius: 3.0,\n      },\n      {\n        id: \"saiph\",\n        name: \"Saiph\",\n        designation: \"κ Ori\",\n        spectralType: \"B0.5 Ia\",\n        spectralColor: \"#93C5FD\",\n        mag: \"2.06\",\n        x: 18.2,\n        y: 62.5,\n        radius: 3.3,\n      },\n      {\n        id: \"rigel\",\n        name: \"Rigel\",\n        designation: \"β Ori\",\n        spectralType: \"B8 Ia\",\n        spectralColor: \"#7DD3FC\",\n        mag: \"0.13\",\n        x: 28.8,\n        y: 60.5,\n        radius: 4.8,\n      },\n    ],\n    edges: [\n      [\"meissa\", \"betelgeuse\"],\n      [\"meissa\", \"bellatrix\"],\n      [\"betelgeuse\", \"bellatrix\"],\n      [\"betelgeuse\", \"alnitak\"],\n      [\"bellatrix\", \"mintaka\"],\n      [\"alnitak\", \"alnilam\"],\n      [\"alnilam\", \"mintaka\"],\n      [\"alnitak\", \"saiph\"],\n      [\"mintaka\", \"rigel\"],\n      [\"saiph\", \"rigel\"],\n    ],\n  },\n  {\n    id: \"cassiopeia\",\n    name: \"CASSIOPEIA\",\n    latin: \"The Seated Queen\",\n    ra: \"01h 00m\",\n    dec: \"+60° 14′\",\n    labelPos: { x: 44, y: 11 },\n    stars: [\n      {\n        id: \"caph\",\n        name: \"Caph\",\n        designation: \"β Cas\",\n        spectralType: \"F2 III\",\n        spectralColor: \"#FEF08A\",\n        mag: \"2.28\",\n        x: 38.5,\n        y: 18.2,\n        radius: 3.2,\n      },\n      {\n        id: \"schedar\",\n        name: \"Schedar\",\n        designation: \"α Cas\",\n        spectralType: \"K0 IIIa\",\n        spectralColor: \"#FDBA74\",\n        mag: \"2.24\",\n        x: 43.8,\n        y: 24.5,\n        radius: 3.8,\n      },\n      {\n        id: \"gamma_cas\",\n        name: \"Navi\",\n        designation: \"γ Cas\",\n        spectralType: \"B0.5 IVe\",\n        spectralColor: \"#7DD3FC\",\n        mag: \"2.15\",\n        x: 48.8,\n        y: 19.2,\n        radius: 3.6,\n      },\n      {\n        id: \"ruchbah\",\n        name: \"Ruchbah\",\n        designation: \"δ Cas\",\n        spectralType: \"A5 III\",\n        spectralColor: \"#F8FAFC\",\n        mag: \"2.68\",\n        x: 54.2,\n        y: 25.0,\n        radius: 3.0,\n      },\n      {\n        id: \"segin\",\n        name: \"Segin\",\n        designation: \"ε Cas\",\n        spectralType: \"B3 III\",\n        spectralColor: \"#93C5FD\",\n        mag: \"3.35\",\n        x: 59.5,\n        y: 16.8,\n        radius: 2.8,\n      },\n    ],\n    edges: [\n      [\"caph\", \"schedar\"],\n      [\"schedar\", \"gamma_cas\"],\n      [\"gamma_cas\", \"ruchbah\"],\n      [\"ruchbah\", \"segin\"],\n    ],\n  },\n  {\n    id: \"ursa_major\",\n    name: \"URSA MAJOR\",\n    latin: \"The Great Bear\",\n    ra: \"11h 18m\",\n    dec: \"+55° 23′\",\n    labelPos: { x: 72, y: 14 },\n    stars: [\n      {\n        id: \"dubhe\",\n        name: \"Dubhe\",\n        designation: \"α UMa\",\n        spectralType: \"K0 III\",\n        spectralColor: \"#FDBA74\",\n        mag: \"1.79\",\n        x: 87.5,\n        y: 21.5,\n        radius: 4.0,\n      },\n      {\n        id: \"merak\",\n        name: \"Merak\",\n        designation: \"β UMa\",\n        spectralType: \"A1 V\",\n        spectralColor: \"#F8FAFC\",\n        mag: \"2.37\",\n        x: 86.2,\n        y: 31.2,\n        radius: 3.3,\n      },\n      {\n        id: \"phecda\",\n        name: \"Phecda\",\n        designation: \"γ UMa\",\n        spectralType: \"A0 Ve\",\n        spectralColor: \"#F8FAFC\",\n        mag: \"2.44\",\n        x: 77.2,\n        y: 33.0,\n        radius: 3.2,\n      },\n      {\n        id: \"megrez\",\n        name: \"Megrez\",\n        designation: \"δ UMa\",\n        spectralType: \"A3 V\",\n        spectralColor: \"#F8FAFC\",\n        mag: \"3.31\",\n        x: 76.5,\n        y: 24.8,\n        radius: 2.7,\n      },\n      {\n        id: \"alioth\",\n        name: \"Alioth\",\n        designation: \"ε UMa\",\n        spectralType: \"A1 III\",\n        spectralColor: \"#E0F2FE\",\n        mag: \"1.77\",\n        x: 69.8,\n        y: 23.8,\n        radius: 3.9,\n      },\n      {\n        id: \"mizar\",\n        name: \"Mizar\",\n        designation: \"ζ UMa\",\n        spectralType: \"A2 V\",\n        spectralColor: \"#F8FAFC\",\n        mag: \"2.23\",\n        x: 64.2,\n        y: 25.5,\n        radius: 3.4,\n      },\n      {\n        id: \"alkaid\",\n        name: \"Alkaid\",\n        designation: \"η UMa\",\n        spectralType: \"B3 V\",\n        spectralColor: \"#93C5FD\",\n        mag: \"1.86\",\n        x: 57.8,\n        y: 31.2,\n        radius: 3.8,\n      },\n    ],\n    edges: [\n      [\"dubhe\", \"merak\"],\n      [\"merak\", \"phecda\"],\n      [\"phecda\", \"megrez\"],\n      [\"megrez\", \"dubhe\"],\n      [\"megrez\", \"alioth\"],\n      [\"alioth\", \"mizar\"],\n      [\"mizar\", \"alkaid\"],\n    ],\n  },\n  {\n    id: \"cygnus\",\n    name: \"CYGNUS\",\n    latin: \"The Northern Cross\",\n    ra: \"20h 37m\",\n    dec: \"+42° 18′\",\n    labelPos: { x: 47, y: 42 },\n    stars: [\n      {\n        id: \"deneb\",\n        name: \"Deneb\",\n        designation: \"α Cyg\",\n        spectralType: \"A2 Ia\",\n        spectralColor: \"#E0F2FE\",\n        mag: \"1.25\",\n        x: 52.0,\n        y: 45.8,\n        radius: 4.5,\n      },\n      {\n        id: \"sadr\",\n        name: \"Sadr\",\n        designation: \"γ Cyg\",\n        spectralType: \"F8 Ib\",\n        spectralColor: \"#FEF08A\",\n        mag: \"2.23\",\n        x: 52.0,\n        y: 57.2,\n        radius: 3.6,\n      },\n      {\n        id: \"albireo\",\n        name: \"Albireo\",\n        designation: \"β Cyg\",\n        spectralType: \"K3 II\",\n        spectralColor: \"#FDBA74\",\n        mag: \"3.05\",\n        x: 52.0,\n        y: 73.5,\n        radius: 3.2,\n      },\n      {\n        id: \"gienah\",\n        name: \"Gienah\",\n        designation: \"ε Cyg\",\n        spectralType: \"K0 III\",\n        spectralColor: \"#FDBA74\",\n        mag: \"2.48\",\n        x: 62.2,\n        y: 59.2,\n        radius: 3.3,\n      },\n      {\n        id: \"delta_cyg\",\n        name: \"Fawaris\",\n        designation: \"δ Cyg\",\n        spectralType: \"B9.5 III\",\n        spectralColor: \"#BAE6FD\",\n        mag: \"2.87\",\n        x: 41.8,\n        y: 59.2,\n        radius: 3.1,\n      },\n    ],\n    edges: [\n      [\"deneb\", \"sadr\"],\n      [\"sadr\", \"albireo\"],\n      [\"delta_cyg\", \"sadr\"],\n      [\"sadr\", \"gienah\"],\n    ],\n  },\n  {\n    id: \"lyra\",\n    name: \"LYRA\",\n    latin: \"The Harp\",\n    ra: \"18h 51m\",\n    dec: \"+36° 41′\",\n    labelPos: { x: 76, y: 41 },\n    stars: [\n      {\n        id: \"vega\",\n        name: \"Vega\",\n        designation: \"α Lyr\",\n        spectralType: \"A0 Va\",\n        spectralColor: \"#BAE6FD\",\n        mag: \"0.03\",\n        x: 78.2,\n        y: 47.2,\n        radius: 4.9,\n      },\n      {\n        id: \"eps_lyr\",\n        name: \"Double Double\",\n        designation: \"ε Lyr\",\n        spectralType: \"A4 V\",\n        spectralColor: \"#F8FAFC\",\n        mag: \"4.67\",\n        x: 81.8,\n        y: 44.5,\n        radius: 2.5,\n      },\n      {\n        id: \"zeta_lyr\",\n        name: \"Zeta Lyrae\",\n        designation: \"ζ Lyr\",\n        spectralType: \"Am\",\n        spectralColor: \"#F8FAFC\",\n        mag: \"4.36\",\n        x: 80.2,\n        y: 51.2,\n        radius: 2.7,\n      },\n      {\n        id: \"delta_lyr\",\n        name: \"Delta Lyrae\",\n        designation: \"δ Lyr\",\n        spectralType: \"M4 II\",\n        spectralColor: \"#FB923C\",\n        mag: \"4.22\",\n        x: 85.2,\n        y: 52.2,\n        radius: 2.7,\n      },\n      {\n        id: \"sheliak\",\n        name: \"Sheliak\",\n        designation: \"β Lyr\",\n        spectralType: \"B8 II\",\n        spectralColor: \"#93C5FD\",\n        mag: \"3.52\",\n        x: 81.2,\n        y: 60.4,\n        radius: 3.1,\n      },\n      {\n        id: \"sulafat\",\n        name: \"Sulafat\",\n        designation: \"γ Lyr\",\n        spectralType: \"B9 III\",\n        spectralColor: \"#BAE6FD\",\n        mag: \"3.25\",\n        x: 86.4,\n        y: 61.2,\n        radius: 3.2,\n      },\n    ],\n    edges: [\n      [\"vega\", \"eps_lyr\"],\n      [\"vega\", \"zeta_lyr\"],\n      [\"eps_lyr\", \"zeta_lyr\"],\n      [\"zeta_lyr\", \"delta_lyr\"],\n      [\"delta_lyr\", \"sulafat\"],\n      [\"sulafat\", \"sheliak\"],\n      [\"sheliak\", \"zeta_lyr\"],\n    ],\n  },\n];\n\nconst SPECTRAL_PALETTE = [\n  \"#93C5FD\", // O/B blue-white\n  \"#E0F2FE\", // A white-blue\n  \"#F8FAFC\", // F white\n  \"#FEF08A\", // G yellow-white\n  \"#FDBA74\", // K/M orange\n];\n\n// 240+ deterministic deep-field stars clustered denser along the diagonal Milky Way plane\nconst FIELD_STARS = Array.from({ length: 240 }, (_, i) => {\n  const s1 = Math.sin(i * 12.9898 + 4.1414) * 43758.5453;\n  const r1 = s1 - Math.floor(s1);\n  const s2 = Math.sin(i * 78.233 + 9.731) * 29432.182;\n  const r2 = s2 - Math.floor(s2);\n\n  // Concentrate 45% of stars along the Milky Way diagonal band\n  const inGalacticPlane = i % 10 < 5;\n  const baseT = r1 * 96 + 2;\n  const x = baseT;\n  const y = inGalacticPlane\n    ? Math.max(3, Math.min(96, 88 - baseT * 0.72 + (r2 - 0.5) * 32))\n    : r2 * 94 + 3;\n\n  return {\n    id: i,\n    x,\n    y,\n    r: 0.45 + (i % 5) * 0.28,\n    opacity: 0.14 + ((i * 23) % 68) / 100,\n    color: SPECTRAL_PALETTE[i % SPECTRAL_PALETTE.length] || \"#F8FAFC\",\n  };\n});\n\nexport function ConstellationMap({\n  lineColor = \"#38BDF8\",\n  starColor = \"#F8FAFC\",\n  drawSpeed = 1.0,\n  showGrid: propShowGrid = true,\n  showLabels: propShowLabels = true,\n  children,\n  className,\n}: ConstellationMapProps) {\n  const containerRef = useRef<HTMLDivElement>(null);\n  const [dimensions, setDimensions] = useState({ width: 960, height: 540 });\n  const [showGrid, setShowGrid] = useState(propShowGrid);\n  const [showLabels, setShowLabels] = useState(propShowLabels);\n  const [hoveredStar, setHoveredStar] = useState<StarNode | null>(null);\n  const [parallax, setParallax] = useState({ x: 0, y: 0 });\n  const [replayKey, setReplayKey] = useState(0);\n\n  useEffect(() => {\n    setShowGrid(propShowGrid);\n  }, [propShowGrid]);\n\n  useEffect(() => {\n    setShowLabels(propShowLabels);\n  }, [propShowLabels]);\n\n  useEffect(() => {\n    const container = containerRef.current;\n    if (!container) return;\n\n    const updateDimensions = () => {\n      const rect = container.getBoundingClientRect();\n      setDimensions({\n        width: Math.max(320, Math.floor(rect.width)),\n        height: Math.max(420, Math.floor(rect.height)),\n      });\n    };\n\n    updateDimensions();\n    const observer = new ResizeObserver(updateDimensions);\n    observer.observe(container);\n    return () => observer.disconnect();\n  }, []);\n\n  const durationBase = Math.max(0.4, 1.8 / Math.max(0.2, drawSpeed));\n\n  return (\n    <div\n      ref={containerRef}\n      data-fullscreen-scroll\n      onMouseMove={(e) => {\n        const rect = e.currentTarget.getBoundingClientRect();\n        const nx = (e.clientX - rect.left) / Math.max(1, rect.width) - 0.5;\n        const ny = (e.clientY - rect.top) / Math.max(1, rect.height) - 0.5;\n        setParallax({ x: nx * 14, y: ny * 14 });\n      }}\n      onMouseLeave={() => setParallax({ x: 0, y: 0 })}\n      className={cn(\n        \"relative w-full min-h-[520px] overflow-hidden rounded-2xl border border-sky-500/20 bg-[#02050E] text-slate-100 shadow-2xl\",\n        className\n      )}\n    >\n      {/* Deep Space Zenith & Milky Way Galactic Dust Band */}\n      <div\n        aria-hidden=\"true\"\n        className=\"pointer-events-none absolute inset-0 bg-[radial-gradient(ellipse_at_50%_30%,rgba(14,165,233,0.16),rgba(15,23,42,0.78)_55%,rgba(2,5,14,1)_100%)]\"\n      />\n      <div\n        aria-hidden=\"true\"\n        className=\"pointer-events-none absolute -inset-20 rotate-[-28deg] bg-[radial-gradient(ellipse_at_center,rgba(56,189,248,0.13)_0%,rgba(99,102,241,0.08)_35%,transparent_70%)] blur-2xl\"\n      />\n\n      {/* Interactive Astronomical SVG Chart */}\n      <svg\n        key={replayKey}\n        viewBox={`0 0 ${dimensions.width} ${dimensions.height}`}\n        className=\"absolute inset-0 h-full w-full select-none\"\n        aria-label=\"Astronomical Constellation Star Chart\"\n      >\n        <defs>\n          <filter id=\"star-glow\" x=\"-150%\" y=\"-150%\" width=\"400%\" height=\"400%\">\n            <feGaussianBlur stdDeviation=\"3.6\" result=\"blur\" />\n            <feMerge>\n              <feMergeNode in=\"blur\" />\n              <feMergeNode in=\"SourceGraphic\" />\n            </feMerge>\n          </filter>\n          <radialGradient id=\"nebula-band\" cx=\"50%\" cy=\"50%\" r=\"55%\">\n            <stop offset=\"0%\" stopColor={lineColor} stopOpacity=\"0.16\" />\n            <stop offset=\"50%\" stopColor=\"#818CF8\" stopOpacity=\"0.07\" />\n            <stop offset=\"100%\" stopColor=\"#02050E\" stopOpacity=\"0\" />\n          </radialGradient>\n        </defs>\n\n        {/* Diagonal Milky Way Galactic Plane Nebula Dust */}\n        <g\n          aria-hidden=\"true\"\n          transform={`translate(${-parallax.x * 0.35}, ${-parallax.y * 0.35})`}\n        >\n          <ellipse\n            cx={dimensions.width * 0.52}\n            cy={dimensions.height * 0.48}\n            rx={dimensions.width * 0.65}\n            ry={dimensions.height * 0.22}\n            transform={`rotate(-26 ${dimensions.width * 0.52} ${\n              dimensions.height * 0.48\n            })`}\n            fill=\"url(#nebula-band)\"\n          />\n        </g>\n\n        {/* Celestial RA / Dec Coordinate Grid */}\n        {showGrid && (\n          <g className=\"opacity-35\">\n            {/* Declination Parallels */}\n            {[0.18, 0.36, 0.54, 0.72, 0.9].map((ratio, idx) => {\n              const y = dimensions.height * ratio;\n              const decDeg = 60 - idx * 20;\n              return (\n                <g key={`dec-${idx}`}>\n                  <line\n                    x1={0}\n                    y1={y}\n                    x2={dimensions.width}\n                    y2={y}\n                    stroke={lineColor}\n                    strokeWidth=\"0.6\"\n                    strokeDasharray=\"3 6\"\n                    strokeOpacity=\"0.48\"\n                  />\n                  <text\n                    x={14}\n                    y={y - 5}\n                    fill={lineColor}\n                    fontSize=\"9\"\n                    fontFamily=\"ui-monospace, SFMono-Regular, Menlo, monospace\"\n                    opacity=\"0.8\"\n                  >\n                    DEC {decDeg >= 0 ? `+${decDeg}°` : `${decDeg}°`}\n                  </text>\n                </g>\n              );\n            })}\n\n            {/* Right Ascension Meridians */}\n            {[0.15, 0.32, 0.5, 0.68, 0.85].map((ratio, idx) => {\n              const x = dimensions.width * ratio;\n              const raHour = (idx * 4 + 2).toString().padStart(2, \"0\");\n              return (\n                <g key={`ra-${idx}`}>\n                  <line\n                    x1={x}\n                    y1={0}\n                    x2={x}\n                    y2={dimensions.height}\n                    stroke={lineColor}\n                    strokeWidth=\"0.6\"\n                    strokeDasharray=\"3 6\"\n                    strokeOpacity=\"0.48\"\n                  />\n                  <text\n                    x={x + 6}\n                    y={18}\n                    fill={lineColor}\n                    fontSize=\"9\"\n                    fontFamily=\"ui-monospace, SFMono-Regular, Menlo, monospace\"\n                    opacity=\"0.8\"\n                  >\n                    RA {raHour}h 00m\n                  </text>\n                </g>\n              );\n            })}\n\n            {/* Celestial Equator & Ecliptic Great Circle Curve */}\n            <path\n              d={`M 0 ${dimensions.height * 0.68} Q ${dimensions.width * 0.5} ${\n                dimensions.height * 0.24\n              } ${dimensions.width} ${dimensions.height * 0.62}`}\n              fill=\"none\"\n              stroke={lineColor}\n              strokeWidth=\"0.9\"\n              strokeDasharray=\"6 6\"\n              strokeOpacity=\"0.4\"\n            />\n          </g>\n        )}\n\n        {/* 240+ Multi-Spectral Background Field Stars with subtle parallax */}\n        <g\n          aria-hidden=\"true\"\n          transform={`translate(${-parallax.x * 0.45}, ${-parallax.y * 0.45})`}\n        >\n          {FIELD_STARS.map((s) => (\n            <circle\n              key={s.id}\n              cx={(s.x / 100) * dimensions.width}\n              cy={(s.y / 100) * dimensions.height}\n              r={s.r}\n              fill={s.color}\n              opacity={s.opacity}\n            />\n          ))}\n        </g>\n\n        {/* Constellation Geometries & Optical Diffraction Spikes */}\n        <g transform={`translate(${parallax.x * 0.35}, ${parallax.y * 0.35})`}>\n          {CONSTELLATIONS.map((constellation, cIndex) => {\n            const starMap = new Map(\n              constellation.stars.map((s) => [s.id, s])\n            );\n\n            return (\n              <g key={constellation.id}>\n                {/* Animated Connecting Edges */}\n                {constellation.edges.map(([fromId, toId], edgeIndex) => {\n                  const from = starMap.get(fromId);\n                  const to = starMap.get(toId);\n                  if (!from || !to) return null;\n\n                  const x1 = (from.x / 100) * dimensions.width;\n                  const y1 = (from.y / 100) * dimensions.height;\n                  const x2 = (to.x / 100) * dimensions.width;\n                  const y2 = (to.y / 100) * dimensions.height;\n\n                  return (\n                    <motion.line\n                      key={`${constellation.id}-${fromId}-${toId}`}\n                      x1={x1}\n                      y1={y1}\n                      x2={x2}\n                      y2={y2}\n                      stroke={lineColor}\n                      strokeWidth=\"1.35\"\n                      strokeOpacity=\"0.68\"\n                      initial={{ pathLength: 0, opacity: 0 }}\n                      animate={{ pathLength: 1, opacity: 0.72 }}\n                      transition={{\n                        duration: durationBase,\n                        delay: cIndex * 0.18 + edgeIndex * 0.08,\n                        ease: \"easeInOut\",\n                      }}\n                    />\n                  );\n                })}\n\n                {/* Constellation Designation Header */}\n                {showLabels && (\n                  <g\n                    transform={`translate(${\n                      (constellation.labelPos.x / 100) * dimensions.width\n                    }, ${(constellation.labelPos.y / 100) * dimensions.height})`}\n                  >\n                    <text\n                      fill={lineColor}\n                      fontSize=\"10\"\n                      fontWeight=\"700\"\n                      letterSpacing=\"0.2em\"\n                      fontFamily=\"ui-monospace, SFMono-Regular, Menlo, monospace\"\n                    >\n                      {constellation.name}\n                    </text>\n                    <text\n                      y={12}\n                      fill=\"#94A3B8\"\n                      fontSize=\"8.5\"\n                      fontFamily=\"ui-monospace, SFMono-Regular, Menlo, monospace\"\n                    >\n                      {constellation.latin} · {constellation.ra} {constellation.dec}\n                    </text>\n                  </g>\n                )}\n\n                {/* Interactive Star Nodes with Optical Diffraction Spikes */}\n                {constellation.stars.map((star) => {\n                  const cx = (star.x / 100) * dimensions.width;\n                  const cy = (star.y / 100) * dimensions.height;\n                  const isHovered = hoveredStar?.id === star.id;\n                  const isBrightMajor = star.radius >= 3.8;\n                  const spikeLen = isHovered\n                    ? star.radius * 4.2\n                    : star.radius * 2.9;\n\n                  return (\n                    <g\n                      key={star.id}\n                      className=\"cursor-pointer\"\n                      onMouseEnter={() => setHoveredStar(star)}\n                      onMouseLeave={() => setHoveredStar(null)}\n                    >\n                      {/* Spectral Color Halo */}\n                      <circle\n                        cx={cx}\n                        cy={cy}\n                        r={isHovered ? star.radius * 3.4 : star.radius * 2.2}\n                        fill={star.spectralColor}\n                        opacity={isHovered ? 0.34 : 0.18}\n                        filter=\"url(#star-glow)\"\n                      />\n\n                      {/* 4-Point Telescope Optical Diffraction Spikes on Bright / Hovered Stars */}\n                      {(isBrightMajor || isHovered) && (\n                        <g stroke={star.spectralColor} strokeOpacity={isHovered ? 0.9 : 0.65}>\n                          <line\n                            x1={cx - spikeLen}\n                            y1={cy}\n                            x2={cx + spikeLen}\n                            y2={cy}\n                            strokeWidth={isHovered ? \"1.1\" : \"0.8\"}\n                          />\n                          <line\n                            x1={cx}\n                            y1={cy - spikeLen}\n                            x2={cx}\n                            y2={cy + spikeLen}\n                            strokeWidth={isHovered ? \"1.1\" : \"0.8\"}\n                          />\n                        </g>\n                      )}\n\n                      {/* Outer Astrometric Lock-On Reticle Ring */}\n                      {(isBrightMajor || isHovered) && (\n                        <circle\n                          cx={cx}\n                          cy={cy}\n                          r={isHovered ? star.radius + 7 : star.radius + 4.5}\n                          fill=\"none\"\n                          stroke={isHovered ? \"#FFFFFF\" : lineColor}\n                          strokeWidth={isHovered ? \"1.1\" : \"0.75\"}\n                          strokeOpacity={isHovered ? \"0.95\" : \"0.35\"}\n                          strokeDasharray=\"2.5 2.5\"\n                        />\n                      )}\n\n                      {/* Invisible hit target for effortless hovering */}\n                      <circle cx={cx} cy={cy} r={14} fill=\"transparent\" />\n\n                      {/* Incandescent Star Core */}\n                      <circle\n                        cx={cx}\n                        cy={cy}\n                        r={isHovered ? star.radius + 1.5 : star.radius}\n                        fill={isHovered ? \"#FFFFFF\" : star.spectralColor || starColor}\n                        filter=\"url(#star-glow)\"\n                      />\n\n                      {/* Star Designation & Magnitude Label */}\n                      {showLabels && (star.radius >= 3.3 || isHovered) && (\n                        <text\n                          x={cx + star.radius + 8}\n                          y={cy + 3}\n                          fill={isHovered ? \"#FFFFFF\" : \"#E2E8F0\"}\n                          fontSize={isHovered ? \"10.5\" : \"9.5\"}\n                          fontWeight={isHovered ? \"600\" : \"400\"}\n                          fontFamily=\"ui-monospace, SFMono-Regular, Menlo, monospace\"\n                        >\n                          {star.name}{\" \"}\n                          <tspan fill={lineColor} opacity=\"0.88\">\n                            ({star.designation})\n                          </tspan>\n                        </text>\n                      )}\n                    </g>\n                  );\n                })}\n              </g>\n            );\n          })}\n        </g>\n      </svg>\n\n      {children && (\n        <div className=\"relative z-10 flex min-h-[520px] w-full flex-col\">\n          {children}\n        </div>\n      )}\n    </div>\n  );\n}\n\nexport default ConstellationMap;\n",
          "type": "registry:ui",
          "target": "components/ui/constellation-map.tsx"
        },
        {
          "path": "lib/utils.ts",
          "content": "import { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...inputs: ClassValue[]) {\n  return twMerge(clsx(inputs));\n}\n\nexport async function copyToClipboard(text: string): Promise<boolean> {\n  if (typeof window === \"undefined\") return false;\n\n  try {\n    if (navigator.clipboard && window.isSecureContext) {\n      await navigator.clipboard.writeText(text);\n      return true;\n    }\n\n    const textArea = document.createElement(\"textarea\");\n    textArea.value = text;\n    textArea.style.position = \"fixed\";\n    textArea.style.left = \"-999999px\";\n    textArea.style.top = \"-999999px\";\n    document.body.appendChild(textArea);\n    textArea.focus();\n    textArea.select();\n    const succeeded = document.execCommand(\"copy\");\n    textArea.remove();\n    return succeeded;\n  } catch {\n    return false;\n  }\n}\n",
          "type": "registry:lib",
          "target": "lib/utils.ts"
        }
      ]
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "constellation-mesh-field",
      "type": "registry:ui",
      "title": "Constellation Mesh Field",
      "author": "Rishabh Bose <https://theb0se.vercel.app/>",
      "description": "Interactive SVG vertex constellation surface that dynamically tethers proximity edges to the pointer with spring-scaled nodes.",
      "dependencies": [
        "framer-motion",
        "lucide-react",
        "clsx",
        "tailwind-merge"
      ],
      "files": [
        {
          "path": "components/ui/constellation-mesh-field.tsx",
          "content": "\"use client\";\n\nimport React, { useRef, useState } from \"react\";\nimport { motion, useReducedMotion } from \"framer-motion\";\nimport { Share2 } from \"lucide-react\";\nimport { cn } from \"@/lib/utils\";\n\nexport interface ConstellationMeshFieldProps {\n  /** Proximity distance threshold in pixels to connect cursor to mesh vertices. Default: 130 */\n  connectRadius?: number;\n  /** Optional foreground content */\n  children?: React.ReactNode;\n  className?: string;\n}\n\ninterface MeshVertex {\n  id: string;\n  x: number;\n  y: number;\n}\n\nconst VERTICES: MeshVertex[] = [\n  { id: \"v1\", x: 52, y: 46 },\n  { id: \"v2\", x: 148, y: 38 },\n  { id: \"v3\", x: 262, y: 54 },\n  { id: \"v4\", x: 348, y: 42 },\n  { id: \"v5\", x: 84, y: 118 },\n  { id: \"v6\", x: 198, y: 112 },\n  { id: \"v7\", x: 310, y: 124 },\n  { id: \"v8\", x: 48, y: 188 },\n  { id: \"v9\", x: 156, y: 184 },\n  { id: \"v10\", x: 258, y: 192 },\n  { id: \"v11\", x: 354, y: 180 },\n];\n\nexport function ConstellationMeshField({\n  connectRadius = 130,\n  children,\n  className,\n}: ConstellationMeshFieldProps) {\n  const containerRef = useRef<HTMLDivElement | null>(null);\n  const shouldReduceMotion = useReducedMotion() ?? false;\n  const [pointer, setPointer] = useState<{ x: number; y: number } | null>(null);\n\n  const handleMouseMove = (e: React.MouseEvent<HTMLDivElement>) => {\n    if (shouldReduceMotion) return;\n    const el = containerRef.current;\n    if (!el) return;\n    const rect = el.getBoundingClientRect();\n    // Normalize coordinates into 400x230 SVG viewBox space\n    const normX = ((e.clientX - rect.left) / rect.width) * 400;\n    const normY = ((e.clientY - rect.top) / rect.height) * 230;\n    setPointer({ x: normX, y: normY });\n  };\n\n  return (\n    <div\n      ref={containerRef}\n      onMouseMove={handleMouseMove}\n      onMouseLeave={() => setPointer(null)}\n      className={cn(\n        \"relative flex min-h-[230px] w-full max-w-lg items-center justify-center overflow-hidden rounded-2xl border border-neutral-200 bg-white p-6 dark:border-[#222222] dark:bg-[#0A0A0A]\",\n        className\n      )}\n    >\n      {/* Interactive SVG Constellation Graph */}\n      <svg\n        aria-hidden=\"true\"\n        viewBox=\"0 0 400 230\"\n        className=\"pointer-events-none absolute inset-0 h-full w-full\"\n      >\n        {/* Static ambient mesh edges between close vertices */}\n        {VERTICES.map((a, i) =>\n          VERTICES.slice(i + 1).map((b) => {\n            const dist = Math.hypot(a.x - b.x, a.y - b.y);\n            if (dist > 125) return null;\n            return (\n              <line\n                key={`${a.id}-${b.id}`}\n                x1={a.x}\n                y1={a.y}\n                x2={b.x}\n                y2={b.y}\n                stroke=\"currentColor\"\n                strokeWidth=\"1\"\n                className=\"text-neutral-200/70 dark:text-[#1D1D1D]\"\n              />\n            );\n          })\n        )}\n\n        {/* Dynamic pointer-coupled proximity edges */}\n        {pointer &&\n          VERTICES.map((v) => {\n            const dist = Math.hypot(pointer.x - v.x, pointer.y - v.y);\n            if (dist > connectRadius) return null;\n            const opacity = Math.max(0.15, 1 - dist / connectRadius);\n            return (\n              <line\n                key={`ptr-${v.id}`}\n                x1={pointer.x}\n                y1={pointer.y}\n                x2={v.x}\n                y2={v.y}\n                stroke=\"currentColor\"\n                strokeOpacity={opacity}\n                strokeWidth=\"1.5\"\n                className=\"text-black dark:text-white\"\n              />\n            );\n          })}\n\n        {/* Constellation Vertices */}\n        {VERTICES.map((v) => {\n          const dist = pointer\n            ? Math.hypot(pointer.x - v.x, pointer.y - v.y)\n            : Infinity;\n          const active = dist <= connectRadius;\n          return (\n            <motion.circle\n              key={v.id}\n              cx={v.x}\n              cy={v.y}\n              animate={{ r: active ? 4.2 : 2.5 }}\n              transition={{ type: \"spring\", stiffness: 360, damping: 20 }}\n              className={cn(\n                \"fill-current transition-colors\",\n                active\n                  ? \"text-black dark:text-white\"\n                  : \"text-neutral-300 dark:text-neutral-700\"\n              )}\n            />\n          );\n        })}\n      </svg>\n\n      <div className=\"relative z-10 text-center\">\n        {children || (\n          <div className=\"inline-flex flex-col items-center rounded-2xl border border-neutral-200/90 bg-white/90 px-5 py-3.5 shadow-sm backdrop-blur-md dark:border-[#262626] dark:bg-[#111111]/90\">\n            <span className=\"inline-flex items-center gap-1.5 font-mono text-[10px] font-semibold uppercase tracking-widest text-neutral-500\">\n              <Share2 className=\"h-3.5 w-3.5 text-black dark:text-white\" />\n              Constellation Graph\n            </span>\n            <span className=\"mt-1 text-xs font-semibold text-black dark:text-white\">\n              Sweep cursor to tether proximity edges\n            </span>\n          </div>\n        )}\n      </div>\n    </div>\n  );\n}\n\nexport default ConstellationMeshField;\n",
          "type": "registry:ui",
          "target": "components/ui/constellation-mesh-field.tsx"
        },
        {
          "path": "lib/utils.ts",
          "content": "import { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...inputs: ClassValue[]) {\n  return twMerge(clsx(inputs));\n}\n\nexport async function copyToClipboard(text: string): Promise<boolean> {\n  if (typeof window === \"undefined\") return false;\n\n  try {\n    if (navigator.clipboard && window.isSecureContext) {\n      await navigator.clipboard.writeText(text);\n      return true;\n    }\n\n    const textArea = document.createElement(\"textarea\");\n    textArea.value = text;\n    textArea.style.position = \"fixed\";\n    textArea.style.left = \"-999999px\";\n    textArea.style.top = \"-999999px\";\n    document.body.appendChild(textArea);\n    textArea.focus();\n    textArea.select();\n    const succeeded = document.execCommand(\"copy\");\n    textArea.remove();\n    return succeeded;\n  } catch {\n    return false;\n  }\n}\n",
          "type": "registry:lib",
          "target": "lib/utils.ts"
        }
      ]
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "copy-code-block",
      "type": "registry:ui",
      "title": "Copy Code Block",
      "author": "Rishabh Bose <https://theb0se.vercel.app/>",
      "description": "Multi-tab CLI and code snippet block with sliding spring package-manager tabs (npx, pnpm, bun, yarn), optional line numbers, and one-click clipboard copy feedback.",
      "dependencies": [
        "framer-motion",
        "lucide-react",
        "clsx",
        "tailwind-merge"
      ],
      "files": [
        {
          "path": "components/ui/copy-code-block.tsx",
          "content": "\"use client\";\n\nimport React, { useState, useId } from \"react\";\nimport { AnimatePresence, motion, useReducedMotion } from \"framer-motion\";\nimport { Check, Copy, Terminal } from \"lucide-react\";\nimport { cn } from \"@/lib/utils\";\n\nexport interface CodeSnippetTab {\n  id: string;\n  label: string;\n  code: string;\n  language?: string;\n}\n\nexport interface CopyCodeBlockProps {\n  /** Array of code or package-manager tabs */\n  tabs?: CodeSnippetTab[];\n  /** Single code string when tabs are not needed */\n  code?: string;\n  /** Optional header title shown when single `code` is used */\n  title?: string;\n  /** Show line numbers next to multi-line code. Default: false */\n  showLineNumbers?: boolean;\n  /** Show terminal `$` prefix for single-line CLI commands. Default: true */\n  showPromptPrefix?: boolean;\n  /** Callback fired when code is copied to clipboard */\n  onCopy?: (copiedText: string) => void;\n  className?: string;\n}\n\nconst DEFAULT_TABS: CodeSnippetTab[] = [\n  {\n    id: \"npx\",\n    label: \"npx\",\n    code: 'npx shadcn@latest add \"https://boseui.site/r/drawer.json\"',\n    language: \"bash\",\n  },\n  {\n    id: \"pnpm\",\n    label: \"pnpm\",\n    code: 'pnpm dlx shadcn@latest add \"https://boseui.site/r/drawer.json\"',\n    language: \"bash\",\n  },\n  {\n    id: \"bun\",\n    label: \"bun\",\n    code: 'bunx --bun shadcn@latest add \"https://boseui.site/r/drawer.json\"',\n    language: \"bash\",\n  },\n  {\n    id: \"yarn\",\n    label: \"yarn\",\n    code: 'yarn dlx shadcn@latest add \"https://boseui.site/r/drawer.json\"',\n    language: \"bash\",\n  },\n];\n\nexport function CopyCodeBlock({\n  tabs = DEFAULT_TABS,\n  code,\n  title = \"Terminal\",\n  showLineNumbers = false,\n  showPromptPrefix = true,\n  onCopy,\n  className,\n}: CopyCodeBlockProps) {\n  const shouldReduceMotion = useReducedMotion() ?? false;\n  const tabGroupId = useId();\n\n  const resolvedTabs: CodeSnippetTab[] = code\n    ? [{ id: \"single\", label: title, code }]\n    : tabs.length > 0\n      ? tabs\n      : DEFAULT_TABS;\n\n  const [activeTabId, setActiveTabId] = useState<string>(resolvedTabs[0].id);\n  const [copied, setCopied] = useState(false);\n\n  const currentTab =\n    resolvedTabs.find((t) => t.id === activeTabId) ?? resolvedTabs[0];\n\n  const lines = currentTab.code.split(\"\\n\");\n  const isSingleLine = lines.length === 1;\n\n  const handleCopy = async () => {\n    try {\n      await navigator.clipboard.writeText(currentTab.code);\n      setCopied(true);\n      onCopy?.(currentTab.code);\n      setTimeout(() => setCopied(false), 1800);\n    } catch {\n      // Fallback ignore if clipboard permission denied\n    }\n  };\n\n  return (\n    <div\n      className={cn(\n        \"w-full max-w-lg overflow-hidden rounded-2xl border border-neutral-200 bg-white shadow-sm dark:border-[#262626] dark:bg-[#0A0A0A]\",\n        className\n      )}\n    >\n      {/* Header Bar with Tabs + Copy Button */}\n      <div className=\"flex items-center justify-between border-b border-neutral-200 bg-neutral-50/80 px-3 py-2 dark:border-[#1A1A1A] dark:bg-[#111111]\">\n        <div className=\"flex items-center gap-1.5 overflow-x-auto\">\n          <Terminal className=\"mr-1 h-3.5 w-3.5 shrink-0 text-neutral-400\" />\n          {resolvedTabs.length === 1 ? (\n            <span className=\"font-mono text-xs font-medium text-neutral-600 dark:text-neutral-300\">\n              {resolvedTabs[0].label}\n            </span>\n          ) : (\n            resolvedTabs.map((tab) => {\n              const isActive = tab.id === currentTab.id;\n              return (\n                <button\n                  key={tab.id}\n                  type=\"button\"\n                  onClick={() => setActiveTabId(tab.id)}\n                  className={cn(\n                    \"relative rounded-lg px-2.5 py-1 font-mono text-xs font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-black dark:focus-visible:ring-white\",\n                    isActive\n                      ? \"text-black dark:text-white\"\n                      : \"text-neutral-500 hover:text-black dark:text-neutral-400 dark:hover:text-white\"\n                  )}\n                >\n                  {isActive && (\n                    <motion.span\n                      layoutId={`code-tab-pill-${tabGroupId}`}\n                      transition={\n                        shouldReduceMotion\n                          ? { duration: 0 }\n                          : { type: \"spring\", stiffness: 420, damping: 30 }\n                      }\n                      className=\"absolute inset-0 rounded-lg border border-neutral-200/80 bg-white shadow-2xs dark:border-[#262626] dark:bg-[#1C1C1C]\"\n                    />\n                  )}\n                  <span className=\"relative z-10\">{tab.label}</span>\n                </button>\n              );\n            })\n          )}\n        </div>\n\n        {/* Copy Button */}\n        <button\n          type=\"button\"\n          aria-label=\"Copy code to clipboard\"\n          onClick={handleCopy}\n          className={cn(\n            \"inline-flex h-7 items-center gap-1.5 rounded-lg border px-2.5 font-mono text-[11px] font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-black dark:focus-visible:ring-white\",\n            copied\n              ? \"border-black bg-black text-white dark:border-white dark:bg-white dark:text-black\"\n              : \"border-neutral-200 bg-white text-neutral-600 hover:border-neutral-300 hover:text-black dark:border-[#262626] dark:bg-[#141414] dark:text-neutral-300 dark:hover:text-white\"\n          )}\n        >\n          <AnimatePresence mode=\"wait\" initial={false}>\n            {copied ? (\n              <motion.span\n                key=\"copied\"\n                initial={{ opacity: 0, scale: 0.85 }}\n                animate={{ opacity: 1, scale: 1 }}\n                exit={{ opacity: 0, scale: 0.85 }}\n                transition={{ duration: 0.12 }}\n                className=\"inline-flex items-center gap-1\"\n              >\n                <Check className=\"h-3 w-3\" />\n                <span>Copied</span>\n              </motion.span>\n            ) : (\n              <motion.span\n                key=\"copy\"\n                initial={{ opacity: 0, scale: 0.85 }}\n                animate={{ opacity: 1, scale: 1 }}\n                exit={{ opacity: 0, scale: 0.85 }}\n                transition={{ duration: 0.12 }}\n                className=\"inline-flex items-center gap-1\"\n              >\n                <Copy className=\"h-3 w-3\" />\n                <span>Copy</span>\n              </motion.span>\n            )}\n          </AnimatePresence>\n        </button>\n      </div>\n\n      {/* Code Content */}\n      <div className=\"overflow-x-auto p-4 font-mono text-xs leading-relaxed text-neutral-800 dark:text-neutral-200\">\n        <pre className=\"m-0\">\n          <code>\n            {lines.map((line, i) => (\n              <div key={i} className=\"flex items-baseline\">\n                {showLineNumbers && !isSingleLine && (\n                  <span className=\"mr-4 inline-block w-5 select-none text-right text-[11px] text-neutral-400 dark:text-neutral-600\">\n                    {i + 1}\n                  </span>\n                )}\n                {isSingleLine && showPromptPrefix && (\n                  <span className=\"mr-2.5 select-none text-neutral-400 dark:text-neutral-500\">\n                    $\n                  </span>\n                )}\n                <span className=\"whitespace-pre\">{line}</span>\n              </div>\n            ))}\n          </code>\n        </pre>\n      </div>\n    </div>\n  );\n}\n\nexport default CopyCodeBlock;\n",
          "type": "registry:ui",
          "target": "components/ui/copy-code-block.tsx"
        },
        {
          "path": "lib/utils.ts",
          "content": "import { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...inputs: ClassValue[]) {\n  return twMerge(clsx(inputs));\n}\n\nexport async function copyToClipboard(text: string): Promise<boolean> {\n  if (typeof window === \"undefined\") return false;\n\n  try {\n    if (navigator.clipboard && window.isSecureContext) {\n      await navigator.clipboard.writeText(text);\n      return true;\n    }\n\n    const textArea = document.createElement(\"textarea\");\n    textArea.value = text;\n    textArea.style.position = \"fixed\";\n    textArea.style.left = \"-999999px\";\n    textArea.style.top = \"-999999px\";\n    document.body.appendChild(textArea);\n    textArea.focus();\n    textArea.select();\n    const succeeded = document.execCommand(\"copy\");\n    textArea.remove();\n    return succeeded;\n  } catch {\n    return false;\n  }\n}\n",
          "type": "registry:lib",
          "target": "lib/utils.ts"
        }
      ]
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "cursor-follower",
      "type": "registry:ui",
      "title": "Cursor Follower",
      "author": "Rishabh Bose <https://theb0se.vercel.app/>",
      "description": "Dual-spring custom pointer stage with a high-stiffness inner core and morphing outer ring that expands into contextual HUD pills.",
      "dependencies": [
        "framer-motion",
        "clsx",
        "tailwind-merge"
      ],
      "files": [
        {
          "path": "components/ui/cursor-follower.tsx",
          "content": "\"use client\";\n\nimport React, { useRef, useState } from \"react\";\nimport {\n  motion,\n  AnimatePresence,\n  useMotionValue,\n  useSpring,\n  useReducedMotion,\n} from \"framer-motion\";\nimport { cn } from \"@/lib/utils\";\n\nexport interface CursorFollowerProps {\n  children: React.ReactNode;\n  className?: string;\n  /** Custom accent color override for the cursor ring and dot */\n  accentColor?: string;\n  /** Spring stiffness for the outer trailing ring. Default: 260 */\n  ringStiffness?: number;\n  /** Spring damping for the outer trailing ring. Default: 22 */\n  ringDamping?: number;\n  /** Size of the outer ring in pixels when idle. Default: 34 */\n  ringSize?: number;\n  /** Show coordinate HUD readout in corner of stage. Default: true */\n  showCoordinates?: boolean;\n}\n\nexport function CursorFollower({\n  children,\n  className,\n  accentColor,\n  ringStiffness = 260,\n  ringDamping = 22,\n  ringSize = 34,\n  showCoordinates = true,\n}: CursorFollowerProps) {\n  const containerRef = useRef<HTMLDivElement>(null);\n  const shouldReduceMotion = useReducedMotion();\n\n  const [isInside, setIsInside] = useState(false);\n  const [isPressed, setIsPressed] = useState(false);\n  const [activeLabel, setActiveLabel] = useState<string | null>(null);\n  const [coords, setCoords] = useState({ x: 0, y: 0 });\n\n  const rawX = useMotionValue(0);\n  const rawY = useMotionValue(0);\n\n  const dotX = useSpring(rawX, { stiffness: 750, damping: 35, mass: 0.1 });\n  const dotY = useSpring(rawY, { stiffness: 750, damping: 35, mass: 0.1 });\n\n  const ringX = useSpring(rawX, {\n    stiffness: ringStiffness,\n    damping: ringDamping,\n    mass: 0.35,\n  });\n  const ringY = useSpring(rawY, {\n    stiffness: ringStiffness,\n    damping: ringDamping,\n    mass: 0.35,\n  });\n\n  const handleMouseMove = (e: React.MouseEvent<HTMLDivElement>) => {\n    if (!containerRef.current) return;\n    const rect = containerRef.current.getBoundingClientRect();\n    const x = Math.round(e.clientX - rect.left);\n    const y = Math.round(e.clientY - rect.top);\n\n    rawX.set(x);\n    rawY.set(y);\n    setCoords({ x, y });\n\n    const target = e.target as HTMLElement | null;\n    const labeledEl = target?.closest(\n      \"[data-cursor-label]\"\n    ) as HTMLElement | null;\n    if (labeledEl) {\n      setActiveLabel(labeledEl.getAttribute(\"data-cursor-label\"));\n    } else {\n      setActiveLabel(null);\n    }\n  };\n\n  return (\n    <div\n      ref={containerRef}\n      onMouseEnter={() => setIsInside(true)}\n      onMouseLeave={() => {\n        setIsInside(false);\n        setIsPressed(false);\n        setActiveLabel(null);\n      }}\n      onMouseDown={() => setIsPressed(true)}\n      onMouseUp={() => setIsPressed(false)}\n      onMouseMove={handleMouseMove}\n      className={cn(\n        \"relative overflow-hidden rounded-2xl border border-neutral-200 bg-neutral-50 select-none dark:border-[#222222] dark:bg-black\",\n        isInside && !shouldReduceMotion && \"cursor-none\",\n        className\n      )}\n    >\n      {showCoordinates && (\n        <div className=\"pointer-events-none absolute right-3.5 top-3.5 z-20 flex items-center gap-2 rounded-full border border-neutral-200 bg-white px-2.5 py-1 font-mono text-[10px] text-neutral-500 dark:border-[#262626] dark:bg-[#0A0A0A] dark:text-neutral-400\">\n          <span\n            className={cn(\n              \"h-1.5 w-1.5 rounded-full transition-colors\",\n              isInside\n                ? \"bg-black dark:bg-white\"\n                : \"bg-neutral-300 dark:bg-neutral-700\"\n            )}\n            style={\n              isInside && accentColor\n                ? { backgroundColor: accentColor }\n                : undefined\n            }\n          />\n          <span>\n            X:{coords.x.toString().padStart(3, \"0\")} Y:\n            {coords.y.toString().padStart(3, \"0\")}\n          </span>\n        </div>\n      )}\n\n      <div className=\"relative z-10\">{children}</div>\n\n      {!shouldReduceMotion && (\n        <AnimatePresence>\n          {isInside && (\n            <>\n              <motion.div\n                aria-hidden=\"true\"\n                initial={{ opacity: 0, scale: 0 }}\n                animate={{\n                  opacity: activeLabel ? 0 : 1,\n                  scale: isPressed ? 0.7 : 1,\n                }}\n                exit={{ opacity: 0, scale: 0 }}\n                style={{\n                  x: dotX,\n                  y: dotY,\n                  translateX: \"-50%\",\n                  translateY: \"-50%\",\n                  ...(accentColor ? { backgroundColor: accentColor } : {}),\n                }}\n                className=\"pointer-events-none absolute left-0 top-0 z-30 h-2 w-2 rounded-full bg-black dark:bg-white\"\n              />\n\n              <motion.div\n                aria-hidden=\"true\"\n                initial={{ opacity: 0, scale: 0.4 }}\n                animate={{\n                  opacity: 1,\n                  scale: isPressed ? 0.88 : 1,\n                  width: activeLabel ? \"auto\" : ringSize,\n                  height: activeLabel ? 30 : ringSize,\n                }}\n                exit={{ opacity: 0, scale: 0.4 }}\n                transition={{\n                  width: { type: \"spring\", stiffness: 380, damping: 28 },\n                  height: { type: \"spring\", stiffness: 380, damping: 28 },\n                }}\n                style={{\n                  x: ringX,\n                  y: ringY,\n                  translateX: \"-50%\",\n                  translateY: \"-50%\",\n                  ...(accentColor ? { borderColor: accentColor } : {}),\n                }}\n                className={cn(\n                  \"pointer-events-none absolute left-0 top-0 z-30 flex items-center justify-center rounded-full border border-black transition-colors duration-150 dark:border-white\",\n                  activeLabel\n                    ? \"bg-black px-3 text-white shadow-lg dark:bg-white dark:text-black\"\n                    : \"bg-black/5 backdrop-blur-sm dark:bg-white/10\"\n                )}\n              >\n                {activeLabel && (\n                  <motion.span\n                    initial={{ opacity: 0, scale: 0.85 }}\n                    animate={{ opacity: 1, scale: 1 }}\n                    exit={{ opacity: 0, scale: 0.85 }}\n                    className=\"whitespace-nowrap font-mono text-[10px] font-semibold tracking-wider text-white dark:text-black\"\n                  >\n                    {activeLabel}\n                  </motion.span>\n                )}\n              </motion.div>\n            </>\n          )}\n        </AnimatePresence>\n      )}\n    </div>\n  );\n}\n",
          "type": "registry:ui",
          "target": "components/ui/cursor-follower.tsx"
        },
        {
          "path": "lib/utils.ts",
          "content": "import { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...inputs: ClassValue[]) {\n  return twMerge(clsx(inputs));\n}\n\nexport async function copyToClipboard(text: string): Promise<boolean> {\n  if (typeof window === \"undefined\") return false;\n\n  try {\n    if (navigator.clipboard && window.isSecureContext) {\n      await navigator.clipboard.writeText(text);\n      return true;\n    }\n\n    const textArea = document.createElement(\"textarea\");\n    textArea.value = text;\n    textArea.style.position = \"fixed\";\n    textArea.style.left = \"-999999px\";\n    textArea.style.top = \"-999999px\";\n    document.body.appendChild(textArea);\n    textArea.focus();\n    textArea.select();\n    const succeeded = document.execCommand(\"copy\");\n    textArea.remove();\n    return succeeded;\n  } catch {\n    return false;\n  }\n}\n",
          "type": "registry:lib",
          "target": "lib/utils.ts"
        }
      ]
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "deployment-timeline",
      "type": "registry:ui",
      "title": "Deployment Timeline",
      "author": "Rishabh Bose <https://theb0se.vercel.app/>",
      "description": "Vercel-inspired deployment pipeline stepper with multi-phase statuses, elapsed timers, commit SHA metadata, and an interactive streaming build stdout log console.",
      "dependencies": [
        "framer-motion",
        "lucide-react",
        "clsx",
        "tailwind-merge"
      ],
      "files": [
        {
          "path": "components/ui/deployment-timeline.tsx",
          "content": "\"use client\";\n\nimport React, { useState, useEffect, useRef } from \"react\";\nimport { motion, AnimatePresence } from \"framer-motion\";\nimport {\n  CheckCircle2,\n  Loader2,\n  Clock,\n  GitCommit,\n  GitBranch,\n  Terminal,\n  RotateCcw,\n  AlertCircle,\n  Copy,\n  Check,\n  Globe,\n  ExternalLink,\n  ChevronDown,\n  ChevronUp,\n  Sparkles,\n} from \"lucide-react\";\nimport { cn } from \"@/lib/utils\";\n\nexport type PipelineStage = \"queued\" | \"building\" | \"assigning\" | \"ready\" | \"failed\";\n\nexport interface DeploymentTimelineProps {\n  commitSha?: string;\n  branch?: string;\n  autoPlay?: boolean;\n  className?: string;\n}\n\ninterface StageStep {\n  id: PipelineStage;\n  label: string;\n  desc: string;\n  durationMs: number;\n}\n\nconst STAGES: StageStep[] = [\n  { id: \"queued\", label: \"Queued\", desc: \"Assigned to build runner-west-04\", durationMs: 2500 },\n  { id: \"building\", label: \"Building\", desc: \"Running turbo build & asset optimization\", durationMs: 4000 },\n  { id: \"assigning\", label: \"Assigning Domains\", desc: \"Propagating DNS & edge worker routes\", durationMs: 2500 },\n  { id: \"ready\", label: \"Ready\", desc: \"Deployment live globally in 310 regions\", durationMs: 0 },\n];\n\nconst LOG_MESSAGES: Record<PipelineStage, string[]> = {\n  queued: [\n    \"[runner] Initializing isolated microVM container...\",\n    \"[git] Fetching origin/main @ commit a89e4c1...\",\n    \"[cache] Restoring Turborepo lockfile hash (98.2% cache hit)...\",\n  ],\n  building: [\n    \"[pnpm] Resolving dependencies with frozen-lockfile...\",\n    \"[next] Creating optimized production build...\",\n    \"[next] ✓ Compiled client and server bundles in 842ms\",\n    \"[turbopack] Generating static pages (28/28)...\",\n    \"[wasm] Compiling Rust image processing pipeline to wasm32-unknown...\",\n    \"[edge] Generating immutable edge functions bundles...\",\n  ],\n  assigning: [\n    \"[network] Uploading 142 static assets to edge CDN...\",\n    \"[dns] Pointing pulseui.dev to canonical alias 76.76.21.21...\",\n    \"[ssl] Validating automated Let's Encrypt TLS certificate...\",\n    \"[mesh] Health probe verified 200 OK across 24 regional points of presence.\",\n  ],\n  ready: [\n    \"✓ DEPLOYMENT COMPLETE in 9.24s\",\n    \"Production URL: https://pulseui.dev\",\n    \"Preview URL: https://pulseui-git-feat-engine.pulse.app\",\n    \"State: Immutably locked and ready for incoming traffic.\",\n  ],\n  failed: [\n    \"✗ ERROR: Build runner terminated with exit code 1\",\n    \"Error: Module not found: Can't resolve '@lib/core' in /app/src/index.ts\",\n    \"Pipeline aborted. Previous production deployment preserved.\",\n  ],\n};\n\nexport function DeploymentTimeline({\n  commitSha = \"a89e4c1\",\n  branch = \"main\",\n  autoPlay = true,\n  className,\n}: DeploymentTimelineProps) {\n  const [currentStage, setCurrentStage] = useState<PipelineStage>(\"building\");\n  const [elapsedSeconds, setElapsedSeconds] = useState<number>(3.4);\n  const [showStdout, setShowStdout] = useState<boolean>(true);\n  const [isSimulating, setIsSimulating] = useState<boolean>(autoPlay);\n  const [copiedSha, setCopiedSha] = useState<boolean>(false);\n  const [activeLogs, setActiveLogs] = useState<string[]>([\n    ...LOG_MESSAGES.queued,\n    ...LOG_MESSAGES.building.slice(0, 3),\n  ]);\n\n  const logEndRef = useRef<HTMLDivElement>(null);\n\n  // Auto-scroll logs\n  useEffect(() => {\n    if (showStdout && logEndRef.current) {\n      logEndRef.current.scrollIntoView({ behavior: \"smooth\" });\n    }\n  }, [activeLogs, showStdout]);\n\n  // Timer loop\n  useEffect(() => {\n    if (!isSimulating || currentStage === \"ready\" || currentStage === \"failed\") return;\n\n    const interval = setInterval(() => {\n      setElapsedSeconds((prev) => parseFloat((prev + 0.1).toFixed(1)));\n    }, 100);\n\n    return () => clearInterval(interval);\n  }, [isSimulating, currentStage]);\n\n  // Stage progression simulator\n  useEffect(() => {\n    if (!isSimulating) return;\n\n    let timeout: NodeJS.Timeout;\n\n    if (currentStage === \"queued\") {\n      timeout = setTimeout(() => {\n        setCurrentStage(\"building\");\n        setActiveLogs((prev) => [...prev, ...LOG_MESSAGES.building]);\n      }, 2500);\n    } else if (currentStage === \"building\") {\n      timeout = setTimeout(() => {\n        setCurrentStage(\"assigning\");\n        setActiveLogs((prev) => [...prev, ...LOG_MESSAGES.assigning]);\n      }, 3500);\n    } else if (currentStage === \"assigning\") {\n      timeout = setTimeout(() => {\n        setCurrentStage(\"ready\");\n        setActiveLogs((prev) => [...prev, ...LOG_MESSAGES.ready]);\n      }, 2500);\n    }\n\n    return () => clearTimeout(timeout);\n  }, [currentStage, isSimulating]);\n\n  const restartDeployment = () => {\n    setCurrentStage(\"queued\");\n    setElapsedSeconds(0.0);\n    setIsSimulating(true);\n    setActiveLogs([...LOG_MESSAGES.queued]);\n  };\n\n  const triggerFailure = () => {\n    setCurrentStage(\"failed\");\n    setIsSimulating(false);\n    setActiveLogs((prev) => [...prev, ...LOG_MESSAGES.failed]);\n  };\n\n  const copySha = () => {\n    navigator.clipboard?.writeText(commitSha);\n    setCopiedSha(true);\n    setTimeout(() => setCopiedSha(false), 2000);\n  };\n\n  const getStageIndex = (stage: PipelineStage) => {\n    if (stage === \"failed\") return 1;\n    return STAGES.findIndex((s) => s.id === stage);\n  };\n\n  const currentIndex = getStageIndex(currentStage);\n\n  return (\n    <div\n      data-fullscreen-scroll\n      className={cn(\n        \"relative w-full min-h-[520px] overflow-hidden rounded-2xl border border-neutral-800 bg-[#07080D] p-6 text-white shadow-2xl flex flex-col justify-between selection:bg-neutral-800\",\n        className\n      )}\n    >\n      {/* Background glow when ready */}\n      {currentStage === \"ready\" && (\n        <div className=\"pointer-events-none absolute -top-24 right-1/4 h-80 w-80 rounded-full bg-emerald-500/10 blur-3xl\" />\n      )}\n      {currentStage === \"failed\" && (\n        <div className=\"pointer-events-none absolute -top-24 right-1/4 h-80 w-80 rounded-full bg-rose-500/10 blur-3xl\" />\n      )}\n\n      {/* Header bar */}\n      <div className=\"relative z-10 flex flex-wrap items-center justify-between gap-4 border-b border-neutral-800/80 pb-4\">\n        <div className=\"flex items-center gap-2.5\">\n          <div className=\"flex h-8 w-8 items-center justify-center rounded-lg border border-neutral-700 bg-neutral-900 font-mono text-xs font-bold text-neutral-200\">\n            ▲\n          </div>\n          <div>\n            <div className=\"flex items-center gap-2\">\n              <h3 className=\"text-sm font-semibold tracking-tight text-white\">\n                pulseui.dev\n              </h3>\n              <span\n                className={cn(\n                  \"text-[10px] font-mono uppercase px-2 py-0.5 rounded-full border\",\n                  currentStage === \"ready\"\n                    ? \"border-emerald-500/40 bg-emerald-950/60 text-emerald-400\"\n                    : currentStage === \"failed\"\n                    ? \"border-rose-500/40 bg-rose-950/60 text-rose-400\"\n                    : \"border-cyan-500/40 bg-cyan-950/60 text-cyan-400 animate-pulse\"\n                )}\n              >\n                {currentStage === \"ready\"\n                  ? \"Production Ready\"\n                  : currentStage === \"failed\"\n                  ? \"Build Failed\"\n                  : \"Deploying...\"}\n              </span>\n            </div>\n            <div className=\"flex items-center gap-3 text-xs text-neutral-400 font-mono mt-0.5\">\n              <span className=\"flex items-center gap-1\">\n                <GitBranch className=\"h-3 w-3 text-neutral-500\" />\n                {branch}\n              </span>\n              <button\n                onClick={copySha}\n                className=\"flex items-center gap-1 hover:text-white transition-colors\"\n                title=\"Copy Commit Hash\"\n              >\n                <GitCommit className=\"h-3 w-3 text-neutral-500\" />\n                <span>{commitSha}</span>\n                {copiedSha ? <Check className=\"h-2.5 w-2.5 text-emerald-400\" /> : <Copy className=\"h-2.5 w-2.5\" />}\n              </button>\n            </div>\n          </div>\n        </div>\n\n        {/* Live Controls */}\n        <div className=\"flex flex-wrap items-center gap-2\">\n          <button\n            onClick={restartDeployment}\n            className=\"flex items-center gap-1.5 px-3 py-1.5 text-xs font-mono rounded-lg border border-neutral-700 bg-neutral-800 text-neutral-200 hover:text-white hover:bg-neutral-700 transition-all shadow-sm\"\n          >\n            <RotateCcw className=\"h-3.5 w-3.5\" />\n            <span>Redeploy</span>\n          </button>\n\n          <button\n            onClick={triggerFailure}\n            disabled={currentStage === \"failed\"}\n            className={cn(\n              \"flex items-center gap-1.5 px-2.5 py-1.5 text-xs font-mono rounded-lg border transition-all\",\n              currentStage === \"failed\"\n                ? \"border-neutral-800 text-neutral-600 cursor-not-allowed\"\n                : \"border-rose-900/60 bg-rose-950/30 text-rose-400 hover:bg-rose-900/40\"\n            )}\n          >\n            <AlertCircle className=\"h-3.5 w-3.5\" />\n            <span>Simulate Error</span>\n          </button>\n\n          <button\n            onClick={() => setShowStdout(!showStdout)}\n            className=\"flex items-center gap-1.5 px-2.5 py-1.5 text-xs font-mono rounded-lg border border-neutral-800 bg-neutral-900 text-neutral-300 hover:text-white transition-colors\"\n          >\n            <Terminal className=\"h-3.5 w-3.5\" />\n            <span>{showStdout ? \"Hide Logs\" : \"Show Logs\"}</span>\n            {showStdout ? <ChevronUp className=\"h-3 w-3\" /> : <ChevronDown className=\"h-3 w-3\" />}\n          </button>\n        </div>\n      </div>\n\n      {/* Main Deployment Pipeline Stepper */}\n      <div className=\"relative z-10 my-6\">\n        <div className=\"grid grid-cols-1 md:grid-cols-4 gap-3\">\n          {STAGES.map((step, idx) => {\n            const isCompleted = currentIndex > idx || currentStage === \"ready\";\n            const isCurrent = currentStage === step.id;\n            const isFailed = currentStage === \"failed\" && step.id === \"building\";\n\n            return (\n              <div\n                key={step.id}\n                className={cn(\n                  \"relative flex flex-col justify-between rounded-xl border p-4 transition-all duration-300\",\n                  isCurrent && !isFailed\n                    ? \"border-cyan-500/60 bg-cyan-950/20 shadow-[0_0_20px_rgba(6,182,212,0.15)] ring-1 ring-cyan-500/40\"\n                    : isCompleted\n                    ? \"border-neutral-700/80 bg-neutral-900/70\"\n                    : isFailed\n                    ? \"border-rose-500/60 bg-rose-950/20 shadow-[0_0_20px_rgba(244,63,94,0.15)]\"\n                    : \"border-neutral-800/60 bg-neutral-950/40 opacity-50\"\n                )}\n              >\n                <div className=\"flex items-center justify-between\">\n                  <span className=\"font-mono text-[10px] uppercase tracking-wider text-neutral-400\">\n                    PHASE 0{idx + 1}\n                  </span>\n\n                  {/* Status Indicator Icon */}\n                  {isFailed ? (\n                    <AlertCircle className=\"h-4 w-4 text-rose-400\" />\n                  ) : isCompleted ? (\n                    <CheckCircle2 className=\"h-4 w-4 text-emerald-400\" />\n                  ) : isCurrent ? (\n                    <Loader2 className=\"h-4 w-4 text-cyan-400 animate-spin\" />\n                  ) : (\n                    <div className=\"h-2 w-2 rounded-full bg-neutral-700\" />\n                  )}\n                </div>\n\n                <div className=\"mt-3\">\n                  <div className=\"text-sm font-semibold text-white flex items-center gap-1.5\">\n                    {step.label}\n                  </div>\n                  <div className=\"mt-1 text-[11px] leading-snug text-neutral-400 line-clamp-2\">\n                    {step.desc}\n                  </div>\n                </div>\n\n                <div className=\"mt-3 border-t border-neutral-800/80 pt-2 flex items-center justify-between text-[10px] font-mono text-neutral-500\">\n                  <span>\n                    {isCompleted ? \"DONE\" : isCurrent ? \"IN PROGRESS\" : isFailed ? \"FAILED\" : \"PENDING\"}\n                  </span>\n                  {isCurrent && (\n                    <span className=\"text-cyan-400 font-bold\">{elapsedSeconds}s</span>\n                  )}\n                </div>\n              </div>\n            );\n          })}\n        </div>\n      </div>\n\n      {/* Streaming Stdout Console */}\n      <AnimatePresence>\n        {showStdout && (\n          <motion.div\n            initial={{ opacity: 0, height: 0 }}\n            animate={{ opacity: 1, height: \"auto\" }}\n            exit={{ opacity: 0, height: 0 }}\n            className=\"relative z-10 my-2 overflow-hidden rounded-xl border border-neutral-800 bg-[#040508] font-mono text-xs shadow-inner\"\n          >\n            {/* Console top header */}\n            <div className=\"flex items-center justify-between border-b border-neutral-800/90 bg-neutral-900/60 px-4 py-2 text-[11px] text-neutral-400\">\n              <div className=\"flex items-center gap-2\">\n                <span className=\"inline-block h-2 w-2 rounded-full bg-emerald-400 animate-ping\" />\n                <span className=\"text-neutral-300 font-medium\">Build Stdout Logs</span>\n                <span className=\"text-neutral-600\">•</span>\n                <span>Streaming live</span>\n              </div>\n              <div className=\"flex items-center gap-3 text-neutral-500\">\n                <span>{activeLogs.length} events logged</span>\n                <button\n                  onClick={() => setActiveLogs([])}\n                  className=\"hover:text-neutral-300 transition-colors\"\n                >\n                  Clear\n                </button>\n              </div>\n            </div>\n\n            {/* Console lines container */}\n            <div\n              tabIndex={0}\n              role=\"region\"\n              aria-label=\"Build stdout logs\"\n              aria-live=\"polite\"\n              className=\"max-h-48 overflow-y-auto p-4 space-y-1.5 text-neutral-300 selection:bg-neutral-800 focus:outline-none focus:ring-1 focus:ring-neutral-700\"\n            >\n              {activeLogs.map((log, index) => {\n                const isError = log.includes(\"ERROR\") || log.includes(\"✗\");\n                const isSuccess = log.includes(\"✓\") || log.includes(\"COMPLETE\");\n                return (\n                  <div\n                    key={index}\n                    className={cn(\n                      \"flex items-start gap-2.5 font-mono text-[11px] leading-relaxed\",\n                      isError\n                        ? \"text-rose-400 font-medium\"\n                        : isSuccess\n                        ? \"text-emerald-400 font-medium\"\n                        : \"text-neutral-300\"\n                    )}\n                  >\n                    <span className=\"text-neutral-600 select-none w-5 text-right font-mono text-[10px]\">\n                      {index + 1}\n                    </span>\n                    <span className=\"flex-1 break-all\">{log}</span>\n                  </div>\n                );\n              })}\n              <div ref={logEndRef} />\n            </div>\n          </motion.div>\n        )}\n      </AnimatePresence>\n\n      {/* Footer telemetry */}\n      <div className=\"relative z-10 flex flex-wrap items-center justify-between gap-2 border-t border-neutral-800/80 pt-3 text-[11px] font-mono text-neutral-400\">\n        <div className=\"flex items-center gap-2\">\n          <Clock className=\"h-3 w-3 text-neutral-500\" />\n          <span>ELAPSED TOTAL: {elapsedSeconds}s</span>\n        </div>\n\n        {currentStage === \"ready\" ? (\n          <a\n            href=\"https://pulseui.dev\"\n            target=\"_blank\"\n            rel=\"noreferrer\"\n            className=\"flex items-center gap-1.5 text-emerald-400 hover:underline\"\n          >\n            <Globe className=\"h-3 w-3\" />\n            <span>Visit Live URL: pulseui.dev</span>\n            <ExternalLink className=\"h-3 w-3\" />\n          </a>\n        ) : (\n          <div className=\"flex items-center gap-2\">\n            <span>EDGE WORKERS: 310 REGIONS ROUTED</span>\n          </div>\n        )}\n      </div>\n    </div>\n  );\n}\n\nexport default DeploymentTimeline;\n",
          "type": "registry:ui",
          "target": "components/ui/deployment-timeline.tsx"
        },
        {
          "path": "lib/utils.ts",
          "content": "import { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...inputs: ClassValue[]) {\n  return twMerge(clsx(inputs));\n}\n\nexport async function copyToClipboard(text: string): Promise<boolean> {\n  if (typeof window === \"undefined\") return false;\n\n  try {\n    if (navigator.clipboard && window.isSecureContext) {\n      await navigator.clipboard.writeText(text);\n      return true;\n    }\n\n    const textArea = document.createElement(\"textarea\");\n    textArea.value = text;\n    textArea.style.position = \"fixed\";\n    textArea.style.left = \"-999999px\";\n    textArea.style.top = \"-999999px\";\n    document.body.appendChild(textArea);\n    textArea.focus();\n    textArea.select();\n    const succeeded = document.execCommand(\"copy\");\n    textArea.remove();\n    return succeeded;\n  } catch {\n    return false;\n  }\n}\n",
          "type": "registry:lib",
          "target": "lib/utils.ts"
        }
      ]
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "diff-viewer",
      "type": "registry:ui",
      "title": "Diff Viewer",
      "author": "Rishabh Bose <https://theb0se.vercel.app/>",
      "description": "GitHub and GitLab-inspired code difference viewer featuring side-by-side split and unified inspection modes, line gutter numbering, collapsible unchanged regions, and copy diff clipboard actions.",
      "dependencies": [
        "framer-motion",
        "lucide-react",
        "clsx",
        "tailwind-merge"
      ],
      "files": [
        {
          "path": "components/ui/diff-viewer.tsx",
          "content": "\"use client\";\n\nimport React, { useState } from \"react\";\nimport { motion, AnimatePresence } from \"framer-motion\";\nimport {\n  FileCode2,\n  Columns2,\n  Rows3,\n  Copy,\n  Check,\n  ChevronDown,\n  ChevronRight,\n  GitCommit,\n  Plus,\n  Minus,\n  FileDiff,\n  Code2,\n} from \"lucide-react\";\nimport { cn } from \"@/lib/utils\";\n\nexport type DiffViewMode = \"split\" | \"unified\";\n\nexport interface DiffLine {\n  type: \"normal\" | \"add\" | \"del\";\n  oldLineNumber?: number;\n  newLineNumber?: number;\n  content: string;\n}\n\nexport interface DiffFile {\n  id: string;\n  fileName: string;\n  language: string;\n  additions: number;\n  deletions: number;\n  hunkHeader: string;\n  foldCount: number;\n  hiddenLines: DiffLine[];\n  visibleLines: DiffLine[];\n}\n\nexport interface DiffViewerProps {\n  initialViewMode?: DiffViewMode;\n  fileName?: string;\n  allowCopyDiff?: boolean;\n  className?: string;\n}\n\nconst SAMPLE_FILES: DiffFile[] = [\n  {\n    id: \"session-ts\",\n    fileName: \"src/auth/session.ts\",\n    language: \"typescript\",\n    additions: 8,\n    deletions: 4,\n    hunkHeader: \"@@ -14,12 +14,16 @@ export async function verifySession(token: string)\",\n    foldCount: 14,\n    hiddenLines: [\n      { type: \"normal\", oldLineNumber: 1, newLineNumber: 1, content: \"import { jwtVerify, createRemoteJWKSet } from '@/lib/auth-jwt';\" },\n      { type: \"normal\", oldLineNumber: 2, newLineNumber: 2, content: \"import { db } from '@/lib/database';\" },\n      { type: \"normal\", oldLineNumber: 3, newLineNumber: 3, content: \"import type { UserSession } from '@/types/auth';\" },\n      { type: \"normal\", oldLineNumber: 4, newLineNumber: 4, content: \"\" },\n      { type: \"normal\", oldLineNumber: 5, newLineNumber: 5, content: \"const JWKS = createRemoteJWKSet(new URL(process.env.AUTH_JWKS_URL!));\" },\n    ],\n    visibleLines: [\n      { type: \"normal\", oldLineNumber: 14, newLineNumber: 14, content: \"export async function verifySession(token: string) {\" },\n      { type: \"del\", oldLineNumber: 15, content: \"  // Legacy slow synchronous token verification\" },\n      { type: \"del\", oldLineNumber: 16, content: \"  const session = await db.sessions.findFirst({ where: { token } });\" },\n      { type: \"del\", oldLineNumber: 17, content: \"  if (!session) return null;\" },\n      { type: \"add\", newLineNumber: 15, content: \"  // Fast-path edge JWKS verification via V8 crypto isolate\" },\n      { type: \"add\", newLineNumber: 16, content: \"  const { payload } = await jwtVerify(token, JWKS, {\" },\n      { type: \"add\", newLineNumber: 17, content: \"    issuer: 'urn:pulse:issuer',\" },\n      { type: \"add\", newLineNumber: 18, content: \"    audience: 'urn:pulse:api',\" },\n      { type: \"add\", newLineNumber: 19, content: \"  });\" },\n      { type: \"add\", newLineNumber: 20, content: \"  const session = await db.sessions.getCached(payload.sub as string);\" },\n      { type: \"normal\", oldLineNumber: 18, newLineNumber: 21, content: \"  if (session.revokedAt) {\" },\n      { type: \"del\", oldLineNumber: 19, content: \"    throw new Error('SESSION_REVOKED');\" },\n      { type: \"add\", newLineNumber: 22, content: \"    throw new AuthenticationError('TOKEN_REVOKED', { cause: 401 });\" },\n      { type: \"normal\", oldLineNumber: 20, newLineNumber: 23, content: \"  }\" },\n      { type: \"normal\", oldLineNumber: 21, newLineNumber: 24, content: \"  return session;\" },\n      { type: \"normal\", oldLineNumber: 22, newLineNumber: 25, content: \"}\" },\n    ],\n  },\n  {\n    id: \"alloc-rs\",\n    fileName: \"crates/engine/src/alloc.rs\",\n    language: \"rust\",\n    additions: 6,\n    deletions: 3,\n    hunkHeader: \"@@ -42,8 +42,11 @@ impl MemoryPool\",\n    foldCount: 22,\n    hiddenLines: [\n      { type: \"normal\", oldLineNumber: 1, newLineNumber: 1, content: \"use std::alloc::{alloc, dealloc, Layout};\" },\n      { type: \"normal\", oldLineNumber: 2, newLineNumber: 2, content: \"use std::sync::atomic::{AtomicUsize, Ordering};\" },\n    ],\n    visibleLines: [\n      { type: \"normal\", oldLineNumber: 42, newLineNumber: 42, content: \"pub fn acquire_slice(&mut self, capacity: usize) -> &mut [u8] {\" },\n      { type: \"del\", oldLineNumber: 43, content: \"    let raw_buf = vec![0u8; capacity];\" },\n      { type: \"del\", oldLineNumber: 44, content: \"    self.heap_allocations.fetch_add(1, Ordering::Relaxed);\" },\n      { type: \"add\", newLineNumber: 43, content: \"    // Zero-copy ring buffer slice allocation\" },\n      { type: \"add\", newLineNumber: 44, content: \"    let offset = self.ring_head.fetch_add(capacity, Ordering::AcqRel);\" },\n      { type: \"add\", newLineNumber: 45, content: \"    assert!(offset + capacity <= self.ring_capacity, \\\"OOM in ring pool\\\");\" },\n      { type: \"normal\", oldLineNumber: 45, newLineNumber: 46, content: \"    unsafe {\" },\n      { type: \"del\", oldLineNumber: 46, content: \"        Box::leak(raw_buf.into_boxed_slice())\" },\n      { type: \"add\", newLineNumber: 47, content: \"        std::slice::from_raw_parts_mut(self.base_ptr.add(offset), capacity)\" },\n      { type: \"normal\", oldLineNumber: 47, newLineNumber: 48, content: \"    }\" },\n      { type: \"normal\", oldLineNumber: 48, newLineNumber: 49, content: \"}\" },\n    ],\n  },\n];\n\nexport function DiffViewer({\n  initialViewMode = \"unified\",\n  allowCopyDiff = true,\n  className,\n}: DiffViewerProps) {\n  const [viewMode, setViewMode] = useState<DiffViewMode>(initialViewMode);\n  const [activeFileIndex, setActiveFileIndex] = useState<number>(0);\n  const [isFoldExpanded, setIsFoldExpanded] = useState<boolean>(false);\n  const [copied, setCopied] = useState<boolean>(false);\n\n  const file = SAMPLE_FILES[activeFileIndex] || SAMPLE_FILES[0];\n  const allLines = isFoldExpanded\n    ? [...file.hiddenLines, ...file.visibleLines]\n    : file.visibleLines;\n\n  const handleCopyRaw = () => {\n    const rawPatch = [\n      `--- a/${file.fileName}`,\n      `+++ b/${file.fileName}`,\n      file.hunkHeader,\n      ...allLines.map((l) => {\n        if (l.type === \"add\") return `+${l.content}`;\n        if (l.type === \"del\") return `-${l.content}`;\n        return ` ${l.content}`;\n      }),\n    ].join(\"\\n\");\n\n    navigator.clipboard?.writeText(rawPatch);\n    setCopied(true);\n    setTimeout(() => setCopied(false), 2000);\n  };\n\n  return (\n    <div\n      data-fullscreen-scroll\n      className={cn(\n        \"relative w-full min-h-[520px] overflow-hidden rounded-2xl border border-neutral-800 bg-[#090B10] p-6 text-white shadow-2xl flex flex-col justify-between selection:bg-neutral-700\",\n        className\n      )}\n    >\n      {/* Top Header Toolbar */}\n      <div className=\"relative z-10 flex flex-wrap items-center justify-between gap-4 border-b border-neutral-800/80 pb-4\">\n        <div className=\"flex items-center gap-2.5\">\n          <div className=\"flex h-8 w-8 items-center justify-center rounded-lg border border-neutral-700 bg-neutral-900 font-mono text-xs font-bold text-neutral-200\">\n            <FileDiff className=\"h-4 w-4\" />\n          </div>\n          <div>\n            <div className=\"flex items-center gap-2\">\n              <h3 className=\"text-sm font-semibold tracking-tight text-white font-mono\">\n                {file.fileName}\n              </h3>\n              <div className=\"flex items-center gap-1 font-mono text-[11px]\">\n                <span className=\"text-emerald-400 font-semibold bg-emerald-950/60 px-1.5 py-0.2 rounded border border-emerald-900/50\">\n                  +{file.additions}\n                </span>\n                <span className=\"text-rose-400 font-semibold bg-rose-950/60 px-1.5 py-0.2 rounded border border-rose-900/50\">\n                  -{file.deletions}\n                </span>\n              </div>\n            </div>\n            <p className=\"text-xs text-neutral-400 font-mono mt-0.5\">\n              Pull Request #412 • branch <code className=\"text-neutral-300\">feat/perf-optimization</code>\n            </p>\n          </div>\n        </div>\n\n        {/* Live Controls */}\n        <div className=\"flex flex-wrap items-center gap-2\">\n          {/* File Switcher */}\n          <div className=\"flex items-center rounded-lg border border-neutral-800 bg-neutral-900/90 p-1\">\n            {SAMPLE_FILES.map((f, i) => (\n              <button\n                key={f.id}\n                onClick={() => {\n                  setActiveFileIndex(i);\n                  setIsFoldExpanded(false);\n                }}\n                className={cn(\n                  \"px-2.5 py-1 text-[11px] font-mono rounded transition-all\",\n                  activeFileIndex === i\n                    ? \"bg-neutral-800 text-white font-bold shadow-sm\"\n                    : \"text-neutral-400 hover:text-neutral-200\"\n                )}\n              >\n                {f.fileName.split(\"/\").pop()}\n              </button>\n            ))}\n          </div>\n\n          {/* View Mode Toggle */}\n          <div className=\"flex items-center rounded-lg border border-neutral-800 bg-neutral-900/90 p-1\">\n            <button\n              onClick={() => setViewMode(\"unified\")}\n              className={cn(\n                \"flex items-center gap-1.5 px-2.5 py-1 text-xs font-mono rounded transition-all\",\n                viewMode === \"unified\"\n                  ? \"bg-neutral-800 text-white font-bold shadow-sm\"\n                  : \"text-neutral-400 hover:text-neutral-200\"\n              )}\n            >\n              <Rows3 className=\"h-3 w-3\" />\n              <span>Unified</span>\n            </button>\n            <button\n              onClick={() => setViewMode(\"split\")}\n              className={cn(\n                \"flex items-center gap-1.5 px-2.5 py-1 text-xs font-mono rounded transition-all\",\n                viewMode === \"split\"\n                  ? \"bg-neutral-800 text-white font-bold shadow-sm\"\n                  : \"text-neutral-400 hover:text-neutral-200\"\n              )}\n            >\n              <Columns2 className=\"h-3 w-3\" />\n              <span>Split</span>\n            </button>\n          </div>\n\n          {/* Copy Patch */}\n          {allowCopyDiff && (\n            <button\n              onClick={handleCopyRaw}\n              className=\"flex items-center gap-1.5 px-3 py-1.5 text-xs font-mono rounded-lg border border-neutral-700 bg-neutral-800 text-neutral-200 hover:text-white transition-all shadow-sm\"\n            >\n              {copied ? (\n                <>\n                  <Check className=\"h-3 w-3 text-emerald-400\" />\n                  <span>Copied Patch</span>\n                </>\n              ) : (\n                <>\n                  <Copy className=\"h-3 w-3\" />\n                  <span>Copy Diff</span>\n                </>\n              )}\n            </button>\n          )}\n        </div>\n      </div>\n\n      {/* Main Diff Code Body */}\n      <div className=\"relative z-10 my-4 flex-1 overflow-x-auto rounded-xl border border-neutral-800/90 bg-[#05060A] font-mono text-xs shadow-inner\">\n        {/* Fold Expand Bar */}\n        <div\n          onClick={() => setIsFoldExpanded(!isFoldExpanded)}\n          role=\"button\"\n          tabIndex={0}\n          onKeyDown={(e) => {\n            if (e.key === \"Enter\" || e.key === \" \") {\n              e.preventDefault();\n              setIsFoldExpanded(!isFoldExpanded);\n            }\n          }}\n          className=\"flex cursor-pointer items-center justify-between border-b border-neutral-800/80 bg-neutral-900/50 px-4 py-1.5 text-[11px] text-neutral-400 hover:bg-neutral-800/60 hover:text-neutral-200 transition-colors\"\n        >\n          <div className=\"flex items-center gap-2\">\n            {isFoldExpanded ? (\n              <ChevronDown className=\"h-3.5 w-3.5 text-neutral-400\" />\n            ) : (\n              <ChevronRight className=\"h-3.5 w-3.5 text-neutral-400\" />\n            )}\n            <span className=\"text-cyan-400 font-medium\">{file.hunkHeader}</span>\n          </div>\n          <span className=\"text-neutral-500 text-[10px]\">\n            {isFoldExpanded ? \"Collapse unchanged lines\" : `Expand ${file.foldCount} unchanged lines`}\n          </span>\n        </div>\n\n        {/* Code Content: Unified Mode */}\n        {viewMode === \"unified\" && (\n          <div className=\"divide-y divide-neutral-900/40\">\n            {allLines.map((line, idx) => {\n              const isAdd = line.type === \"add\";\n              const isDel = line.type === \"del\";\n\n              return (\n                <div\n                  key={idx}\n                  className={cn(\n                    \"flex items-stretch text-[11px] font-mono leading-5 transition-colors\",\n                    isAdd && \"bg-emerald-950/25 text-emerald-200 hover:bg-emerald-950/40\",\n                    isDel && \"bg-rose-950/25 text-rose-200 hover:bg-rose-950/40\",\n                    !isAdd && !isDel && \"text-neutral-300 hover:bg-white/[0.02]\"\n                  )}\n                >\n                  {/* Old line gutter */}\n                  <span className=\"w-10 select-none text-right pr-2 text-neutral-600 bg-neutral-950/40 border-r border-neutral-900\">\n                    {line.oldLineNumber || \"\"}\n                  </span>\n\n                  {/* New line gutter */}\n                  <span className=\"w-10 select-none text-right pr-2 text-neutral-600 bg-neutral-950/40 border-r border-neutral-900\">\n                    {line.newLineNumber || \"\"}\n                  </span>\n\n                  {/* Indicator symbol (+ / - / space) */}\n                  <span\n                    className={cn(\n                      \"w-6 select-none text-center font-bold\",\n                      isAdd && \"text-emerald-400\",\n                      isDel && \"text-rose-400\",\n                      !isAdd && !isDel && \"text-neutral-600\"\n                    )}\n                  >\n                    {isAdd ? \"+\" : isDel ? \"-\" : \" \"}\n                  </span>\n\n                  {/* Code Line text */}\n                  <span className=\"flex-1 px-2 py-0.5 whitespace-pre overflow-x-auto\">\n                    {line.content}\n                  </span>\n                </div>\n              );\n            })}\n          </div>\n        )}\n\n        {/* Code Content: Split Mode (Side by Side) */}\n        {viewMode === \"split\" && (\n          <div className=\"grid grid-cols-2 divide-x divide-neutral-800\">\n            {/* Left Column (Deletions / Original) */}\n            <div className=\"divide-y divide-neutral-900/40\">\n              <div className=\"bg-neutral-900/80 px-3 py-1 text-[10px] uppercase font-mono text-neutral-400 border-b border-neutral-800\">\n                Original / Deletions\n              </div>\n              {allLines\n                .filter((l) => l.type !== \"add\")\n                .map((line, idx) => {\n                  const isDel = line.type === \"del\";\n                  return (\n                    <div\n                      key={`left-${idx}`}\n                      className={cn(\n                        \"flex items-stretch text-[11px] font-mono leading-5\",\n                        isDel ? \"bg-rose-950/30 text-rose-200\" : \"text-neutral-300\"\n                      )}\n                    >\n                      <span className=\"w-10 select-none text-right pr-2 text-neutral-600 bg-neutral-950/40 border-r border-neutral-900\">\n                        {line.oldLineNumber || \"\"}\n                      </span>\n                      <span className=\"w-6 select-none text-center font-bold text-rose-400\">\n                        {isDel ? \"-\" : \" \"}\n                      </span>\n                      <span className=\"flex-1 px-2 py-0.5 whitespace-pre overflow-x-auto\">\n                        {line.content}\n                      </span>\n                    </div>\n                  );\n                })}\n            </div>\n\n            {/* Right Column (Additions / Patched) */}\n            <div className=\"divide-y divide-neutral-900/40\">\n              <div className=\"bg-neutral-900/80 px-3 py-1 text-[10px] uppercase font-mono text-neutral-400 border-b border-neutral-800\">\n                Modified / Additions\n              </div>\n              {allLines\n                .filter((l) => l.type !== \"del\")\n                .map((line, idx) => {\n                  const isAdd = line.type === \"add\";\n                  return (\n                    <div\n                      key={`right-${idx}`}\n                      className={cn(\n                        \"flex items-stretch text-[11px] font-mono leading-5\",\n                        isAdd ? \"bg-emerald-950/30 text-emerald-200\" : \"text-neutral-300\"\n                      )}\n                    >\n                      <span className=\"w-10 select-none text-right pr-2 text-neutral-600 bg-neutral-950/40 border-r border-neutral-900\">\n                        {line.newLineNumber || \"\"}\n                      </span>\n                      <span className=\"w-6 select-none text-center font-bold text-emerald-400\">\n                        {isAdd ? \"+\" : \" \"}\n                      </span>\n                      <span className=\"flex-1 px-2 py-0.5 whitespace-pre overflow-x-auto\">\n                        {line.content}\n                      </span>\n                    </div>\n                  );\n                })}\n            </div>\n          </div>\n        )}\n      </div>\n\n      {/* Footer telemetry */}\n      <div className=\"relative z-10 flex flex-wrap items-center justify-between gap-2 border-t border-neutral-800/80 pt-3 text-[11px] font-mono text-neutral-400\">\n        <div className=\"flex items-center gap-2\">\n          <GitCommit className=\"h-3 w-3 text-neutral-500\" />\n          <span>COMMIT HASH: 8f49a2c</span>\n        </div>\n        <div className=\"flex items-center gap-4\">\n          <span>MODE: {viewMode.toUpperCase()} VIEW</span>\n          <span>SYNTAX: {file.language.toUpperCase()}</span>\n        </div>\n      </div>\n    </div>\n  );\n}\n\nexport default DiffViewer;\n",
          "type": "registry:ui",
          "target": "components/ui/diff-viewer.tsx"
        },
        {
          "path": "lib/utils.ts",
          "content": "import { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...inputs: ClassValue[]) {\n  return twMerge(clsx(inputs));\n}\n\nexport async function copyToClipboard(text: string): Promise<boolean> {\n  if (typeof window === \"undefined\") return false;\n\n  try {\n    if (navigator.clipboard && window.isSecureContext) {\n      await navigator.clipboard.writeText(text);\n      return true;\n    }\n\n    const textArea = document.createElement(\"textarea\");\n    textArea.value = text;\n    textArea.style.position = \"fixed\";\n    textArea.style.left = \"-999999px\";\n    textArea.style.top = \"-999999px\";\n    document.body.appendChild(textArea);\n    textArea.focus();\n    textArea.select();\n    const succeeded = document.execCommand(\"copy\");\n    textArea.remove();\n    return succeeded;\n  } catch {\n    return false;\n  }\n}\n",
          "type": "registry:lib",
          "target": "lib/utils.ts"
        }
      ]
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "digital-radar",
      "type": "registry:ui",
      "title": "Digital Radar",
      "author": "Rishabh Bose <https://theb0se.vercel.app/>",
      "description": "Tactical polar radar sweep background featuring concentric nautical range rings, degree azimuth ticks, a rotating phosphor conic beam, and target blips that illuminate with decaying afterglow on sweep contact.",
      "dependencies": [
        "lucide-react",
        "clsx",
        "tailwind-merge"
      ],
      "files": [
        {
          "path": "components/ui/digital-radar.tsx",
          "content": "\"use client\";\n\nimport React, { useEffect, useRef, useState } from \"react\";\nimport { Radar, Crosshair, Activity, Plus, ShieldAlert } from \"lucide-react\";\nimport { cn } from \"@/lib/utils\";\n\nexport interface DigitalRadarProps {\n  /** Angular rotation speed multiplier */\n  sweepSpeed?: number;\n  /** Number of tracked tactical blips */\n  blipCount?: number;\n  /** Primary radar phosphor color in hex format */\n  color?: string;\n  /** Number of concentric range rings */\n  rangeRings?: number;\n  /** Whether to render target coordinate labels and HUD readouts */\n  showTelemetry?: boolean;\n  /** Optional foreground content */\n  children?: React.ReactNode;\n  /** Additional Tailwind classes */\n  className?: string;\n}\n\ninterface RadarBlip {\n  id: string;\n  angle: number; // polar angle in radians [0, 2*PI)\n  distanceNorm: number; // normalized radius [0.16, 0.90]\n  heading: number; // target movement heading in radians\n  intensity: number; // [0, 1] phosphor excitation triggered on sweep contact\n  altitude: number; // Flight level in hundreds of feet\n  velocity: number; // Speed in knots\n  classification: \"HOSTILE\" | \"FRIENDLY\" | \"UNKNOWN\";\n  trail: { angle: number; dist: number }[];\n}\n\ninterface ClutterCell {\n  angle: number;\n  distNorm: number;\n  sizeNorm: number;\n  density: number;\n  intensity: number;\n}\n\nfunction hexToRgb(hex: string): { r: number; g: number; b: number } {\n  const clean = hex.replace(\"#\", \"\");\n  const full =\n    clean.length === 3\n      ? clean\n          .split(\"\")\n          .map((c) => c + c)\n          .join(\"\")\n      : clean;\n  const num = parseInt(full, 16);\n  if (Number.isNaN(num)) return { r: 16, g: 185, b: 129 };\n  return {\n    r: (num >> 16) & 255,\n    g: (num >> 8) & 255,\n    b: num & 255,\n  };\n}\n\nexport function DigitalRadar({\n  sweepSpeed: propSweepSpeed = 1.0,\n  blipCount: propBlipCount = 8,\n  color: propColor = \"#10B981\",\n  rangeRings: propRangeRings = 4,\n  showTelemetry: propShowTelemetry = true,\n  children,\n  className,\n}: DigitalRadarProps) {\n  const containerRef = useRef<HTMLDivElement>(null);\n  const canvasRef = useRef<HTMLCanvasElement>(null);\n\n  const [activeColor, setActiveColor] = useState(propColor);\n  const [activeSpeed, setActiveSpeed] = useState(propSweepSpeed);\n  const [activeBlipCount, setActiveBlipCount] = useState(propBlipCount);\n  const [showTelemetry, setShowTelemetry] = useState(propShowTelemetry);\n  const [sweepDeg, setSweepDeg] = useState(0);\n\n  useEffect(() => {\n    setActiveColor(propColor);\n  }, [propColor]);\n\n  useEffect(() => {\n    setActiveSpeed(propSweepSpeed);\n  }, [propSweepSpeed]);\n\n  useEffect(() => {\n    setActiveBlipCount(propBlipCount);\n  }, [propBlipCount]);\n\n  useEffect(() => {\n    setShowTelemetry(propShowTelemetry);\n  }, [propShowTelemetry]);\n\n  useEffect(() => {\n    const container = containerRef.current;\n    const canvas = canvasRef.current;\n    if (!container || !canvas) return;\n\n    const ctx = canvas.getContext(\"2d\");\n    if (!ctx) return;\n\n    let animationFrameId = 0;\n    let width = 0;\n    let height = 0;\n    let currentAngle = -Math.PI * 0.5;\n    let frameTick = 0;\n\n    // Generate procedural topographic / weather clutter cells in polar coordinates\n    const clutterClusters = [\n      { baseAngle: 0.75, baseDist: 0.58, spread: 0.36, count: 42 },\n      { baseAngle: 2.45, baseDist: 0.72, spread: 0.42, count: 48 },\n      { baseAngle: 4.3, baseDist: 0.44, spread: 0.28, count: 32 },\n    ];\n    const clutterCells: ClutterCell[] = [];\n    clutterClusters.forEach((cluster, cIdx) => {\n      for (let i = 0; i < cluster.count; i++) {\n        const seedA = Math.sin(i * 12.9898 + cIdx * 78.233) * 43758.5453;\n        const randA = seedA - Math.floor(seedA);\n        const seedB = Math.sin(i * 45.164 + cIdx * 19.13) * 23421.631;\n        const randB = seedB - Math.floor(seedB);\n\n        const angle =\n          (cluster.baseAngle + (randA - 0.5) * cluster.spread * 2 + Math.PI * 2) %\n          (Math.PI * 2);\n        const distNorm = Math.max(\n          0.12,\n          Math.min(0.94, cluster.baseDist + (randB - 0.5) * cluster.spread * 0.75)\n        );\n        clutterCells.push({\n          angle,\n          distNorm,\n          sizeNorm: 0.025 + (randA * 0.045),\n          density: 0.12 + randB * 0.22,\n          intensity: 0.2,\n        });\n      }\n    });\n\n    const callsigns = [\n      \"VPR-104\",\n      \"AEX-882\",\n      \"Kestrel-7\",\n      \"NVR-310\",\n      \"SIGMA-4\",\n      \"ORION-9\",\n      \"TALON-2\",\n      \"DRAKE-5\",\n      \"COBALT-6\",\n      \"APEX-12\",\n      \"VECTOR-8\",\n      \"TITAN-3\",\n      \"SPECTRE-1\",\n      \"NOVA-11\",\n    ];\n\n    const createBlips = (count: number): RadarBlip[] =>\n      Array.from({ length: Math.max(1, count) }, (_, i) => {\n        const angle = ((i / count) * Math.PI * 2 + Math.random() * 0.45) % (Math.PI * 2);\n        const distanceNorm = 0.22 + Math.random() * 0.65;\n        return {\n          id: callsigns[i % callsigns.length] || `TRK-${101 + i}`,\n          angle,\n          distanceNorm,\n          heading: angle + Math.PI * (0.55 + (Math.random() - 0.5) * 0.6),\n          intensity: 0.35 + Math.random() * 0.5,\n          altitude: Math.floor(140 + Math.random() * 280),\n          velocity: Math.floor(390 + Math.random() * 480),\n          classification:\n            i % 5 === 0 ? \"HOSTILE\" : i % 3 === 0 ? \"UNKNOWN\" : \"FRIENDLY\",\n          trail: [\n            { angle: angle - 0.03, dist: distanceNorm + 0.01 },\n            { angle: angle - 0.06, dist: distanceNorm + 0.02 },\n            { angle: angle - 0.09, dist: distanceNorm + 0.03 },\n          ],\n        };\n      });\n\n    let blips = createBlips(activeBlipCount);\n\n    const updateSize = () => {\n      const rect = container.getBoundingClientRect();\n      const dpr = Math.min(window.devicePixelRatio || 1, 2);\n      width = Math.max(1, Math.floor(rect.width));\n      height = Math.max(1, Math.floor(rect.height));\n      canvas.width = width * dpr;\n      canvas.height = height * dpr;\n      ctx.setTransform(dpr, 0, 0, dpr, 0, 0);\n    };\n\n    updateSize();\n    const observer = new ResizeObserver(updateSize);\n    observer.observe(container);\n\n    const rgb = hexToRgb(activeColor);\n    const brightR = Math.min(255, rgb.r + 120);\n    const brightG = Math.min(255, rgb.g + 120);\n    const brightB = Math.min(255, rgb.b + 120);\n\n    const isAngleCrossed = (target: number, prev: number, curr: number) => {\n      const normTarget = ((target % (Math.PI * 2)) + Math.PI * 2) % (Math.PI * 2);\n      const normPrev = ((prev % (Math.PI * 2)) + Math.PI * 2) % (Math.PI * 2);\n      const normCurr = ((curr % (Math.PI * 2)) + Math.PI * 2) % (Math.PI * 2);\n      if (normPrev <= normCurr) {\n        return normTarget >= normPrev && normTarget <= normCurr;\n      }\n      return normTarget >= normPrev || normTarget <= normCurr;\n    };\n\n    const render = () => {\n      frameTick++;\n      ctx.clearRect(0, 0, width, height);\n\n      const cx = width / 2;\n      const cy = height / 2;\n      const maxRadius = Math.min(width, height) * 0.405;\n\n      // Deep CRT Phosphor Scope Background\n      const bgGrad = ctx.createRadialGradient(\n        cx,\n        cy,\n        maxRadius * 0.05,\n        cx,\n        cy,\n        Math.max(width, height) * 0.65\n      );\n      bgGrad.addColorStop(0, `rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, 0.11)`);\n      bgGrad.addColorStop(0.55, \"rgba(3, 9, 15, 0.96)\");\n      bgGrad.addColorStop(1, \"rgba(1, 4, 8, 1)\");\n      ctx.fillStyle = bgGrad;\n      ctx.fillRect(0, 0, width, height);\n\n      // Subtle Cartesian Tactical Grid\n      ctx.strokeStyle = `rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, 0.045)`;\n      ctx.lineWidth = 1;\n      const gridStep = 36;\n      for (let x = cx % gridStep; x < width; x += gridStep) {\n        ctx.beginPath();\n        ctx.moveTo(x, 0);\n        ctx.lineTo(x, height);\n        ctx.stroke();\n      }\n      for (let y = cy % gridStep; y < height; y += gridStep) {\n        ctx.beginPath();\n        ctx.moveTo(0, y);\n        ctx.lineTo(width, y);\n        ctx.stroke();\n      }\n\n      // Advance sweep beam angle\n      const prevAngle = currentAngle;\n      const step = 0.017 * activeSpeed;\n      currentAngle = (currentAngle + step) % (Math.PI * 2);\n\n      if (frameTick % 4 === 0) {\n        setSweepDeg(Math.floor(((currentAngle * 180) / Math.PI + 90 + 360) % 360));\n      }\n\n      // 1. Render Topographic / Weather Radar Clutter Return inside scope clip\n      ctx.save();\n      ctx.beginPath();\n      ctx.arc(cx, cy, maxRadius - 2, 0, Math.PI * 2);\n      ctx.clip();\n\n      for (let i = 0; i < clutterCells.length; i++) {\n        const cell = clutterCells[i];\n        if (isAngleCrossed(cell.angle, prevAngle, currentAngle)) {\n          cell.intensity = 1.0;\n        } else {\n          cell.intensity = Math.max(0.14, cell.intensity * 0.991);\n        }\n\n        const cellX = cx + Math.cos(cell.angle) * (cell.distNorm * maxRadius);\n        const cellY = cy + Math.sin(cell.angle) * (cell.distNorm * maxRadius);\n        const cellR = cell.sizeNorm * maxRadius;\n\n        const cellGrad = ctx.createRadialGradient(\n          cellX,\n          cellY,\n          0,\n          cellX,\n          cellY,\n          cellR\n        );\n        const alpha = (cell.density * cell.intensity).toFixed(3);\n        cellGrad.addColorStop(0, `rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, ${alpha})`);\n        cellGrad.addColorStop(1, `rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, 0)`);\n\n        ctx.fillStyle = cellGrad;\n        ctx.beginPath();\n        ctx.arc(cellX, cellY, cellR, 0, Math.PI * 2);\n        ctx.fill();\n      }\n      ctx.restore();\n\n      // 2. Concentric Range Rings & Nautical Mile Scale\n      const rings = Math.max(2, Math.min(8, propRangeRings));\n      for (let i = 1; i <= rings; i++) {\n        const r = (maxRadius / rings) * i;\n        ctx.beginPath();\n        ctx.arc(cx, cy, r, 0, Math.PI * 2);\n        ctx.strokeStyle =\n          i === rings\n            ? `rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, 0.55)`\n            : `rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, 0.2)`;\n        ctx.lineWidth = i === rings ? 1.6 : 1;\n        ctx.stroke();\n\n        if (showTelemetry) {\n          ctx.fillStyle = `rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, 0.62)`;\n          ctx.font = \"600 9.5px ui-monospace, SFMono-Regular, Menlo, monospace\";\n          ctx.textAlign = \"left\";\n          ctx.fillText(`${i * 25} NM`, cx + 6, cy - r + 11);\n        }\n      }\n\n      // Outer Bezel Ring\n      ctx.beginPath();\n      ctx.arc(cx, cy, maxRadius + 16, 0, Math.PI * 2);\n      ctx.strokeStyle = `rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, 0.25)`;\n      ctx.lineWidth = 1;\n      ctx.stroke();\n\n      // Crosshair Cardinal Axes & 30-degree Radial Spokes\n      for (let deg = 0; deg < 360; deg += 30) {\n        const rad = (deg * Math.PI) / 180;\n        const isCardinal = deg % 90 === 0;\n        ctx.beginPath();\n        ctx.moveTo(\n          cx + Math.cos(rad) * (isCardinal ? 0 : maxRadius / rings),\n          cy + Math.sin(rad) * (isCardinal ? 0 : maxRadius / rings)\n        );\n        ctx.lineTo(cx + Math.cos(rad) * maxRadius, cy + Math.sin(rad) * maxRadius);\n        ctx.strokeStyle = isCardinal\n          ? `rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, 0.24)`\n          : `rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, 0.1)`;\n        ctx.lineWidth = 1;\n        ctx.stroke();\n      }\n\n      // 360-Degree Precision Compass Bezel Ticks & Bearings\n      for (let deg = 0; deg < 360; deg += 2) {\n        const rad = (deg * Math.PI) / 180;\n        const isMajor = deg % 30 === 0;\n        const isMed = deg % 10 === 0;\n        if (!isMed && deg % 4 !== 0) continue;\n\n        const innerTick = maxRadius + 2;\n        const outerTick = maxRadius + (isMajor ? 13 : isMed ? 8 : 5);\n\n        ctx.beginPath();\n        ctx.moveTo(cx + Math.cos(rad) * innerTick, cy + Math.sin(rad) * innerTick);\n        ctx.lineTo(cx + Math.cos(rad) * outerTick, cy + Math.sin(rad) * outerTick);\n        ctx.strokeStyle = isMajor\n          ? `rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, 0.7)`\n          : `rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, 0.28)`;\n        ctx.lineWidth = isMajor ? 1.5 : 1;\n        ctx.stroke();\n\n        if (isMajor && showTelemetry) {\n          const labelRadius = maxRadius + 26;\n          const lx = cx + Math.cos(rad) * labelRadius;\n          const ly = cy + Math.sin(rad) * labelRadius;\n          ctx.fillStyle = `rgba(${brightR}, ${brightG}, ${brightB}, 0.78)`;\n          ctx.font = \"600 10px ui-monospace, SFMono-Regular, Menlo, monospace\";\n          ctx.textAlign = \"center\";\n          ctx.textBaseline = \"middle\";\n          const compassDeg = (deg + 90) % 360;\n          ctx.fillText(`${String(compassDeg).padStart(3, \"0\")}°`, lx, ly);\n        }\n      }\n\n      // 3. Rotating Phosphor Conic Sweep Wedge\n      const slices = 46;\n      const trailArc = Math.PI * 0.48;\n      for (let s = 0; s < slices; s++) {\n        const ratio = s / slices;\n        const a0 = currentAngle - trailArc * (1 - ratio);\n        const a1 = currentAngle - trailArc * (1 - (s + 1) / slices);\n        ctx.beginPath();\n        ctx.moveTo(cx, cy);\n        ctx.arc(cx, cy, maxRadius, a0, a1);\n        ctx.closePath();\n        ctx.fillStyle = `rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, ${(\n          Math.pow(ratio, 2.35) * 0.28\n        ).toFixed(4)})`;\n        ctx.fill();\n      }\n\n      // Incandescent Leading Sweep Beam\n      ctx.save();\n      ctx.beginPath();\n      ctx.moveTo(cx, cy);\n      ctx.lineTo(\n        cx + Math.cos(currentAngle) * maxRadius,\n        cy + Math.sin(currentAngle) * maxRadius\n      );\n      ctx.strokeStyle = \"#FFFFFF\";\n      ctx.shadowColor = `rgba(${brightR}, ${brightG}, ${brightB}, 1)`;\n      ctx.shadowBlur = 14;\n      ctx.lineWidth = 2.2;\n      ctx.stroke();\n      ctx.restore();\n\n      // 4. Update & Render Tactical Target Blips, Velocity Vectors & Transponder Tags\n      for (let i = 0; i < blips.length; i++) {\n        const blip = blips[i];\n\n        // Slow orbital kinematics\n        blip.angle = (blip.angle + 0.00028 * activeSpeed) % (Math.PI * 2);\n\n        if (isAngleCrossed(blip.angle, prevAngle, currentAngle)) {\n          blip.intensity = 1.0;\n          // Push breadcrumb trail on sweep hit\n          blip.trail.unshift({ angle: blip.angle, dist: blip.distanceNorm });\n          if (blip.trail.length > 4) blip.trail.pop();\n        } else {\n          blip.intensity = Math.max(0.14, blip.intensity * 0.988);\n        }\n\n        const bx = cx + Math.cos(blip.angle) * (blip.distanceNorm * maxRadius);\n        const by = cy + Math.sin(blip.angle) * (blip.distanceNorm * maxRadius);\n\n        const isHostile = blip.classification === \"HOSTILE\";\n        const blipRgb = isHostile ? { r: 244, g: 63, b: 94 } : rgb;\n\n        // Draw decaying history breadcrumb dots\n        for (let t = 0; t < blip.trail.length; t++) {\n          const pt = blip.trail[t];\n          const tx = cx + Math.cos(pt.angle) * (pt.dist * maxRadius);\n          const ty = cy + Math.sin(pt.angle) * (pt.dist * maxRadius);\n          const tAlpha = blip.intensity * (1 - (t + 1) / (blip.trail.length + 1)) * 0.55;\n          ctx.beginPath();\n          ctx.arc(tx, ty, 1.8, 0, Math.PI * 2);\n          ctx.fillStyle = `rgba(${blipRgb.r}, ${blipRgb.g}, ${blipRgb.b}, ${tAlpha.toFixed(\n            3\n          )})`;\n          ctx.fill();\n        }\n\n        // Expanding sonar/radar ping wave immediately following sweep contact\n        if (blip.intensity > 0.62) {\n          const pingProgress = (1 - blip.intensity) / 0.38;\n          const pingRadius = 5 + pingProgress * 28;\n          ctx.beginPath();\n          ctx.arc(bx, by, pingRadius, 0, Math.PI * 2);\n          ctx.strokeStyle = `rgba(${blipRgb.r}, ${blipRgb.g}, ${blipRgb.b}, ${(\n            (1 - pingProgress) *\n            0.85\n          ).toFixed(3)})`;\n          ctx.lineWidth = 1.3;\n          ctx.stroke();\n        }\n\n        // Velocity Vector Leader Line showing projected heading\n        const vecLen = 18;\n        const vx = bx + Math.cos(blip.heading) * vecLen;\n        const vy = by + Math.sin(blip.heading) * vecLen;\n        ctx.beginPath();\n        ctx.moveTo(bx, by);\n        ctx.lineTo(vx, vy);\n        ctx.strokeStyle = `rgba(${blipRgb.r}, ${blipRgb.g}, ${blipRgb.b}, ${(\n          blip.intensity * 0.85\n        ).toFixed(3)})`;\n        ctx.lineWidth = 1.25;\n        ctx.stroke();\n\n        // Tactical Diamond / Reticle Symbol + Glowing Core\n        ctx.save();\n        ctx.translate(bx, by);\n        ctx.beginPath();\n        if (isHostile) {\n          // Diamond symbol for hostile contact\n          ctx.moveTo(0, -7);\n          ctx.lineTo(7, 0);\n          ctx.lineTo(0, 7);\n          ctx.lineTo(-7, 0);\n          ctx.closePath();\n        } else {\n          // Tactical bracketed square for friendly/unknown\n          ctx.rect(-6, -6, 12, 12);\n        }\n        ctx.strokeStyle = `rgba(${blipRgb.r}, ${blipRgb.g}, ${blipRgb.b}, ${Math.min(\n          1,\n          blip.intensity * 1.1\n        ).toFixed(3)})`;\n        ctx.lineWidth = 1.2;\n        ctx.stroke();\n\n        // Bright Phosphor Center Dot\n        ctx.beginPath();\n        ctx.arc(0, 0, 2.8, 0, Math.PI * 2);\n        ctx.fillStyle =\n          blip.intensity > 0.84\n            ? \"#FFFFFF\"\n            : `rgba(${blipRgb.r}, ${blipRgb.g}, ${blipRgb.b}, ${blip.intensity.toFixed(\n                3\n              )})`;\n        ctx.shadowColor = `rgba(${blipRgb.r}, ${blipRgb.g}, ${blipRgb.b}, 0.95)`;\n        ctx.shadowBlur = blip.intensity * 14;\n        ctx.fill();\n        ctx.restore();\n\n        // Crisp Transponder Data Block Callout\n        if (showTelemetry && blip.intensity > 0.2) {\n          const alpha = Math.min(1, blip.intensity * 0.98);\n          const calloutX = bx + 13;\n          const calloutY = by - 8;\n\n          // Leader tick from target to data block\n          ctx.beginPath();\n          ctx.moveTo(bx + 6, by - 4);\n          ctx.lineTo(calloutX - 2, calloutY + 2);\n          ctx.strokeStyle = `rgba(${blipRgb.r}, ${blipRgb.g}, ${blipRgb.b}, ${(\n            alpha * 0.6\n          ).toFixed(3)})`;\n          ctx.lineWidth = 0.8;\n          ctx.stroke();\n\n          ctx.font = \"700 10px ui-monospace, SFMono-Regular, Menlo, monospace\";\n          ctx.textAlign = \"left\";\n          ctx.textBaseline = \"alphabetic\";\n          ctx.fillStyle = isHostile\n            ? `rgba(251, 113, 133, ${alpha.toFixed(3)})`\n            : `rgba(${brightR}, ${brightG}, ${brightB}, ${alpha.toFixed(3)})`;\n          ctx.fillText(blip.id, calloutX, calloutY);\n\n          const bearingDeg = String(\n            Math.floor(((blip.angle * 180) / Math.PI + 90 + 360) % 360)\n          ).padStart(3, \"0\");\n          const rangeNm = Math.round(blip.distanceNorm * 100);\n\n          ctx.font = \"500 9px ui-monospace, SFMono-Regular, Menlo, monospace\";\n          ctx.fillStyle = `rgba(226, 232, 240, ${(alpha * 0.82).toFixed(3)})`;\n          ctx.fillText(\n            `FL${blip.altitude} · ${blip.velocity}KT`,\n            calloutX,\n            calloutY + 11\n          );\n          ctx.fillStyle = `rgba(${blipRgb.r}, ${blipRgb.g}, ${blipRgb.b}, ${(\n            alpha * 0.72\n          ).toFixed(3)})`;\n          ctx.fillText(\n            `${bearingDeg}°/${rangeNm}NM`,\n            calloutX,\n            calloutY + 21\n          );\n        }\n      }\n\n      // Center Radar Origin Reticle\n      ctx.beginPath();\n      ctx.arc(cx, cy, 4, 0, Math.PI * 2);\n      ctx.fillStyle = \"#FFFFFF\";\n      ctx.fill();\n      ctx.beginPath();\n      ctx.arc(cx, cy, 8, 0, Math.PI * 2);\n      ctx.strokeStyle = activeColor;\n      ctx.lineWidth = 1.2;\n      ctx.stroke();\n\n      animationFrameId = requestAnimationFrame(render);\n    };\n\n    animationFrameId = requestAnimationFrame(render);\n\n    return () => {\n      cancelAnimationFrame(animationFrameId);\n      observer.disconnect();\n    };\n  }, [activeColor, activeSpeed, activeBlipCount, propRangeRings, showTelemetry]);\n\n  return (\n    <div\n      ref={containerRef}\n      data-fullscreen-scroll\n      className={cn(\n        \"relative w-full min-h-[520px] overflow-hidden rounded-2xl border border-emerald-500/20 bg-[#010509] text-slate-100 shadow-2xl\",\n        className\n      )}\n    >\n      <canvas\n        ref={canvasRef}\n        aria-hidden=\"true\"\n        className=\"pointer-events-none absolute inset-0 h-full w-full\"\n      />\n\n      {/* CRT Glass Scanlines & Curved Scope Vignette */}\n      <div\n        aria-hidden=\"true\"\n        className=\"pointer-events-none absolute inset-0 bg-[linear-gradient(to_bottom,transparent_50%,rgba(0,0,0,0.25)_50%)] bg-[length:100%_4px] opacity-55\"\n      />\n      <div\n        aria-hidden=\"true\"\n        className=\"pointer-events-none absolute inset-0 bg-[radial-gradient(circle_at_center,transparent_48%,rgba(1,4,9,0.88)_100%)]\"\n      />\n\n      {children && (\n        <div className=\"relative z-10 flex min-h-[520px] w-full flex-col\">\n          {children}\n        </div>\n      )}\n    </div>\n  );\n}\n\nexport default DigitalRadar;\n",
          "type": "registry:ui",
          "target": "components/ui/digital-radar.tsx"
        },
        {
          "path": "lib/utils.ts",
          "content": "import { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...inputs: ClassValue[]) {\n  return twMerge(clsx(inputs));\n}\n\nexport async function copyToClipboard(text: string): Promise<boolean> {\n  if (typeof window === \"undefined\") return false;\n\n  try {\n    if (navigator.clipboard && window.isSecureContext) {\n      await navigator.clipboard.writeText(text);\n      return true;\n    }\n\n    const textArea = document.createElement(\"textarea\");\n    textArea.value = text;\n    textArea.style.position = \"fixed\";\n    textArea.style.left = \"-999999px\";\n    textArea.style.top = \"-999999px\";\n    document.body.appendChild(textArea);\n    textArea.focus();\n    textArea.select();\n    const succeeded = document.execCommand(\"copy\");\n    textArea.remove();\n    return succeeded;\n  } catch {\n    return false;\n  }\n}\n",
          "type": "registry:lib",
          "target": "lib/utils.ts"
        }
      ]
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "dock-magnification",
      "type": "registry:ui",
      "title": "macOS Dock Magnification",
      "author": "Rishabh Bose <https://theb0se.vercel.app/>",
      "description": "macOS-inspired dock magnification bar with continuous Gaussian/cosine pointer falloff, spring physics scaling, click-to-bounce launch animations, floating tooltip labels, and running indicator dots.",
      "dependencies": [
        "framer-motion",
        "lucide-react",
        "clsx",
        "tailwind-merge"
      ],
      "files": [
        {
          "path": "components/ui/dock-magnification.tsx",
          "content": "\"use client\";\n\nimport React, { useState, useRef, useEffect } from \"react\";\nimport {\n  motion,\n  useMotionValue,\n  useSpring,\n  useTransform,\n  AnimatePresence,\n  MotionValue,\n} from \"framer-motion\";\nimport {\n  Folder,\n  Compass,\n  MessageSquare,\n  Terminal,\n  Music,\n  Camera,\n  Calendar,\n  Settings,\n  Sliders,\n  Sparkles,\n  Play,\n  RotateCcw,\n} from \"lucide-react\";\nimport { cn } from \"@/lib/utils\";\n\nexport interface DockAppItem {\n  id: string;\n  name: string;\n  icon: React.ComponentType<{ className?: string }>;\n  color: string;\n  gradient: string;\n  isRunning?: boolean;\n  notificationCount?: number;\n}\n\nexport interface DockMagnificationProps {\n  /** Array of dock items */\n  items?: DockAppItem[];\n  /** Default base item size in px */\n  baseSize?: number;\n  /** Max magnification factor (e.g. 1.8) */\n  magnification?: number;\n  /** Falloff distance in px */\n  distance?: number;\n  /** On app click callback */\n  onItemClick?: (item: DockAppItem) => void;\n  /** Whether the dock is embedded in another section without full desktop window framing */\n  embedded?: boolean;\n  /** Container custom classes */\n  className?: string;\n}\n\nconst DEFAULT_DOCK_ITEMS: DockAppItem[] = [\n  {\n    id: \"finder\",\n    name: \"Finder\",\n    icon: Folder,\n    color: \"#3B82F6\",\n    gradient: \"from-blue-500 to-cyan-500\",\n    isRunning: true,\n  },\n  {\n    id: \"safari\",\n    name: \"Safari\",\n    icon: Compass,\n    color: \"#0284C7\",\n    gradient: \"from-sky-400 to-blue-600\",\n    isRunning: true,\n  },\n  {\n    id: \"messages\",\n    name: \"Messages\",\n    icon: MessageSquare,\n    color: \"#22C55E\",\n    gradient: \"from-emerald-400 to-green-600\",\n    isRunning: true,\n    notificationCount: 3,\n  },\n  {\n    id: \"terminal\",\n    name: \"Terminal\",\n    icon: Terminal,\n    color: \"#1E293B\",\n    gradient: \"from-neutral-800 to-neutral-950\",\n    isRunning: true,\n  },\n  {\n    id: \"music\",\n    name: \"Music\",\n    icon: Music,\n    color: \"#F43F5E\",\n    gradient: \"from-rose-500 to-red-600\",\n    isRunning: false,\n  },\n  {\n    id: \"photos\",\n    name: \"Photos\",\n    icon: Camera,\n    color: \"#EAB308\",\n    gradient: \"from-amber-400 to-yellow-600\",\n    isRunning: false,\n  },\n  {\n    id: \"calendar\",\n    name: \"Calendar\",\n    icon: Calendar,\n    color: \"#EF4444\",\n    gradient: \"from-red-500 to-rose-600\",\n    isRunning: true,\n  },\n  {\n    id: \"settings\",\n    name: \"System Settings\",\n    icon: Settings,\n    color: \"#64748B\",\n    gradient: \"from-slate-500 to-neutral-700\",\n    isRunning: false,\n  },\n];\n\ninterface DockIconProps {\n  item: DockAppItem;\n  mouseX: MotionValue<number>;\n  baseSize: number;\n  magnification: number;\n  distanceThreshold: number;\n  onClick: (item: DockAppItem) => void;\n}\n\nfunction DockIcon({\n  item,\n  mouseX,\n  baseSize,\n  magnification,\n  distanceThreshold,\n  onClick,\n}: DockIconProps) {\n  const ref = useRef<HTMLDivElement>(null);\n  const [isHovered, setIsHovered] = useState(false);\n  const [isBouncing, setIsBouncing] = useState(false);\n\n  // Compute continuous distance from mouse pointer\n  const distance = useTransform(mouseX, (val) => {\n    const bounds = ref.current?.getBoundingClientRect();\n    if (!bounds || val === Infinity) return Infinity;\n    return val - (bounds.x + bounds.width / 2);\n  });\n\n  // Calculate width transformation with cosine/gaussian-like interpolation\n  const sizeTransform = useTransform(\n    distance,\n    [-distanceThreshold, 0, distanceThreshold],\n    [baseSize, baseSize * magnification, baseSize]\n  );\n\n  const springSize = useSpring(sizeTransform, {\n    mass: 0.1,\n    stiffness: 170,\n    damping: 14,\n  });\n\n  const handleClick = () => {\n    setIsBouncing(true);\n    onClick(item);\n    setTimeout(() => {\n      setIsBouncing(false);\n    }, 1200);\n  };\n\n  const IconComponent = item.icon;\n\n  return (\n    <div\n      ref={ref}\n      onMouseEnter={() => setIsHovered(true)}\n      onMouseLeave={() => setIsHovered(false)}\n      className=\"relative flex flex-col items-center justify-end\"\n    >\n      {/* macOS Floating Tooltip */}\n      <AnimatePresence>\n        {isHovered && (\n          <motion.div\n            initial={{ opacity: 0, y: 8, scale: 0.85 }}\n            animate={{ opacity: 1, y: -10, scale: 1 }}\n            exit={{ opacity: 0, y: 4, scale: 0.85 }}\n            transition={{ duration: 0.15 }}\n            className=\"pointer-events-none absolute -top-8 z-50 whitespace-nowrap rounded-lg border border-white/20 bg-neutral-900/90 px-3 py-1 text-xs font-medium text-white shadow-xl backdrop-blur-md\"\n          >\n            {item.name}\n          </motion.div>\n        )}\n      </AnimatePresence>\n\n      {/* Main Animated Icon Container */}\n      <motion.button\n        type=\"button\"\n        onClick={handleClick}\n        style={{\n          width: springSize,\n          height: springSize,\n        }}\n        animate={\n          isBouncing\n            ? {\n              y: [0, -32, 0, -18, 0, -8, 0],\n            }\n            : { y: 0 }\n        }\n        transition={\n          isBouncing\n            ? {\n              duration: 1.1,\n              times: [0, 0.2, 0.45, 0.65, 0.8, 0.9, 1],\n              ease: \"easeOut\",\n            }\n            : undefined\n        }\n        className={cn(\n          \"group relative flex items-center justify-center rounded-2xl p-2.5 shadow-lg ring-1 ring-white/25 transition-transform active:scale-95\",\n          `bg-gradient-to-br ${item.gradient}`\n        )}\n        aria-label={item.name}\n      >\n        <IconComponent className=\"h-full w-full text-white drop-shadow-md transition-transform\" />\n\n        {/* Glossy top-specular sheen */}\n        <div className=\"pointer-events-none absolute inset-x-0 top-0 h-1/2 rounded-t-2xl bg-gradient-to-b from-white/30 to-transparent\" />\n\n        {/* Notification badge */}\n        {item.notificationCount && (\n          <span className=\"absolute -top-1 -right-1 flex h-4.5 min-w-4.5 items-center justify-center rounded-full bg-red-500 px-1 text-[10px] font-bold text-white shadow ring-2 ring-neutral-900\">\n            {item.notificationCount}\n          </span>\n        )}\n      </motion.button>\n\n      {/* macOS Running Indicator Dot */}\n      <div className=\"mt-1 flex h-1.5 w-full items-center justify-center\">\n        {item.isRunning && (\n          <span className=\"h-1 w-1 rounded-full bg-white/80 shadow-[0_0_4px_rgba(255,255,255,0.8)]\" />\n        )}\n      </div>\n    </div>\n  );\n}\n\nexport function DockMagnification({\n  items = DEFAULT_DOCK_ITEMS,\n  baseSize = 48,\n  magnification = 1.65,\n  distance = 140,\n  onItemClick,\n  embedded = false,\n  className,\n}: DockMagnificationProps) {\n  const [currentMagnification, setCurrentMagnification] = useState(magnification);\n  const [currentDistance, setCurrentDistance] = useState(distance);\n  const [lastClickedApp, setLastClickedApp] = useState<string | null>(\"Safari\");\n  const [showRunningOnly, setShowRunningOnly] = useState(false);\n\n  const mouseX = useMotionValue(Infinity);\n\n  const filteredItems = showRunningOnly\n    ? items.filter((item) => item.isRunning)\n    : items;\n\n  const handleItemClick = (item: DockAppItem) => {\n    setLastClickedApp(item.name);\n    onItemClick?.(item);\n  };\n\n  if (embedded) {\n    return (\n      <div className={cn(\"relative flex items-center justify-center\", className)}>\n        <motion.div\n          onMouseMove={(e) => mouseX.set(e.pageX)}\n          onMouseLeave={() => mouseX.set(Infinity)}\n          className=\"relative flex items-end gap-3.5 rounded-3xl border border-white/20 bg-white/10 px-4 py-3 shadow-[0_20px_50px_rgba(0,0,0,0.6)] backdrop-blur-2xl ring-1 ring-white/10 dark:bg-black/50\"\n        >\n          {filteredItems.map((item) => (\n            <DockIcon\n              key={item.id}\n              item={item}\n              mouseX={mouseX}\n              baseSize={baseSize}\n              magnification={currentMagnification}\n              distanceThreshold={currentDistance}\n              onClick={handleItemClick}\n            />\n          ))}\n        </motion.div>\n      </div>\n    );\n  }\n\n  return (\n    <div\n      data-fullscreen-scroll\n      className={cn(\n        \"relative w-full min-h-[520px] overflow-hidden rounded-2xl border border-neutral-200/80 bg-[#090D16] p-6 text-neutral-100 shadow-2xl transition-all dark:border-neutral-800\",\n        className\n      )}\n    >\n      {/* Atmospheric macOS Desktop Wallpaper Background */}\n      <div\n        className=\"pointer-events-none absolute inset-0 opacity-70\"\n        style={{\n          background: `radial-gradient(ellipse 80% 60% at 50% 20%, rgba(59, 130, 246, 0.22), transparent 70%),\n                       radial-gradient(ellipse 60% 50% at 80% 80%, rgba(236, 72, 153, 0.16), transparent 70%),\n                       radial-gradient(ellipse 50% 50% at 20% 70%, rgba(139, 92, 246, 0.18), transparent 70%)`,\n        }}\n      />\n\n      {/* Desktop Top Menu Bar Simulation */}\n      <div className=\"relative z-10 flex flex-wrap items-center justify-between gap-4 border-b border-white/10 pb-4\">\n        <div>\n          <div className=\"inline-flex items-center gap-2 rounded-full border border-white/15 bg-white/10 px-3 py-1 text-xs font-medium text-white backdrop-blur-md\">\n            <Sparkles className=\"h-3 w-3 text-sky-400\" />\n            macOS Desktop Dock Simulation\n          </div>\n          <h2 className=\"mt-2 text-xl font-semibold tracking-tight text-white\">\n            macOS Continuous Spring Dock\n          </h2>\n          <p className=\"text-xs text-neutral-300\">\n            Continuous Gaussian pointer falloff with spring physics, click-to-bounce, and status dots\n          </p>\n        </div>\n\n        {/* Live Status indicator */}\n        <div className=\"flex items-center gap-2 rounded-xl border border-white/10 bg-black/40 px-3 py-1.5 text-xs text-neutral-300 backdrop-blur-md\">\n          <span className=\"h-2 w-2 rounded-full bg-emerald-400 animate-pulse\" />\n          <span>Active App: </span>\n          <strong className=\"text-white\">{lastClickedApp || \"None\"}</strong>\n        </div>\n      </div>\n\n      {/* Center Desktop Area */}\n      <div className=\"relative z-10 flex flex-col items-center justify-center py-16\">\n        <div className=\"text-center mb-8\">\n          <span className=\"text-xs font-medium text-neutral-400 uppercase tracking-widest\">\n            Interactive Test Stage\n          </span>\n          <p className=\"text-sm text-neutral-300 mt-1\">\n            Glide your pointer across the dock to inspect smooth magnification curves. Click an icon to trigger spring bounce.\n          </p>\n        </div>\n\n        {/* The macOS Dock Bar */}\n        <motion.div\n          onMouseMove={(e) => mouseX.set(e.pageX)}\n          onMouseLeave={() => mouseX.set(Infinity)}\n          className=\"relative flex items-end gap-3.5 rounded-3xl border border-white/20 bg-white/15 px-4 py-3 shadow-[0_20px_50px_rgba(0,0,0,0.6)] backdrop-blur-2xl ring-1 ring-white/10 dark:bg-black/40\"\n        >\n          {filteredItems.map((item) => (\n            <DockIcon\n              key={item.id}\n              item={item}\n              mouseX={mouseX}\n              baseSize={baseSize}\n              magnification={currentMagnification}\n              distanceThreshold={currentDistance}\n              onClick={handleItemClick}\n            />\n          ))}\n        </motion.div>\n      </div>\n    </div>\n  );\n}\n\nexport default DockMagnification;\n",
          "type": "registry:ui",
          "target": "components/ui/dock-magnification.tsx"
        },
        {
          "path": "lib/utils.ts",
          "content": "import { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...inputs: ClassValue[]) {\n  return twMerge(clsx(inputs));\n}\n\nexport async function copyToClipboard(text: string): Promise<boolean> {\n  if (typeof window === \"undefined\") return false;\n\n  try {\n    if (navigator.clipboard && window.isSecureContext) {\n      await navigator.clipboard.writeText(text);\n      return true;\n    }\n\n    const textArea = document.createElement(\"textarea\");\n    textArea.value = text;\n    textArea.style.position = \"fixed\";\n    textArea.style.left = \"-999999px\";\n    textArea.style.top = \"-999999px\";\n    document.body.appendChild(textArea);\n    textArea.focus();\n    textArea.select();\n    const succeeded = document.execCommand(\"copy\");\n    textArea.remove();\n    return succeeded;\n  } catch {\n    return false;\n  }\n}\n",
          "type": "registry:lib",
          "target": "lib/utils.ts"
        }
      ]
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "drawer",
      "type": "registry:ui",
      "title": "Drawer",
      "author": "Rishabh Bose <https://theb0se.vercel.app/>",
      "description": "Slide-over panel and bottom sheet drawer with 4-direction support, drag-to-dismiss gestures, top-level portal rendering, and Escape dismissal.",
      "dependencies": [
        "framer-motion",
        "lucide-react",
        "clsx",
        "tailwind-merge"
      ],
      "files": [
        {
          "path": "components/ui/drawer.tsx",
          "content": "\"use client\";\n\nimport React, { useEffect, useState, useCallback } from \"react\";\nimport { createPortal } from \"react-dom\";\nimport { AnimatePresence, motion, useReducedMotion } from \"framer-motion\";\nimport { X } from \"lucide-react\";\nimport { cn } from \"@/lib/utils\";\n\nexport type DrawerSide = \"right\" | \"left\" | \"bottom\" | \"top\";\n\nexport interface DrawerProps {\n  /** Controlled open state */\n  open?: boolean;\n  /** Default open state when uncontrolled */\n  defaultOpen?: boolean;\n  /** Callback when open state changes */\n  onOpenChange?: (open: boolean) => void;\n  /** Edge of the viewport the drawer slides from */\n  side?: DrawerSide;\n  /** Drawer header title */\n  title?: string;\n  /** Optional subtitle below the title */\n  description?: string;\n  /** Trigger button label if used self-contained */\n  triggerLabel?: string;\n  /** Custom trigger element */\n  trigger?: React.ReactNode;\n  /** Drawer body content */\n  children?: React.ReactNode;\n  /** Optional footer actions */\n  footer?: React.ReactNode;\n  /** Additional panel class names */\n  className?: string;\n}\n\nconst SIDE_VARIANTS: Record<\n  DrawerSide,\n  {\n    initial: Record<string, string | number>;\n    animate: Record<string, string | number>;\n    exit: Record<string, string | number>;\n    panelClass: string;\n    dragAxis: \"x\" | \"y\";\n    dragConstraints: { top?: number; bottom?: number; left?: number; right?: number };\n  }\n> = {\n  right: {\n    initial: { x: \"100%\" },\n    animate: { x: 0 },\n    exit: { x: \"100%\" },\n    panelClass: \"inset-y-0 right-0 h-dvh w-full max-w-md border-l\",\n    dragAxis: \"x\",\n    dragConstraints: { left: 0 },\n  },\n  left: {\n    initial: { x: \"-100%\" },\n    animate: { x: 0 },\n    exit: { x: \"-100%\" },\n    panelClass: \"inset-y-0 left-0 h-dvh w-full max-w-md border-r\",\n    dragAxis: \"x\",\n    dragConstraints: { right: 0 },\n  },\n  bottom: {\n    initial: { y: \"100%\" },\n    animate: { y: 0 },\n    exit: { y: \"100%\" },\n    panelClass: \"inset-x-0 bottom-0 w-full max-h-[85dvh] rounded-t-2xl border-t\",\n    dragAxis: \"y\",\n    dragConstraints: { top: 0 },\n  },\n  top: {\n    initial: { y: \"-100%\" },\n    animate: { y: 0 },\n    exit: { y: \"-100%\" },\n    panelClass: \"inset-x-0 top-0 w-full max-h-[85dvh] rounded-b-2xl border-b\",\n    dragAxis: \"y\",\n    dragConstraints: { bottom: 0 },\n  },\n};\n\nexport function Drawer({\n  open: controlledOpen,\n  defaultOpen = false,\n  onOpenChange,\n  side = \"right\",\n  title = \"Drawer Panel\",\n  description,\n  triggerLabel = \"Open Drawer\",\n  trigger,\n  children,\n  footer,\n  className,\n}: DrawerProps) {\n  const shouldReduceMotion = useReducedMotion();\n  const [mounted, setMounted] = useState(false);\n  const [internalOpen, setInternalOpen] = useState(defaultOpen);\n  const isOpen = controlledOpen !== undefined ? controlledOpen : internalOpen;\n\n  useEffect(() => {\n    setMounted(true);\n  }, []);\n\n  const setOpen = useCallback(\n    (next: boolean) => {\n      if (controlledOpen === undefined) {\n        setInternalOpen(next);\n      }\n      onOpenChange?.(next);\n    },\n    [controlledOpen, onOpenChange]\n  );\n\n  useEffect(() => {\n    if (!isOpen) return;\n    const previousOverflow = document.body.style.overflow;\n    document.body.style.overflow = \"hidden\";\n\n    const handleKeyDown = (e: KeyboardEvent) => {\n      if (e.key === \"Escape\") setOpen(false);\n    };\n    window.addEventListener(\"keydown\", handleKeyDown);\n    return () => {\n      document.body.style.overflow = previousOverflow;\n      window.removeEventListener(\"keydown\", handleKeyDown);\n    };\n  }, [isOpen, setOpen]);\n\n  const variant = SIDE_VARIANTS[side];\n\n  const overlayContent = (\n    <AnimatePresence>\n      {isOpen && (\n        <div className=\"fixed inset-0 z-[9999] flex\">\n          {/* Fullscreen Backdrop */}\n          <motion.div\n            initial={{ opacity: 0 }}\n            animate={{ opacity: 1 }}\n            exit={{ opacity: 0 }}\n            transition={{ duration: shouldReduceMotion ? 0 : 0.2 }}\n            onClick={() => setOpen(false)}\n            className=\"fixed inset-0 z-[9998] bg-black/60 backdrop-blur-xs\"\n            aria-hidden=\"true\"\n          />\n\n          {/* Sliding Panel */}\n          <motion.div\n            role=\"dialog\"\n            aria-modal=\"true\"\n            aria-label={title}\n            initial={shouldReduceMotion ? { opacity: 0 } : variant.initial}\n            animate={shouldReduceMotion ? { opacity: 1 } : variant.animate}\n            exit={shouldReduceMotion ? { opacity: 0 } : variant.exit}\n            transition={{\n              type: \"spring\",\n              stiffness: 380,\n              damping: 34,\n            }}\n            drag={shouldReduceMotion ? false : variant.dragAxis}\n            dragConstraints={variant.dragConstraints}\n            dragElastic={0.12}\n            onDragEnd={(_, info) => {\n              if (side === \"bottom\" && info.offset.y > 90) setOpen(false);\n              if (side === \"top\" && info.offset.y < -90) setOpen(false);\n              if (side === \"right\" && info.offset.x > 90) setOpen(false);\n              if (side === \"left\" && info.offset.x < -90) setOpen(false);\n            }}\n            className={cn(\n              \"fixed z-[9999] flex flex-col justify-between border-neutral-200 bg-white p-6 text-black shadow-2xl dark:border-[#222222] dark:bg-[#0A0A0A] dark:text-white\",\n              variant.panelClass,\n              className\n            )}\n          >\n            {side === \"bottom\" && (\n              <div className=\"mx-auto mb-4 h-1.5 w-12 rounded-full bg-neutral-300 dark:bg-neutral-700\" />\n            )}\n\n            {/* Header */}\n            <div className=\"flex items-start justify-between gap-4 border-b border-neutral-200 pb-4 dark:border-[#1F1F1F]\">\n              <div>\n                <h3 className=\"text-base font-semibold tracking-tight text-black dark:text-white\">\n                  {title}\n                </h3>\n                {description && (\n                  <p className=\"mt-1 text-xs text-neutral-500 dark:text-neutral-400\">\n                    {description}\n                  </p>\n                )}\n              </div>\n              <button\n                type=\"button\"\n                onClick={() => setOpen(false)}\n                aria-label=\"Close drawer\"\n                className=\"cursor-pointer rounded-lg border border-neutral-200 p-1.5 text-neutral-500 transition-colors hover:border-black hover:text-black dark:border-[#262626] dark:hover:border-white dark:hover:text-white\"\n              >\n                <X className=\"h-4 w-4\" />\n              </button>\n            </div>\n\n            {/* Body */}\n            <div className=\"my-4 flex-1 overflow-y-auto text-xs leading-relaxed text-neutral-600 dark:text-neutral-300\">\n              {children || (\n                <div className=\"space-y-3 py-2\">\n                  <p>\n                    This drawer renders in a top-level React portal (z-9999)\n                    above all headers, sidebars, and page content. You can also\n                    drag it toward the screen edge to dismiss.\n                  </p>\n                  <div className=\"rounded-xl border border-neutral-200 bg-neutral-50 p-3 font-mono text-[11px] dark:border-[#1F1F1F] dark:bg-[#111111]\">\n                    side=&quot;{side}&quot; · Drag or press ESC to close\n                  </div>\n                </div>\n              )}\n            </div>\n\n            {/* Footer */}\n            <div className=\"flex items-center justify-end gap-2 border-t border-neutral-200 pt-4 dark:border-[#1F1F1F]\">\n              {footer || (\n                <>\n                  <button\n                    type=\"button\"\n                    onClick={() => setOpen(false)}\n                    className=\"cursor-pointer rounded-lg border border-neutral-200 px-3.5 py-1.5 text-xs font-medium text-neutral-600 transition-colors hover:border-black hover:text-black dark:border-[#262626] dark:text-neutral-400 dark:hover:border-white dark:hover:text-white\"\n                  >\n                    Cancel\n                  </button>\n                  <button\n                    type=\"button\"\n                    onClick={() => setOpen(false)}\n                    className=\"cursor-pointer rounded-lg bg-black px-3.5 py-1.5 text-xs font-medium text-white transition-colors hover:bg-neutral-800 dark:bg-white dark:text-black dark:hover:bg-neutral-200\"\n                  >\n                    Save Changes\n                  </button>\n                </>\n              )}\n            </div>\n          </motion.div>\n        </div>\n      )}\n    </AnimatePresence>\n  );\n\n  return (\n    <>\n      {trigger ? (\n        <div onClick={() => setOpen(true)} className=\"inline-block cursor-pointer\">\n          {trigger}\n        </div>\n      ) : (\n        <button\n          type=\"button\"\n          onClick={() => setOpen(true)}\n          className=\"inline-flex cursor-pointer items-center justify-center rounded-xl border border-neutral-200 bg-white px-4 py-2 text-xs font-medium text-black transition-colors hover:border-black dark:border-[#262626] dark:bg-[#0A0A0A] dark:text-white dark:hover:border-white\"\n        >\n          {triggerLabel}\n        </button>\n      )}\n\n      {mounted && createPortal(overlayContent, document.body)}\n    </>\n  );\n}\n\nexport default Drawer;\n",
          "type": "registry:ui",
          "target": "components/ui/drawer.tsx"
        },
        {
          "path": "lib/utils.ts",
          "content": "import { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...inputs: ClassValue[]) {\n  return twMerge(clsx(inputs));\n}\n\nexport async function copyToClipboard(text: string): Promise<boolean> {\n  if (typeof window === \"undefined\") return false;\n\n  try {\n    if (navigator.clipboard && window.isSecureContext) {\n      await navigator.clipboard.writeText(text);\n      return true;\n    }\n\n    const textArea = document.createElement(\"textarea\");\n    textArea.value = text;\n    textArea.style.position = \"fixed\";\n    textArea.style.left = \"-999999px\";\n    textArea.style.top = \"-999999px\";\n    document.body.appendChild(textArea);\n    textArea.focus();\n    textArea.select();\n    const succeeded = document.execCommand(\"copy\");\n    textArea.remove();\n    return succeeded;\n  } catch {\n    return false;\n  }\n}\n",
          "type": "registry:lib",
          "target": "lib/utils.ts"
        }
      ]
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "dynamic-island-toast",
      "type": "registry:ui",
      "title": "Dynamic Island Toast",
      "author": "Rishabh Bose <https://theb0se.vercel.app/>",
      "description": "Morphing top-edge status capsule that expands smoothly between compact badge, live telemetry pill, and actionable notification drawer.",
      "dependencies": [
        "framer-motion",
        "lucide-react",
        "clsx",
        "tailwind-merge"
      ],
      "files": [
        {
          "path": "components/ui/dynamic-island-toast.tsx",
          "content": "\"use client\";\n\nimport React, { useState } from \"react\";\nimport { AnimatePresence, motion, useReducedMotion } from \"framer-motion\";\nimport { Activity, CheckCircle2, Sparkles, X } from \"lucide-react\";\nimport { cn } from \"@/lib/utils\";\n\nexport type IslandMode = \"compact\" | \"telemetry\" | \"expanded\";\n\nexport interface DynamicIslandToastProps {\n  /** Initial state mode of the dynamic capsule. Default: \"compact\" */\n  defaultMode?: IslandMode;\n  /** Title displayed in expanded and telemetry modes. Default: \"Registry Sync Active\" */\n  title?: string;\n  /** Subtitle displayed inside the expanded capsule. Default: \"12 shadcn v2 manifests compiled in 42ms\" */\n  subtitle?: string;\n  /** Hooke's Law spring stiffness coefficient. Default: 340 */\n  stiffness?: number;\n  /** Spring damping coefficient. Default: 25 */\n  damping?: number;\n  className?: string;\n}\n\nexport function DynamicIslandToast({\n  defaultMode = \"compact\",\n  title = \"Registry Sync Active\",\n  subtitle = \"12 shadcn v2 manifests compiled in 42ms\",\n  stiffness = 340,\n  damping = 25,\n  className,\n}: DynamicIslandToastProps) {\n  const shouldReduceMotion = useReducedMotion() ?? false;\n  const [mode, setMode] = useState<IslandMode>(defaultMode);\n\n  const cycleMode = () => {\n    setMode((prev) =>\n      prev === \"compact\"\n        ? \"telemetry\"\n        : prev === \"telemetry\"\n          ? \"expanded\"\n          : \"compact\"\n    );\n  };\n\n  const springTransition = shouldReduceMotion\n    ? { duration: 0.01 }\n    : { type: \"spring\" as const, stiffness, damping };\n\n  return (\n    <div\n      className={cn(\n        \"flex min-h-[160px] w-full flex-col items-center justify-center gap-3\",\n        className\n      )}\n    >\n      <motion.div\n        layout\n        role=\"status\"\n        aria-live=\"polite\"\n        transition={springTransition}\n        onClick={() => {\n          if (mode !== \"expanded\") cycleMode();\n        }}\n        className={cn(\n          \"relative overflow-hidden border border-neutral-800 bg-black text-white shadow-xl dark:border-[#2A2A2A] dark:bg-[#0D0D0D]\",\n          mode === \"compact\" && \"cursor-pointer rounded-full px-4 py-2\",\n          mode === \"telemetry\" && \"cursor-pointer rounded-full px-5 py-2.5\",\n          mode === \"expanded\" && \"w-full max-w-sm rounded-3xl p-5\"\n        )}\n      >\n        <AnimatePresence mode=\"wait\" initial={false}>\n          {mode === \"compact\" && (\n            <motion.button\n              key=\"compact\"\n              type=\"button\"\n              onClick={(e) => {\n                e.stopPropagation();\n                setMode(\"telemetry\");\n              }}\n              initial={{ opacity: 0, scale: 0.92 }}\n              animate={{ opacity: 1, scale: 1 }}\n              exit={{ opacity: 0, scale: 0.92 }}\n              transition={{ duration: 0.14 }}\n              className=\"flex items-center gap-2.5 text-xs font-semibold focus-visible:outline-none\"\n            >\n              <span className=\"relative flex h-2 w-2\">\n                <span className=\"absolute inline-flex h-full w-full animate-ping rounded-full bg-white opacity-75\" />\n                <span className=\"relative inline-flex h-2 w-2 rounded-full bg-white\" />\n              </span>\n              <span>BoseUI Live</span>\n              <span className=\"font-mono text-[10px] text-neutral-400\">\n                120Hz\n              </span>\n            </motion.button>\n          )}\n\n          {mode === \"telemetry\" && (\n            <motion.button\n              key=\"telemetry\"\n              type=\"button\"\n              onClick={(e) => {\n                e.stopPropagation();\n                setMode(\"expanded\");\n              }}\n              initial={{ opacity: 0, scale: 0.94 }}\n              animate={{ opacity: 1, scale: 1 }}\n              exit={{ opacity: 0, scale: 0.94 }}\n              transition={{ duration: 0.15 }}\n              className=\"flex items-center gap-3 text-xs font-semibold focus-visible:outline-none\"\n            >\n              <Activity className=\"h-4 w-4 text-white\" />\n              <span>{title}</span>\n              <span className=\"rounded-full bg-white/15 px-2 py-0.5 font-mono text-[10px] text-white\">\n                99.8%\n              </span>\n            </motion.button>\n          )}\n\n          {mode === \"expanded\" && (\n            <motion.div\n              key=\"expanded\"\n              initial={{ opacity: 0, y: 4 }}\n              animate={{ opacity: 1, y: 0 }}\n              exit={{ opacity: 0, y: -4 }}\n              transition={{ duration: 0.16 }}\n              className=\"flex flex-col gap-3\"\n            >\n              <div className=\"flex items-start justify-between gap-3\">\n                <div className=\"flex items-center gap-2.5\">\n                  <div className=\"flex h-9 w-9 shrink-0 items-center justify-center rounded-2xl bg-white/10 text-white\">\n                    <Sparkles className=\"h-4 w-4\" />\n                  </div>\n                  <div>\n                    <div className=\"text-sm font-semibold text-white\">\n                      {title}\n                    </div>\n                    <div className=\"text-xs text-neutral-400\">{subtitle}</div>\n                  </div>\n                </div>\n\n                <button\n                  type=\"button\"\n                  aria-label=\"Collapse dynamic island\"\n                  onClick={(e) => {\n                    e.stopPropagation();\n                    setMode(\"compact\");\n                  }}\n                  className=\"flex h-7 w-7 items-center justify-center rounded-full bg-white/10 text-neutral-300 transition-colors hover:bg-white hover:text-black focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-white\"\n                >\n                  <X className=\"h-3.5 w-3.5\" />\n                </button>\n              </div>\n\n              <div className=\"flex items-center justify-between rounded-2xl bg-white/5 px-3.5 py-2.5 font-mono text-[11px]\">\n                <span className=\"inline-flex items-center gap-1.5 text-neutral-300\">\n                  <CheckCircle2 className=\"h-3.5 w-3.5 text-white\" />\n                  SEO Audit: 100/100\n                </span>\n                <button\n                  type=\"button\"\n                  onClick={(e) => {\n                    e.stopPropagation();\n                    setMode(\"compact\");\n                  }}\n                  className=\"rounded-lg bg-white px-2.5 py-1 text-[10px] font-bold text-black transition-opacity hover:opacity-90\"\n                >\n                  Dismiss\n                </button>\n              </div>\n            </motion.div>\n          )}\n        </AnimatePresence>\n      </motion.div>\n\n      {/* Mode Switcher Controls */}\n      <div className=\"flex items-center gap-1.5\">\n        {([\"compact\", \"telemetry\", \"expanded\"] as IslandMode[]).map((m) => (\n          <button\n            key={m}\n            type=\"button\"\n            onClick={() => setMode(m)}\n            className={cn(\n              \"rounded-full border px-2.5 py-1 font-mono text-[10px] uppercase transition-colors\",\n              mode === m\n                ? \"border-black bg-black text-white dark:border-white dark:bg-white dark:text-black\"\n                : \"border-neutral-200 bg-transparent text-neutral-500 hover:border-neutral-400 dark:border-[#222222]\"\n            )}\n          >\n            {m}\n          </button>\n        ))}\n      </div>\n    </div>\n  );\n}\n\nexport default DynamicIslandToast;\n",
          "type": "registry:ui",
          "target": "components/ui/dynamic-island-toast.tsx"
        },
        {
          "path": "lib/utils.ts",
          "content": "import { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...inputs: ClassValue[]) {\n  return twMerge(clsx(inputs));\n}\n\nexport async function copyToClipboard(text: string): Promise<boolean> {\n  if (typeof window === \"undefined\") return false;\n\n  try {\n    if (navigator.clipboard && window.isSecureContext) {\n      await navigator.clipboard.writeText(text);\n      return true;\n    }\n\n    const textArea = document.createElement(\"textarea\");\n    textArea.value = text;\n    textArea.style.position = \"fixed\";\n    textArea.style.left = \"-999999px\";\n    textArea.style.top = \"-999999px\";\n    document.body.appendChild(textArea);\n    textArea.focus();\n    textArea.select();\n    const succeeded = document.execCommand(\"copy\");\n    textArea.remove();\n    return succeeded;\n  } catch {\n    return false;\n  }\n}\n",
          "type": "registry:lib",
          "target": "lib/utils.ts"
        }
      ]
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "elastic-dock",
      "type": "registry:ui",
      "title": "Elastic Dock",
      "author": "Rishabh Bose <https://theb0se.vercel.app/>",
      "description": "Physics-coupled magnification dock with continuous Euclidean pointer falloff, spring-tethered icon scaling, and roving keyboard navigation.",
      "dependencies": [
        "framer-motion",
        "lucide-react",
        "clsx",
        "tailwind-merge"
      ],
      "files": [
        {
          "path": "components/ui/elastic-dock.tsx",
          "content": "\"use client\";\n\nimport React, { useRef, useState } from \"react\";\nimport {\n  motion,\n  useMotionValue,\n  useSpring,\n  useTransform,\n  useReducedMotion,\n  type MotionValue,\n} from \"framer-motion\";\nimport {\n  Home,\n  Terminal,\n  Sparkles,\n  Layers,\n  Settings,\n  Compass,\n} from \"lucide-react\";\nimport { cn } from \"@/lib/utils\";\n\nexport interface ElasticDockItem {\n  id: string;\n  label: string;\n  icon: React.ReactNode;\n  badge?: string | number;\n  onClick?: () => void;\n}\n\nexport interface ElasticDockProps {\n  /** Array of dock items to render. Defaults to a 6-item studio toolbar. */\n  items?: ElasticDockItem[];\n  /** Resting icon button size in pixels. Default: 46 */\n  baseSize?: number;\n  /** Peak magnified icon button size in pixels on hover. Default: 72 */\n  magnifiedSize?: number;\n  /** Pointer proximity radius in pixels affecting neighboring items. Default: 140 */\n  distance?: number;\n  /** Hooke's Law spring stiffness coefficient. Default: 320 */\n  stiffness?: number;\n  /** Spring damping coefficient. Default: 22 */\n  damping?: number;\n  /** Controlled or initial active item id */\n  defaultActiveId?: string;\n  /** Callback fired when an item is selected */\n  onSelect?: (id: string) => void;\n  className?: string;\n}\n\nconst DEFAULT_ITEMS: ElasticDockItem[] = [\n  { id: \"overview\", label: \"Overview\", icon: <Home className=\"h-5 w-5\" /> },\n  { id: \"explore\", label: \"Explore\", icon: <Compass className=\"h-5 w-5\" /> },\n  {\n    id: \"primitives\",\n    label: \"Primitives\",\n    icon: <Layers className=\"h-5 w-5\" />,\n    badge: \"12\",\n  },\n  { id: \"kinetic\", label: \"Kinetic Lab\", icon: <Sparkles className=\"h-5 w-5\" /> },\n  { id: \"cli\", label: \"CLI Registry\", icon: <Terminal className=\"h-5 w-5\" /> },\n  { id: \"settings\", label: \"Settings\", icon: <Settings className=\"h-5 w-5\" /> },\n];\n\ninterface DockIconButtonProps {\n  item: ElasticDockItem;\n  isActive: boolean;\n  mouseX: MotionValue<number>;\n  baseSize: number;\n  magnifiedSize: number;\n  distance: number;\n  stiffness: number;\n  damping: number;\n  shouldReduceMotion: boolean;\n  onSelect: () => void;\n  onKeyNav: (e: React.KeyboardEvent<HTMLButtonElement>) => void;\n  buttonRef: (el: HTMLButtonElement | null) => void;\n}\n\nfunction DockIconButton({\n  item,\n  isActive,\n  mouseX,\n  baseSize,\n  magnifiedSize,\n  distance,\n  stiffness,\n  damping,\n  shouldReduceMotion,\n  onSelect,\n  onKeyNav,\n  buttonRef,\n}: DockIconButtonProps) {\n  const localRef = useRef<HTMLButtonElement | null>(null);\n  const [isHovered, setIsHovered] = useState(false);\n  const [isFocused, setIsFocused] = useState(false);\n\n  const distanceFromPointer = useTransform(mouseX, (val) => {\n    const bounds = localRef.current?.getBoundingClientRect();\n    if (!bounds || val === -Infinity) return Infinity;\n    return val - (bounds.x + bounds.width / 2);\n  });\n\n  const targetSize = useTransform(\n    distanceFromPointer,\n    [-distance, 0, distance],\n    [baseSize, magnifiedSize, baseSize]\n  );\n\n  const targetLift = useTransform(\n    distanceFromPointer,\n    [-distance, 0, distance],\n    [0, -8, 0]\n  );\n\n  const springSize = useSpring(targetSize, {\n    stiffness,\n    damping,\n    mass: 0.5,\n  });\n\n  const springLift = useSpring(targetLift, {\n    stiffness,\n    damping,\n    mass: 0.5,\n  });\n\n  const showTooltip = isHovered || isFocused;\n\n  return (\n    <div className=\"relative flex flex-col items-center\">\n      {/* Floating HUD Tooltip */}\n      <motion.div\n        initial={false}\n        animate={{\n          opacity: showTooltip ? 1 : 0,\n          y: showTooltip ? -8 : 2,\n          scale: showTooltip ? 1 : 0.92,\n        }}\n        transition={{ duration: 0.14, ease: \"easeOut\" }}\n        aria-hidden=\"true\"\n        className=\"pointer-events-none absolute -top-9 z-20 whitespace-nowrap rounded-md border border-neutral-200 bg-white/95 px-2.5 py-1 text-[11px] font-medium tracking-tight text-black shadow-sm backdrop-blur-md dark:border-[#262626] dark:bg-[#111111]/95 dark:text-white\"\n      >\n        {item.label}\n      </motion.div>\n\n      <motion.button\n        ref={(el) => {\n          localRef.current = el;\n          buttonRef(el);\n        }}\n        type=\"button\"\n        aria-label={item.label}\n        aria-current={isActive ? \"page\" : undefined}\n        onClick={() => {\n          onSelect();\n          item.onClick?.();\n        }}\n        onKeyDown={onKeyNav}\n        onMouseEnter={() => setIsHovered(true)}\n        onMouseLeave={() => setIsHovered(false)}\n        onFocus={() => setIsFocused(true)}\n        onBlur={() => setIsFocused(false)}\n        whileTap={shouldReduceMotion ? undefined : { scale: 0.9 }}\n        style={{\n          width: shouldReduceMotion ? baseSize : springSize,\n          height: shouldReduceMotion ? baseSize : springSize,\n          y: shouldReduceMotion ? 0 : springLift,\n        }}\n        className={cn(\n          \"group relative flex items-center justify-center rounded-2xl border transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-black dark:focus-visible:ring-white\",\n          isActive\n            ? \"border-black bg-black text-white dark:border-white dark:bg-white dark:text-black\"\n            : \"border-neutral-200/90 bg-neutral-50/90 text-neutral-700 hover:border-neutral-400 hover:bg-white hover:text-black dark:border-[#222222] dark:bg-[#121212] dark:text-neutral-300 dark:hover:border-[#383838] dark:hover:bg-[#1A1A1A] dark:hover:text-white\"\n        )}\n      >\n        <span className=\"pointer-events-none flex items-center justify-center\">\n          {item.icon}\n        </span>\n\n        {item.badge !== undefined && (\n          <span className=\"pointer-events-none absolute -right-1 -top-1 flex h-4 min-w-4 items-center justify-center rounded-full border border-white bg-black px-1 text-[9px] font-bold text-white dark:border-[#0A0A0A] dark:bg-white dark:text-black\">\n            {item.badge}\n          </span>\n        )}\n      </motion.button>\n\n      {/* Active spring indicator dot */}\n      <div className=\"mt-1.5 flex h-1.5 items-center justify-center\">\n        {isActive && (\n          <motion.span\n            layoutId=\"elastic-dock-active-dot\"\n            transition={\n              shouldReduceMotion\n                ? { duration: 0 }\n                : { type: \"spring\", stiffness: 380, damping: 26 }\n            }\n            className=\"h-1.5 w-1.5 rounded-full bg-black dark:bg-white\"\n          />\n        )}\n      </div>\n    </div>\n  );\n}\n\nexport function ElasticDock({\n  items = DEFAULT_ITEMS,\n  baseSize = 46,\n  magnifiedSize = 68,\n  distance = 140,\n  stiffness = 320,\n  damping = 22,\n  defaultActiveId = \"kinetic\",\n  onSelect,\n  className,\n}: ElasticDockProps) {\n  const shouldReduceMotion = useReducedMotion() ?? false;\n  const mouseX = useMotionValue(-Infinity);\n  const [activeId, setActiveId] = useState<string>(\n    defaultActiveId || items[0]?.id || \"\"\n  );\n  const buttonRefs = useRef<Array<HTMLButtonElement | null>>([]);\n\n  const handleKeyDown = (\n    index: number,\n    e: React.KeyboardEvent<HTMLButtonElement>\n  ) => {\n    if (e.key === \"ArrowRight\") {\n      e.preventDefault();\n      const next = (index + 1) % items.length;\n      buttonRefs.current[next]?.focus();\n    } else if (e.key === \"ArrowLeft\") {\n      e.preventDefault();\n      const prev = (index - 1 + items.length) % items.length;\n      buttonRefs.current[prev]?.focus();\n    } else if (e.key === \"Home\") {\n      e.preventDefault();\n      buttonRefs.current[0]?.focus();\n    } else if (e.key === \"End\") {\n      e.preventDefault();\n      buttonRefs.current[items.length - 1]?.focus();\n    }\n  };\n\n  return (\n    <motion.div\n      role=\"toolbar\"\n      aria-label=\"Application dock navigation\"\n      onMouseMove={(e) => {\n        if (!shouldReduceMotion) {\n          mouseX.set(e.clientX);\n        }\n      }}\n      onMouseLeave={() => mouseX.set(-Infinity)}\n      className={cn(\n        \"inline-flex items-end gap-2.5 rounded-3xl border border-neutral-200/90 bg-white/85 px-4 pb-2 pt-3 shadow-sm backdrop-blur-xl dark:border-[#222222] dark:bg-[#0A0A0A]/85\",\n        className\n      )}\n    >\n      {items.map((item, idx) => (\n        <DockIconButton\n          key={item.id}\n          item={item}\n          isActive={activeId === item.id}\n          mouseX={mouseX}\n          baseSize={baseSize}\n          magnifiedSize={magnifiedSize}\n          distance={distance}\n          stiffness={stiffness}\n          damping={damping}\n          shouldReduceMotion={shouldReduceMotion}\n          onSelect={() => {\n            setActiveId(item.id);\n            onSelect?.(item.id);\n          }}\n          onKeyNav={(e) => handleKeyDown(idx, e)}\n          buttonRef={(el) => {\n            buttonRefs.current[idx] = el;\n          }}\n        />\n      ))}\n    </motion.div>\n  );\n}\n\nexport default ElasticDock;\n",
          "type": "registry:ui",
          "target": "components/ui/elastic-dock.tsx"
        },
        {
          "path": "lib/utils.ts",
          "content": "import { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...inputs: ClassValue[]) {\n  return twMerge(clsx(inputs));\n}\n\nexport async function copyToClipboard(text: string): Promise<boolean> {\n  if (typeof window === \"undefined\") return false;\n\n  try {\n    if (navigator.clipboard && window.isSecureContext) {\n      await navigator.clipboard.writeText(text);\n      return true;\n    }\n\n    const textArea = document.createElement(\"textarea\");\n    textArea.value = text;\n    textArea.style.position = \"fixed\";\n    textArea.style.left = \"-999999px\";\n    textArea.style.top = \"-999999px\";\n    document.body.appendChild(textArea);\n    textArea.focus();\n    textArea.select();\n    const succeeded = document.execCommand(\"copy\");\n    textArea.remove();\n    return succeeded;\n  } catch {\n    return false;\n  }\n}\n",
          "type": "registry:lib",
          "target": "lib/utils.ts"
        }
      ]
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "elastic-snap-sortable",
      "type": "registry:ui",
      "title": "Elastic Snap Sortable",
      "author": "Rishabh Bose <https://theb0se.vercel.app/>",
      "description": "Reorderable priority queue where list items swap positions with Hooke's Law layout spring projection and full keyboard arrow-key control.",
      "dependencies": [
        "framer-motion",
        "lucide-react",
        "clsx",
        "tailwind-merge"
      ],
      "files": [
        {
          "path": "components/ui/elastic-snap-sortable.tsx",
          "content": "\"use client\";\n\nimport React, { useState } from \"react\";\nimport { motion, useReducedMotion } from \"framer-motion\";\nimport { GripVertical, ArrowUp, ArrowDown } from \"lucide-react\";\nimport { cn } from \"@/lib/utils\";\n\nexport interface SortableTaskItem {\n  id: string;\n  title: string;\n  tag: string;\n}\n\nexport interface ElasticSnapSortableProps {\n  /** Initial array of sortable items. */\n  items?: SortableTaskItem[];\n  /** Spring stiffness coefficient for layout reordering. Default: 380 */\n  stiffness?: number;\n  /** Spring damping coefficient for layout reordering. Default: 26 */\n  damping?: number;\n  /** Callback fired when item order changes */\n  onReorder?: (items: SortableTaskItem[]) => void;\n  className?: string;\n}\n\nconst DEFAULT_ITEMS: SortableTaskItem[] = [\n  { id: \"task-1\", title: \"GPU Radial Mask Compositor\", tag: \"P0\" },\n  { id: \"task-2\", title: \"Hooke's Law Velocity Solver\", tag: \"P1\" },\n  { id: \"task-3\", title: \"Shadcn v2 Registry Manifests\", tag: \"P2\" },\n  { id: \"task-4\", title: \"WAI-ARIA Reduced Motion Audit\", tag: \"P3\" },\n];\n\nexport function ElasticSnapSortable({\n  items: initialItems = DEFAULT_ITEMS,\n  stiffness = 380,\n  damping = 26,\n  onReorder,\n  className,\n}: ElasticSnapSortableProps) {\n  const shouldReduceMotion = useReducedMotion() ?? false;\n  const [list, setList] = useState<SortableTaskItem[]>(initialItems);\n  const [activeId, setActiveId] = useState<string | null>(null);\n\n  const moveItem = (index: number, direction: -1 | 1) => {\n    const targetIndex = index + direction;\n    if (targetIndex < 0 || targetIndex >= list.length) return;\n    const next = [...list];\n    const [moved] = next.splice(index, 1);\n    next.splice(targetIndex, 0, moved!);\n    setList(next);\n    setActiveId(moved!.id);\n    onReorder?.(next);\n  };\n\n  return (\n    <div\n      role=\"list\"\n      aria-label=\"Sortable priority queue\"\n      className={cn(\n        \"flex w-full max-w-sm flex-col gap-2 rounded-2xl border border-neutral-200 bg-white p-4 dark:border-[#222222] dark:bg-[#0A0A0A]\",\n        className\n      )}\n    >\n      <div className=\"mb-1 flex items-center justify-between px-1 text-[11px] font-semibold uppercase tracking-wider text-neutral-400\">\n        <span>Priority Queue</span>\n        <span className=\"font-mono\">Click arrows or use ↑/↓ keys</span>\n      </div>\n\n      {list.map((item, idx) => {\n        const isActive = activeId === item.id;\n\n        return (\n          <motion.div\n            key={item.id}\n            layout\n            role=\"listitem\"\n            tabIndex={0}\n            aria-label={`${item.title}, priority ${item.tag}, position ${idx + 1} of ${list.length}. Use Up and Down arrow keys to reorder.`}\n            onFocus={() => setActiveId(item.id)}\n            onBlur={() => setActiveId(null)}\n            onKeyDown={(e) => {\n              if (e.key === \"ArrowUp\") {\n                e.preventDefault();\n                moveItem(idx, -1);\n              } else if (e.key === \"ArrowDown\") {\n                e.preventDefault();\n                moveItem(idx, 1);\n              }\n            }}\n            transition={\n              shouldReduceMotion\n                ? { duration: 0 }\n                : { type: \"spring\", stiffness, damping }\n            }\n            className={cn(\n              \"group flex items-center justify-between gap-3 rounded-xl border px-3.5 py-2.5 transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-black dark:focus-visible:ring-white\",\n              isActive\n                ? \"border-black bg-neutral-50 shadow-sm dark:border-white dark:bg-[#141414]\"\n                : \"border-neutral-200 bg-white hover:border-neutral-400 dark:border-[#222222] dark:bg-[#0D0D0D] dark:hover:border-[#383838]\"\n            )}\n          >\n            <div className=\"flex items-center gap-2.5\">\n              <GripVertical\n                aria-hidden=\"true\"\n                className=\"h-4 w-4 shrink-0 text-neutral-400\"\n              />\n              <span className=\"rounded bg-neutral-100 px-1.5 py-0.5 font-mono text-[10px] font-bold text-black dark:bg-[#1E1E1E] dark:text-white\">\n                {item.tag}\n              </span>\n              <span className=\"text-xs font-semibold text-black dark:text-white\">\n                {item.title}\n              </span>\n            </div>\n\n            <div className=\"flex items-center gap-1\">\n              <button\n                type=\"button\"\n                tabIndex={-1}\n                disabled={idx === 0}\n                aria-label={`Move ${item.title} up`}\n                onClick={() => moveItem(idx, -1)}\n                className=\"flex h-6 w-6 items-center justify-center rounded-md border border-neutral-200 text-neutral-500 transition-colors hover:border-black hover:text-black disabled:opacity-25 dark:border-[#262626] dark:hover:border-white dark:hover:text-white\"\n              >\n                <ArrowUp className=\"h-3 w-3\" />\n              </button>\n              <button\n                type=\"button\"\n                tabIndex={-1}\n                disabled={idx === list.length - 1}\n                aria-label={`Move ${item.title} down`}\n                onClick={() => moveItem(idx, 1)}\n                className=\"flex h-6 w-6 items-center justify-center rounded-md border border-neutral-200 text-neutral-500 transition-colors hover:border-black hover:text-black disabled:opacity-25 dark:border-[#262626] dark:hover:border-white dark:hover:text-white\"\n              >\n                <ArrowDown className=\"h-3 w-3\" />\n              </button>\n            </div>\n          </motion.div>\n        );\n      })}\n    </div>\n  );\n}\n\nexport default ElasticSnapSortable;\n",
          "type": "registry:ui",
          "target": "components/ui/elastic-snap-sortable.tsx"
        },
        {
          "path": "lib/utils.ts",
          "content": "import { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...inputs: ClassValue[]) {\n  return twMerge(clsx(inputs));\n}\n\nexport async function copyToClipboard(text: string): Promise<boolean> {\n  if (typeof window === \"undefined\") return false;\n\n  try {\n    if (navigator.clipboard && window.isSecureContext) {\n      await navigator.clipboard.writeText(text);\n      return true;\n    }\n\n    const textArea = document.createElement(\"textarea\");\n    textArea.value = text;\n    textArea.style.position = \"fixed\";\n    textArea.style.left = \"-999999px\";\n    textArea.style.top = \"-999999px\";\n    document.body.appendChild(textArea);\n    textArea.focus();\n    textArea.select();\n    const succeeded = document.execCommand(\"copy\");\n    textArea.remove();\n    return succeeded;\n  } catch {\n    return false;\n  }\n}\n",
          "type": "registry:lib",
          "target": "lib/utils.ts"
        }
      ]
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "elastic-tag-input",
      "type": "registry:ui",
      "title": "Elastic Tag Input",
      "author": "Rishabh Bose <https://theb0se.vercel.app/>",
      "description": "Tokenized multi-tag input with Hooke's Law pill pop-in, FLIP layout reflow, and a two-step Backspace warning wiggle before deletion.",
      "dependencies": [
        "framer-motion",
        "lucide-react",
        "clsx",
        "tailwind-merge"
      ],
      "files": [
        {
          "path": "components/ui/elastic-tag-input.tsx",
          "content": "\"use client\";\n\nimport React, { useState } from \"react\";\nimport { AnimatePresence, motion, useReducedMotion } from \"framer-motion\";\nimport { Plus, X, Tag } from \"lucide-react\";\nimport { cn } from \"@/lib/utils\";\n\nexport interface ElasticTagInputProps {\n  /** Initial array of tag strings. */\n  defaultTags?: string[];\n  /** Maximum number of tags allowed. Default: 8 */\n  maxTags?: number;\n  /** Input placeholder text. Default: \"Add tag & press Enter...\" */\n  placeholder?: string;\n  /** Spring stiffness coefficient for tag pill pop-in and reflow. Default: 380 */\n  stiffness?: number;\n  /** Spring damping coefficient for tag pill pop-in and reflow. Default: 24 */\n  damping?: number;\n  /** Callback fired when tag list changes */\n  onChange?: (tags: string[]) => void;\n  className?: string;\n}\n\nconst DEFAULT_TAGS = [\"framer-motion\", \"spring-physics\", \"shadcn-v2\"];\n\nexport function ElasticTagInput({\n  defaultTags = DEFAULT_TAGS,\n  maxTags = 8,\n  placeholder = \"Add tag & press Enter...\",\n  stiffness = 380,\n  damping = 24,\n  onChange,\n  className,\n}: ElasticTagInputProps) {\n  const shouldReduceMotion = useReducedMotion() ?? false;\n  const [tags, setTags] = useState<string[]>(defaultTags);\n  const [inputValue, setInputValue] = useState(\"\");\n  const [pendingDeleteLast, setPendingDeleteLast] = useState(false);\n\n  const commitTags = (next: string[]) => {\n    setTags(next);\n    onChange?.(next);\n  };\n\n  const addTag = (raw: string) => {\n    const cleaned = raw.trim().toLowerCase().replace(/\\s+/g, \"-\");\n    if (!cleaned || tags.includes(cleaned) || tags.length >= maxTags) return;\n    commitTags([...tags, cleaned]);\n    setInputValue(\"\");\n    setPendingDeleteLast(false);\n  };\n\n  const removeTag = (target: string) => {\n    commitTags(tags.filter((t) => t !== target));\n    setPendingDeleteLast(false);\n  };\n\n  const handleKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {\n    if (e.key === \"Enter\" || e.key === \",\") {\n      e.preventDefault();\n      addTag(inputValue);\n    } else if (e.key === \"Backspace\" && inputValue === \"\" && tags.length > 0) {\n      if (!pendingDeleteLast) {\n        setPendingDeleteLast(true);\n      } else {\n        const last = tags[tags.length - 1];\n        if (last) removeTag(last);\n      }\n    } else {\n      setPendingDeleteLast(false);\n    }\n  };\n\n  return (\n    <div\n      className={cn(\n        \"w-full max-w-md rounded-2xl border border-neutral-200 bg-white p-4 shadow-sm dark:border-[#222222] dark:bg-[#0A0A0A]\",\n        className\n      )}\n    >\n      <div className=\"mb-2.5 flex items-center justify-between text-xs\">\n        <span className=\"inline-flex items-center gap-1.5 font-semibold text-black dark:text-white\">\n          <Tag className=\"h-3.5 w-3.5\" />\n          <span>Registry Keywords</span>\n        </span>\n        <span className=\"font-mono text-[10px] text-neutral-400\">\n          {tags.length}/{maxTags} tags\n        </span>\n      </div>\n\n      <div className=\"flex flex-wrap items-center gap-1.5 rounded-xl border border-neutral-200 bg-neutral-50/70 p-2 focus-within:border-black dark:border-[#262626] dark:bg-[#121212] dark:focus-within:border-white\">\n        <AnimatePresence mode=\"popLayout\" initial={false}>\n          {tags.map((tag, idx) => {\n            const isWarned =\n              pendingDeleteLast && idx === tags.length - 1;\n\n            return (\n              <motion.span\n                key={tag}\n                layout\n                initial={\n                  shouldReduceMotion\n                    ? { opacity: 1 }\n                    : { scale: 0.6, opacity: 0 }\n                }\n                animate={{\n                  scale: 1,\n                  opacity: 1,\n                  x:\n                    isWarned && !shouldReduceMotion\n                      ? [0, -4, 4, -3, 3, 0]\n                      : 0,\n                }}\n                exit={\n                  shouldReduceMotion\n                    ? { opacity: 0 }\n                    : { scale: 0.6, opacity: 0 }\n                }\n                transition={{ type: \"spring\", stiffness, damping }}\n                className={cn(\n                  \"inline-flex items-center gap-1 rounded-lg border px-2.5 py-1 font-mono text-xs font-medium transition-colors\",\n                  isWarned\n                    ? \"border-black bg-black text-white dark:border-white dark:bg-white dark:text-black\"\n                    : \"border-neutral-200 bg-white text-black dark:border-[#2A2A2A] dark:bg-[#1B1B1B] dark:text-white\"\n                )}\n              >\n                <span>#{tag}</span>\n                <button\n                  type=\"button\"\n                  aria-label={`Remove tag ${tag}`}\n                  onClick={() => removeTag(tag)}\n                  className=\"rounded p-0.5 opacity-60 transition-opacity hover:opacity-100 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-current\"\n                >\n                  <X className=\"h-3 w-3\" />\n                </button>\n              </motion.span>\n            );\n          })}\n        </AnimatePresence>\n\n        <div className=\"flex min-w-[140px] flex-1 items-center gap-1\">\n          <input\n            type=\"text\"\n            value={inputValue}\n            disabled={tags.length >= maxTags}\n            placeholder={\n              tags.length >= maxTags ? \"Max tags reached\" : placeholder\n            }\n            aria-label=\"Add keyword tag\"\n            onChange={(e) => {\n              setInputValue(e.target.value);\n              setPendingDeleteLast(false);\n            }}\n            onKeyDown={handleKeyDown}\n            className=\"w-full bg-transparent px-1.5 py-1 text-xs text-black placeholder:text-neutral-400 focus:outline-none dark:text-white\"\n          />\n          {inputValue.trim() && (\n            <button\n              type=\"button\"\n              aria-label=\"Add current tag\"\n              onClick={() => addTag(inputValue)}\n              className=\"flex h-6 w-6 shrink-0 items-center justify-center rounded-md bg-black text-white dark:bg-white dark:text-black\"\n            >\n              <Plus className=\"h-3 w-3\" />\n            </button>\n          )}\n        </div>\n      </div>\n\n      <div className=\"mt-2 text-[10px] text-neutral-400\">\n        Press Enter to add • Press Backspace twice to confirm removal\n      </div>\n    </div>\n  );\n}\n\nexport default ElasticTagInput;\n",
          "type": "registry:ui",
          "target": "components/ui/elastic-tag-input.tsx"
        },
        {
          "path": "lib/utils.ts",
          "content": "import { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...inputs: ClassValue[]) {\n  return twMerge(clsx(inputs));\n}\n\nexport async function copyToClipboard(text: string): Promise<boolean> {\n  if (typeof window === \"undefined\") return false;\n\n  try {\n    if (navigator.clipboard && window.isSecureContext) {\n      await navigator.clipboard.writeText(text);\n      return true;\n    }\n\n    const textArea = document.createElement(\"textarea\");\n    textArea.value = text;\n    textArea.style.position = \"fixed\";\n    textArea.style.left = \"-999999px\";\n    textArea.style.top = \"-999999px\";\n    document.body.appendChild(textArea);\n    textArea.focus();\n    textArea.select();\n    const succeeded = document.execCommand(\"copy\");\n    textArea.remove();\n    return succeeded;\n  } catch {\n    return false;\n  }\n}\n",
          "type": "registry:lib",
          "target": "lib/utils.ts"
        }
      ]
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "elastic-wave-text",
      "type": "registry:ui",
      "title": "Elastic Wave Text",
      "author": "Rishabh Bose <https://theb0se.vercel.app/>",
      "description": "Plucked-string kinetic typography that propagates a damped transverse wave across every character on hover or click.",
      "dependencies": [
        "framer-motion",
        "lucide-react",
        "clsx",
        "tailwind-merge"
      ],
      "files": [
        {
          "path": "components/ui/elastic-wave-text.tsx",
          "content": "\"use client\";\n\nimport React, { useState } from \"react\";\nimport { motion, useReducedMotion } from \"framer-motion\";\nimport { Waves } from \"lucide-react\";\nimport { cn } from \"@/lib/utils\";\n\nexport interface ElasticWaveTextProps {\n  /** Text string to ripple across. Default: \"Harmonic Transverse Wave\" */\n  text?: string;\n  /** Peak vertical wave amplitude in pixels. Default: -14 */\n  amplitude?: number;\n  /** Hooke's Law spring stiffness coefficient. Default: 420 */\n  stiffness?: number;\n  /** Spring damping coefficient. Default: 14 */\n  damping?: number;\n  className?: string;\n}\n\nexport function ElasticWaveText({\n  text = \"Harmonic Transverse Wave\",\n  amplitude = -14,\n  stiffness = 420,\n  damping = 14,\n  className,\n}: ElasticWaveTextProps) {\n  const shouldReduceMotion = useReducedMotion() ?? false;\n  const [wavePulse, setWavePulse] = useState(0);\n\n  const triggerWave = () => {\n    if (!shouldReduceMotion) {\n      setWavePulse((p) => p + 1);\n    }\n  };\n\n  const chars = text.split(\"\");\n\n  return (\n    <button\n      type=\"button\"\n      onClick={triggerWave}\n      onMouseEnter={triggerWave}\n      className={cn(\n        \"group inline-flex flex-col items-center gap-3 rounded-2xl border border-neutral-200 bg-white px-7 py-6 text-center transition-colors hover:border-black focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-black dark:border-[#222222] dark:bg-[#0A0A0A] dark:hover:border-white dark:focus-visible:ring-white\",\n        className\n      )}\n    >\n      <span className=\"sr-only\">{text}</span>\n\n      <div\n        aria-hidden=\"true\"\n        className=\"flex flex-wrap items-center justify-center text-xl font-bold tracking-tight text-black sm:text-2xl dark:text-white\"\n      >\n        {chars.map((char, idx) => {\n          if (char === \" \") {\n            return (\n              <span key={idx} className=\"inline-block w-[0.32em]\">\n                &nbsp;\n              </span>\n            );\n          }\n\n          return (\n            <motion.span\n              key={`${wavePulse}-${idx}`}\n              initial={{ y: 0 }}\n              animate={\n                wavePulse > 0 && !shouldReduceMotion\n                  ? { y: [0, amplitude, -amplitude * 0.45, 0] }\n                  : { y: 0 }\n              }\n              transition={{\n                duration: 0.52,\n                delay: idx * 0.024,\n                ease: \"easeInOut\",\n              }}\n              className=\"inline-block select-none\"\n            >\n              {char}\n            </motion.span>\n          );\n        })}\n      </div>\n\n      <span className=\"inline-flex items-center gap-1.5 text-[11px] text-neutral-400\">\n        <Waves className=\"h-3.5 w-3.5\" />\n        <span>Hover or click to pluck transverse glyph wave</span>\n      </span>\n    </button>\n  );\n}\n\nexport default ElasticWaveText;\n",
          "type": "registry:ui",
          "target": "components/ui/elastic-wave-text.tsx"
        },
        {
          "path": "lib/utils.ts",
          "content": "import { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...inputs: ClassValue[]) {\n  return twMerge(clsx(inputs));\n}\n\nexport async function copyToClipboard(text: string): Promise<boolean> {\n  if (typeof window === \"undefined\") return false;\n\n  try {\n    if (navigator.clipboard && window.isSecureContext) {\n      await navigator.clipboard.writeText(text);\n      return true;\n    }\n\n    const textArea = document.createElement(\"textarea\");\n    textArea.value = text;\n    textArea.style.position = \"fixed\";\n    textArea.style.left = \"-999999px\";\n    textArea.style.top = \"-999999px\";\n    document.body.appendChild(textArea);\n    textArea.focus();\n    textArea.select();\n    const succeeded = document.execCommand(\"copy\");\n    textArea.remove();\n    return succeeded;\n  } catch {\n    return false;\n  }\n}\n",
          "type": "registry:lib",
          "target": "lib/utils.ts"
        }
      ]
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "expandable-bento-card",
      "type": "registry:ui",
      "title": "Expandable Bento Card",
      "author": "Rishabh Bose <https://theb0se.vercel.app/>",
      "description": "Interactive bento surface that expands inline with Hooke's Law spring height projection to reveal secondary diagnostic modules.",
      "dependencies": [
        "framer-motion",
        "lucide-react",
        "clsx",
        "tailwind-merge"
      ],
      "files": [
        {
          "path": "components/ui/expandable-bento-card.tsx",
          "content": "\"use client\";\n\nimport React, { useState } from \"react\";\nimport { AnimatePresence, motion, useReducedMotion } from \"framer-motion\";\nimport { ChevronDown, Cpu, Gauge, Sparkles } from \"lucide-react\";\nimport { cn } from \"@/lib/utils\";\n\nexport interface ExpandableBentoCardProps {\n  /** Card header badge text. Default: \"RUNTIME_TELEMETRY\" */\n  badge?: string;\n  /** Primary card title. Default: \"GPU Compositor Pipeline\" */\n  title?: string;\n  /** Short summary shown in both states. */\n  summary?: string;\n  /** Initial expanded state. Default: false */\n  defaultExpanded?: boolean;\n  /** Hooke's Law spring stiffness coefficient. Default: 320 */\n  stiffness?: number;\n  /** Spring damping coefficient. Default: 26 */\n  damping?: number;\n  className?: string;\n}\n\nexport function ExpandableBentoCard({\n  badge = \"RUNTIME_TELEMETRY\",\n  title = \"GPU Compositor Pipeline\",\n  summary = \"Click to expand live sub-pixel spring diagnostics and frame budget metrics.\",\n  defaultExpanded = false,\n  stiffness = 320,\n  damping = 26,\n  className,\n}: ExpandableBentoCardProps) {\n  const shouldReduceMotion = useReducedMotion() ?? false;\n  const [expanded, setExpanded] = useState(defaultExpanded);\n\n  return (\n    <motion.div\n      layout\n      transition={\n        shouldReduceMotion\n          ? { duration: 0.01 }\n          : { type: \"spring\", stiffness, damping }\n      }\n      className={cn(\n        \"w-full max-w-sm overflow-hidden rounded-3xl border border-neutral-200 bg-white p-5 shadow-sm transition-colors hover:border-neutral-400 dark:border-[#222222] dark:bg-[#0A0A0A] dark:hover:border-[#383838]\",\n        className\n      )}\n    >\n      <button\n        type=\"button\"\n        aria-expanded={expanded}\n        onClick={() => setExpanded((prev) => !prev)}\n        className=\"flex w-full items-start justify-between gap-3 text-left focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-black dark:focus-visible:ring-white\"\n      >\n        <div>\n          <span className=\"inline-flex items-center gap-1.5 font-mono text-[10px] font-semibold uppercase tracking-wider text-neutral-400\">\n            <Sparkles className=\"h-3 w-3 text-black dark:text-white\" />\n            {badge}\n          </span>\n          <h3 className=\"mt-1 text-base font-semibold text-black dark:text-white\">\n            {title}\n          </h3>\n          <p className=\"mt-1 text-xs leading-relaxed text-neutral-500 dark:text-neutral-400\">\n            {summary}\n          </p>\n        </div>\n\n        <motion.span\n          animate={{ rotate: expanded ? 180 : 0 }}\n          transition={\n            shouldReduceMotion\n              ? { duration: 0 }\n              : { type: \"spring\", stiffness: 360, damping: 24 }\n          }\n          className=\"mt-1 flex h-8 w-8 shrink-0 items-center justify-center rounded-full border border-neutral-200 bg-neutral-50 text-black dark:border-[#262626] dark:bg-[#141414] dark:text-white\"\n        >\n          <ChevronDown className=\"h-4 w-4\" />\n        </motion.span>\n      </button>\n\n      <AnimatePresence initial={false}>\n        {expanded && (\n          <motion.div\n            key=\"expanded-content\"\n            initial={{ opacity: 0, height: 0 }}\n            animate={{ opacity: 1, height: \"auto\" }}\n            exit={{ opacity: 0, height: 0 }}\n            transition={\n              shouldReduceMotion\n                ? { duration: 0.01 }\n                : { type: \"spring\", stiffness, damping }\n            }\n            className=\"overflow-hidden\"\n          >\n            <div className=\"mt-4 grid grid-cols-2 gap-2.5 border-t border-neutral-200 pt-4 dark:border-[#1F1F1F]\">\n              <div className=\"rounded-2xl border border-neutral-200/80 bg-neutral-50 p-3 dark:border-[#222222] dark:bg-[#121212]\">\n                <div className=\"flex items-center gap-1.5 text-[10px] font-semibold uppercase text-neutral-400\">\n                  <Gauge className=\"h-3 w-3\" />\n                  Frame Budget\n                </div>\n                <div className=\"mt-1 font-mono text-sm font-bold text-black dark:text-white\">\n                  0.42 ms\n                </div>\n                <div className=\"text-[10px] text-neutral-500\">\n                  120fps locked\n                </div>\n              </div>\n\n              <div className=\"rounded-2xl border border-neutral-200/80 bg-neutral-50 p-3 dark:border-[#222222] dark:bg-[#121212]\">\n                <div className=\"flex items-center gap-1.5 text-[10px] font-semibold uppercase text-neutral-400\">\n                  <Cpu className=\"h-3 w-3\" />\n                  Re-Renders\n                </div>\n                <div className=\"mt-1 font-mono text-sm font-bold text-black dark:text-white\">\n                  0 / sec\n                </div>\n                <div className=\"text-[10px] text-neutral-500\">\n                  MotionValue direct\n                </div>\n              </div>\n            </div>\n          </motion.div>\n        )}\n      </AnimatePresence>\n    </motion.div>\n  );\n}\n\nexport default ExpandableBentoCard;\n",
          "type": "registry:ui",
          "target": "components/ui/expandable-bento-card.tsx"
        },
        {
          "path": "lib/utils.ts",
          "content": "import { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...inputs: ClassValue[]) {\n  return twMerge(clsx(inputs));\n}\n\nexport async function copyToClipboard(text: string): Promise<boolean> {\n  if (typeof window === \"undefined\") return false;\n\n  try {\n    if (navigator.clipboard && window.isSecureContext) {\n      await navigator.clipboard.writeText(text);\n      return true;\n    }\n\n    const textArea = document.createElement(\"textarea\");\n    textArea.value = text;\n    textArea.style.position = \"fixed\";\n    textArea.style.left = \"-999999px\";\n    textArea.style.top = \"-999999px\";\n    document.body.appendChild(textArea);\n    textArea.focus();\n    textArea.select();\n    const succeeded = document.execCommand(\"copy\");\n    textArea.remove();\n    return succeeded;\n  } catch {\n    return false;\n  }\n}\n",
          "type": "registry:lib",
          "target": "lib/utils.ts"
        }
      ]
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "expanding-search-pill",
      "type": "registry:ui",
      "title": "Expanding Search Pill",
      "author": "Rishabh Bose <https://theb0se.vercel.app/>",
      "description": "Airbnb-style compact floating search pill that fluidly morphs with layout springs into an expanded multi-segment drawer with destination, date, and guest selection panels.",
      "dependencies": [
        "framer-motion",
        "lucide-react",
        "clsx",
        "tailwind-merge"
      ],
      "files": [
        {
          "path": "components/ui/expanding-search-pill.tsx",
          "content": "\"use client\";\n\nimport React, { useState, useRef, useEffect } from \"react\";\nimport { motion, AnimatePresence } from \"framer-motion\";\nimport {\n  Search,\n  MapPin,\n  Calendar,\n  Users,\n  X,\n  ChevronRight,\n  Sparkles,\n  SlidersHorizontal,\n  Plus,\n  Minus,\n  Check,\n} from \"lucide-react\";\nimport { cn } from \"@/lib/utils\";\n\nexport type SearchSegment = \"where\" | \"when\" | \"who\" | null;\n\nexport interface SearchState {\n  destination: string;\n  dateRange: string;\n  adults: number;\n  children: number;\n  infants: number;\n}\n\nexport interface ExpandingSearchPillProps {\n  /** Initial destination query */\n  initialDestination?: string;\n  /** Initial date selection */\n  initialDateRange?: string;\n  /** Initial guest count */\n  initialAdults?: number;\n  /** Callback on search submission */\n  onSearch?: (state: SearchState) => void;\n  /** Whether the search pill is embedded in a modal or navbar without full background presentation */\n  embedded?: boolean;\n  /** Extra container className */\n  className?: string;\n}\n\nconst DESTINATION_PRESETS = [\n  { id: \"flexible\", label: \"I'm Flexible\", icon: Sparkles, hint: \"Anywhere in the world\" },\n  { id: \"kyoto\", label: \"Kyoto, Japan\", icon: MapPin, hint: \"Historic shrines & bamboo groves\" },\n  { id: \"amalfi\", label: \"Amalfi Coast, Italy\", icon: MapPin, hint: \"Cliffside ocean villas\" },\n  { id: \"aspen\", label: \"Aspen, Colorado\", icon: MapPin, hint: \"Cozy mountain lodges & ski chalets\" },\n  { id: \"paris\", label: \"Paris, France\", icon: MapPin, hint: \"Haussmannian apartments & bistros\" },\n];\n\nconst DATE_PRESETS = [\n  { id: \"anytime\", label: \"Anytime\", desc: \"Flexible travel dates\" },\n  { id: \"weekend\", label: \"This Weekend\", desc: \"Fri - Sun getaways\" },\n  { id: \"week\", label: \"1 Week in July\", desc: \"Midsummer retreat\" },\n  { id: \"autumn\", label: \"Autumn Foliage\", desc: \"Oct 12 - Oct 19\" },\n];\n\nconst SAMPLE_LISTINGS = [\n  {\n    title: \"Panoramic Villa overlooking Mediterranean\",\n    location: \"Amalfi Coast, Italy\",\n    rating: 4.98,\n    price: \"$480 / night\",\n    tag: \"Superhost\",\n    imageBg: \"from-blue-600/40 via-sky-500/20 to-teal-400/30\",\n  },\n  {\n    title: \"Traditional Machiya Zen Sanctuary\",\n    location: \"Kyoto, Japan\",\n    rating: 4.96,\n    price: \"$295 / night\",\n    tag: \"Guest favorite\",\n    imageBg: \"from-amber-700/40 via-stone-800/30 to-rose-900/30\",\n  },\n  {\n    title: \"A-Frame Snow Chalet with Private Hot Tub\",\n    location: \"Aspen, Colorado\",\n    rating: 4.99,\n    price: \"$620 / night\",\n    tag: \"Rare find\",\n    imageBg: \"from-indigo-950/50 via-slate-800/40 to-blue-900/30\",\n  },\n];\n\nexport function ExpandingSearchPill({\n  initialDestination = \"Anywhere\",\n  initialDateRange = \"Any week\",\n  initialAdults = 1,\n  onSearch,\n  embedded = false,\n  className,\n}: ExpandingSearchPillProps) {\n  const [isExpanded, setIsExpanded] = useState(false);\n  const [activeSegment, setActiveSegment] = useState<SearchSegment>(null);\n\n  const [destination, setDestination] = useState(initialDestination);\n  const [dateRange, setDateRange] = useState(initialDateRange);\n  const [adults, setAdults] = useState(initialAdults);\n  const [children, setChildren] = useState(0);\n  const [infants, setInfants] = useState(0);\n\n  const containerRef = useRef<HTMLDivElement>(null);\n\n  const totalGuests = adults + children + infants;\n  const guestSummary =\n    totalGuests === 0\n      ? \"Add guests\"\n      : `${totalGuests} guest${totalGuests > 1 ? \"s\" : \"\"}${infants > 0 ? `, ${infants} infant` : \"\"}`;\n\n  const destinationSummary = destination.trim() || \"Anywhere\";\n  const dateSummary = dateRange.trim() || \"Any week\";\n\n  const handleOpenSegment = (seg: SearchSegment) => {\n    setIsExpanded(true);\n    setActiveSegment(seg);\n  };\n\n  const handleApplySearch = () => {\n    setIsExpanded(false);\n    setActiveSegment(null);\n    onSearch?.({\n      destination: destinationSummary,\n      dateRange: dateSummary,\n      adults,\n      children,\n      infants,\n    });\n  };\n\n  const handleReset = () => {\n    setDestination(\"Anywhere\");\n    setDateRange(\"Any week\");\n    setAdults(1);\n    setChildren(0);\n    setInfants(0);\n    setActiveSegment(null);\n    setIsExpanded(false);\n  };\n\n  const applyPreset = (dest: string, dates: string, numGuests: number) => {\n    setDestination(dest);\n    setDateRange(dates);\n    setAdults(numGuests);\n    setChildren(0);\n    setInfants(0);\n    setIsExpanded(false);\n    setActiveSegment(null);\n  };\n\n  // Close when clicking outside\n  useEffect(() => {\n    function handleClickOutside(event: MouseEvent) {\n      if (containerRef.current && !containerRef.current.contains(event.target as Node)) {\n        setIsExpanded(false);\n        setActiveSegment(null);\n      }\n    }\n    document.addEventListener(\"mousedown\", handleClickOutside);\n    return () => document.removeEventListener(\"mousedown\", handleClickOutside);\n  }, []);\n\n  const pillWidget = (\n    <div ref={containerRef} className=\"relative w-full max-w-3xl\">\n      {/* COMPACT PILL MODE */}\n      {!isExpanded && (\n        <motion.div\n          layoutId=\"search-pill-container\"\n          transition={{ type: \"spring\", stiffness: 450, damping: 35 }}\n          className=\"mx-auto flex w-full max-w-lg cursor-pointer items-center justify-between rounded-full border border-neutral-300/80 bg-white p-2 shadow-lg shadow-neutral-950/5 transition-all hover:border-neutral-400 hover:shadow-xl dark:border-neutral-700/80 dark:bg-neutral-900 dark:shadow-black/40 dark:hover:border-neutral-600\"\n          onClick={() => handleOpenSegment(\"where\")}\n          role=\"button\"\n          tabIndex={0}\n          aria-label=\"Search destinations, dates, and guests\"\n          onKeyDown={(e) => {\n            if (e.key === \"Enter\" || e.key === \" \") {\n              e.preventDefault();\n              handleOpenSegment(\"where\");\n            }\n          }}\n        >\n          {/* Segment 1: Destination */}\n          <button\n            type=\"button\"\n            onClick={(e) => {\n              e.stopPropagation();\n              handleOpenSegment(\"where\");\n            }}\n            className=\"flex flex-1 items-center px-4 text-left transition hover:opacity-80\"\n          >\n            <span className=\"truncate text-xs font-semibold text-neutral-900 dark:text-neutral-100\">\n              {destinationSummary}\n            </span>\n          </button>\n\n          <div className=\"h-4 w-px bg-neutral-200 dark:bg-neutral-700\" />\n\n          {/* Segment 2: Dates */}\n          <button\n            type=\"button\"\n            onClick={(e) => {\n              e.stopPropagation();\n              handleOpenSegment(\"when\");\n            }}\n            className=\"flex flex-1 items-center px-4 text-left transition hover:opacity-80\"\n          >\n            <span className=\"truncate text-xs font-medium text-neutral-600 dark:text-neutral-300\">\n              {dateSummary}\n            </span>\n          </button>\n\n          <div className=\"h-4 w-px bg-neutral-200 dark:bg-neutral-700\" />\n\n          {/* Segment 3: Guests */}\n          <button\n            type=\"button\"\n            onClick={(e) => {\n              e.stopPropagation();\n              handleOpenSegment(\"who\");\n            }}\n            className=\"flex flex-1 items-center px-4 text-left transition hover:opacity-80\"\n          >\n            <span className=\"truncate text-xs text-neutral-500 dark:text-neutral-400\">\n              {guestSummary}\n            </span>\n          </button>\n\n          {/* Action Button */}\n          <div className=\"flex h-9 w-9 shrink-0 items-center justify-center rounded-full bg-rose-500 text-white shadow-md shadow-rose-500/30 transition hover:bg-rose-600 active:scale-95\">\n            <Search className=\"h-4 w-4\" />\n          </div>\n        </motion.div>\n      )}\n\n      {/* EXPANDED MULTI-SEGMENT SEARCH BAR */}\n      {isExpanded && (\n        <motion.div\n          layoutId=\"search-pill-container\"\n          transition={{ type: \"spring\", stiffness: 450, damping: 35 }}\n          className=\"relative mx-auto flex w-full flex-col rounded-3xl border border-neutral-300/90 bg-white/95 p-2 shadow-2xl shadow-neutral-950/15 backdrop-blur-xl dark:border-neutral-700/80 dark:bg-neutral-900/95 dark:shadow-black/70\"\n        >\n          {/* Top Navigation Row */}\n          <div className=\"flex flex-wrap items-center justify-between border-b border-neutral-100 px-3 py-2 dark:border-neutral-800\">\n            <div className=\"flex items-center gap-1.5 text-xs font-semibold text-neutral-500 dark:text-neutral-400\">\n              <span className=\"inline-block h-2 w-2 rounded-full bg-rose-500\" />\n              <span>Stays &amp; Experiences</span>\n            </div>\n            <button\n              type=\"button\"\n              onClick={() => setIsExpanded(false)}\n              className=\"rounded-full p-1 text-neutral-400 transition hover:bg-neutral-100 hover:text-neutral-700 dark:hover:bg-neutral-800 dark:hover:text-neutral-200\"\n              aria-label=\"Close search\"\n            >\n              <X className=\"h-4 w-4\" />\n            </button>\n          </div>\n\n          {/* Multi-segment Selector Bar */}\n          <div className=\"relative mt-2 flex flex-col items-stretch gap-1 sm:flex-row sm:items-center sm:gap-0\">\n            {/* Segment: Where */}\n            <button\n              type=\"button\"\n              onClick={() => setActiveSegment(\"where\")}\n              className={cn(\n                \"relative z-10 flex flex-1 flex-col rounded-2xl px-5 py-3 text-left transition-colors\",\n                activeSegment === \"where\"\n                  ? \"bg-neutral-100 text-neutral-900 dark:bg-neutral-800 dark:text-white\"\n                  : \"hover:bg-neutral-50 dark:hover:bg-neutral-800/50\"\n              )}\n            >\n              <span className=\"text-[10px] font-semibold tracking-wider uppercase text-neutral-500 dark:text-neutral-400\">\n                Where\n              </span>\n              <input\n                type=\"text\"\n                value={destination === \"Anywhere\" ? \"\" : destination}\n                onChange={(e) => setDestination(e.target.value)}\n                placeholder=\"Search destinations\"\n                className=\"mt-0.5 w-full bg-transparent text-xs font-semibold text-neutral-900 placeholder:text-neutral-400 focus:outline-none dark:text-white\"\n              />\n            </button>\n\n            <div className=\"hidden h-8 w-px bg-neutral-200 sm:block dark:bg-neutral-700\" />\n\n            {/* Segment: When */}\n            <button\n              type=\"button\"\n              onClick={() => setActiveSegment(\"when\")}\n              className={cn(\n                \"relative z-10 flex flex-1 flex-col rounded-2xl px-5 py-3 text-left transition-colors\",\n                activeSegment === \"when\"\n                  ? \"bg-neutral-100 text-neutral-900 dark:bg-neutral-800 dark:text-white\"\n                  : \"hover:bg-neutral-50 dark:hover:bg-neutral-800/50\"\n              )}\n            >\n              <span className=\"text-[10px] font-semibold tracking-wider uppercase text-neutral-500 dark:text-neutral-400\">\n                When\n              </span>\n              <span className=\"mt-0.5 truncate text-xs font-semibold text-neutral-900 dark:text-white\">\n                {dateRange || \"Add dates\"}\n              </span>\n            </button>\n\n            <div className=\"hidden h-8 w-px bg-neutral-200 sm:block dark:bg-neutral-700\" />\n\n            {/* Segment: Who */}\n            <button\n              type=\"button\"\n              onClick={() => setActiveSegment(\"who\")}\n              className={cn(\n                \"relative z-10 flex flex-1 flex-col rounded-2xl px-5 py-3 text-left transition-colors\",\n                activeSegment === \"who\"\n                  ? \"bg-neutral-100 text-neutral-900 dark:bg-neutral-800 dark:text-white\"\n                  : \"hover:bg-neutral-50 dark:hover:bg-neutral-800/50\"\n              )}\n            >\n              <span className=\"text-[10px] font-semibold tracking-wider uppercase text-neutral-500 dark:text-neutral-400\">\n                Who\n              </span>\n              <span className=\"mt-0.5 truncate text-xs font-semibold text-neutral-900 dark:text-white\">\n                {guestSummary}\n              </span>\n            </button>\n\n            {/* Search CTA */}\n            <div className=\"p-1 sm:p-2\">\n              <button\n                type=\"button\"\n                onClick={handleApplySearch}\n                className=\"flex w-full items-center justify-center gap-2 rounded-2xl bg-rose-500 px-5 py-3 text-xs font-semibold text-white shadow-lg shadow-rose-500/30 transition hover:bg-rose-600 active:scale-95 sm:w-auto\"\n              >\n                <Search className=\"h-4 w-4\" />\n                <span>Search</span>\n              </button>\n            </div>\n          </div>\n\n          {/* POPUP / SHEET CONTENT ACCORDING TO ACTIVE SEGMENT */}\n          <AnimatePresence mode=\"wait\">\n            {activeSegment === \"where\" && (\n              <motion.div\n                key=\"where-sheet\"\n                initial={{ opacity: 0, y: 10 }}\n                animate={{ opacity: 1, y: 0 }}\n                exit={{ opacity: 0, y: 5 }}\n                transition={{ duration: 0.18 }}\n                className=\"mt-3 rounded-2xl border border-neutral-200 bg-neutral-50/80 p-4 dark:border-neutral-800 dark:bg-neutral-950/60\"\n              >\n                <div className=\"mb-2 text-xs font-semibold text-neutral-700 dark:text-neutral-300\">\n                  Search by region or vibe\n                </div>\n                <div className=\"grid grid-cols-1 gap-2 sm:grid-cols-2\">\n                  {DESTINATION_PRESETS.map((item) => {\n                    const Icon = item.icon;\n                    const isSelected = destination === item.label;\n                    return (\n                      <button\n                        key={item.id}\n                        type=\"button\"\n                        onClick={() => {\n                          setDestination(item.label);\n                          setActiveSegment(\"when\");\n                        }}\n                        className={cn(\n                          \"flex items-center gap-3 rounded-xl border p-2.5 text-left transition\",\n                          isSelected\n                            ? \"border-rose-500/50 bg-rose-500/10 dark:bg-rose-500/20\"\n                            : \"border-neutral-200 bg-white hover:bg-neutral-100 dark:border-neutral-800 dark:bg-neutral-900 dark:hover:bg-neutral-800\"\n                        )}\n                      >\n                        <div className=\"flex h-8 w-8 shrink-0 items-center justify-center rounded-lg bg-neutral-100 text-neutral-700 dark:bg-neutral-800 dark:text-neutral-300\">\n                          <Icon className=\"h-4 w-4\" />\n                        </div>\n                        <div className=\"min-w-0\">\n                          <div className=\"truncate text-xs font-semibold text-neutral-900 dark:text-neutral-100\">\n                            {item.label}\n                          </div>\n                          <div className=\"truncate text-[10px] text-neutral-500 dark:text-neutral-400\">\n                            {item.hint}\n                          </div>\n                        </div>\n                      </button>\n                    );\n                  })}\n                </div>\n              </motion.div>\n            )}\n\n            {activeSegment === \"when\" && (\n              <motion.div\n                key=\"when-sheet\"\n                initial={{ opacity: 0, y: 10 }}\n                animate={{ opacity: 1, y: 0 }}\n                exit={{ opacity: 0, y: 5 }}\n                transition={{ duration: 0.18 }}\n                className=\"mt-3 rounded-2xl border border-neutral-200 bg-neutral-50/80 p-4 dark:border-neutral-800 dark:bg-neutral-950/60\"\n              >\n                <div className=\"mb-2 text-xs font-semibold text-neutral-700 dark:text-neutral-300\">\n                  Choose your time frame\n                </div>\n                <div className=\"grid grid-cols-2 gap-2 sm:grid-cols-4\">\n                  {DATE_PRESETS.map((preset) => {\n                    const isSelected = dateRange === preset.label;\n                    return (\n                      <button\n                        key={preset.id}\n                        type=\"button\"\n                        onClick={() => {\n                          setDateRange(preset.label);\n                          setActiveSegment(\"who\");\n                        }}\n                        className={cn(\n                          \"flex flex-col rounded-xl border p-3 text-left transition\",\n                          isSelected\n                            ? \"border-rose-500/50 bg-rose-500/10 dark:bg-rose-500/20\"\n                            : \"border-neutral-200 bg-white hover:bg-neutral-100 dark:border-neutral-800 dark:bg-neutral-900 dark:hover:bg-neutral-800\"\n                        )}\n                      >\n                        <div className=\"flex items-center gap-1.5\">\n                          <Calendar className=\"h-3.5 w-3.5 text-neutral-500\" />\n                          <span className=\"text-xs font-semibold text-neutral-900 dark:text-neutral-100\">\n                            {preset.label}\n                          </span>\n                        </div>\n                        <div className=\"mt-1 text-[10px] text-neutral-500 dark:text-neutral-400\">\n                          {preset.desc}\n                        </div>\n                      </button>\n                    );\n                  })}\n                </div>\n              </motion.div>\n            )}\n\n            {activeSegment === \"who\" && (\n              <motion.div\n                key=\"who-sheet\"\n                initial={{ opacity: 0, y: 10 }}\n                animate={{ opacity: 1, y: 0 }}\n                exit={{ opacity: 0, y: 5 }}\n                transition={{ duration: 0.18 }}\n                className=\"mt-3 space-y-3 rounded-2xl border border-neutral-200 bg-neutral-50/80 p-4 dark:border-neutral-800 dark:bg-neutral-950/60\"\n              >\n                {/* Adults Stepper */}\n                <div className=\"flex items-center justify-between border-b border-neutral-200 pb-3 dark:border-neutral-800\">\n                  <div>\n                    <div className=\"text-xs font-semibold text-neutral-900 dark:text-neutral-100\">\n                      Adults\n                    </div>\n                    <div className=\"text-[10px] text-neutral-500 dark:text-neutral-400\">\n                      Ages 13 or above\n                    </div>\n                  </div>\n                  <div className=\"flex items-center gap-2.5\">\n                    <button\n                      type=\"button\"\n                      onClick={() => setAdults((a) => Math.max(1, a - 1))}\n                      disabled={adults <= 1}\n                      className=\"flex h-7 w-7 items-center justify-center rounded-full border border-neutral-300 text-neutral-700 transition hover:bg-neutral-200 disabled:opacity-30 dark:border-neutral-700 dark:text-neutral-300 dark:hover:bg-neutral-800\"\n                    >\n                      <Minus className=\"h-3 w-3\" />\n                    </button>\n                    <span className=\"w-4 text-center font-mono text-xs font-semibold text-neutral-900 dark:text-neutral-100\">\n                      {adults}\n                    </span>\n                    <button\n                      type=\"button\"\n                      onClick={() => setAdults((a) => a + 1)}\n                      className=\"flex h-7 w-7 items-center justify-center rounded-full border border-neutral-300 text-neutral-700 transition hover:bg-neutral-200 dark:border-neutral-700 dark:text-neutral-300 dark:hover:bg-neutral-800\"\n                    >\n                      <Plus className=\"h-3 w-3\" />\n                    </button>\n                  </div>\n                </div>\n\n                {/* Children Stepper */}\n                <div className=\"flex items-center justify-between border-b border-neutral-200 pb-3 dark:border-neutral-800\">\n                  <div>\n                    <div className=\"text-xs font-semibold text-neutral-900 dark:text-neutral-100\">\n                      Children\n                    </div>\n                    <div className=\"text-[10px] text-neutral-500 dark:text-neutral-400\">\n                      Ages 2–12\n                    </div>\n                  </div>\n                  <div className=\"flex items-center gap-2.5\">\n                    <button\n                      type=\"button\"\n                      onClick={() => setChildren((c) => Math.max(0, c - 1))}\n                      disabled={children <= 0}\n                      className=\"flex h-7 w-7 items-center justify-center rounded-full border border-neutral-300 text-neutral-700 transition hover:bg-neutral-200 disabled:opacity-30 dark:border-neutral-700 dark:text-neutral-300 dark:hover:bg-neutral-800\"\n                    >\n                      <Minus className=\"h-3 w-3\" />\n                    </button>\n                    <span className=\"w-4 text-center font-mono text-xs font-semibold text-neutral-900 dark:text-neutral-100\">\n                      {children}\n                    </span>\n                    <button\n                      type=\"button\"\n                      onClick={() => setChildren((c) => c + 1)}\n                      className=\"flex h-7 w-7 items-center justify-center rounded-full border border-neutral-300 text-neutral-700 transition hover:bg-neutral-200 dark:border-neutral-700 dark:text-neutral-300 dark:hover:bg-neutral-800\"\n                    >\n                      <Plus className=\"h-3 w-3\" />\n                    </button>\n                  </div>\n                </div>\n\n                {/* Infants Stepper */}\n                <div className=\"flex items-center justify-between\">\n                  <div>\n                    <div className=\"text-xs font-semibold text-neutral-900 dark:text-neutral-100\">\n                      Infants\n                    </div>\n                    <div className=\"text-[10px] text-neutral-500 dark:text-neutral-400\">\n                      Under 2\n                    </div>\n                  </div>\n                  <div className=\"flex items-center gap-2.5\">\n                    <button\n                      type=\"button\"\n                      onClick={() => setInfants((i) => Math.max(0, i - 1))}\n                      disabled={infants <= 0}\n                      className=\"flex h-7 w-7 items-center justify-center rounded-full border border-neutral-300 text-neutral-700 transition hover:bg-neutral-200 disabled:opacity-30 dark:border-neutral-700 dark:text-neutral-300 dark:hover:bg-neutral-800\"\n                    >\n                      <Minus className=\"h-3 w-3\" />\n                    </button>\n                    <span className=\"w-4 text-center font-mono text-xs font-semibold text-neutral-900 dark:text-neutral-100\">\n                      {infants}\n                    </span>\n                    <button\n                      type=\"button\"\n                      onClick={() => setInfants((i) => i + 1)}\n                      className=\"flex h-7 w-7 items-center justify-center rounded-full border border-neutral-300 text-neutral-700 transition hover:bg-neutral-200 dark:border-neutral-700 dark:text-neutral-300 dark:hover:bg-neutral-800\"\n                    >\n                      <Plus className=\"h-3 w-3\" />\n                    </button>\n                  </div>\n                </div>\n              </motion.div>\n            )}\n          </AnimatePresence>\n        </motion.div>\n      )}\n    </div>\n  );\n\n  if (embedded) {\n    return (\n      <div className={cn(\"relative w-full flex justify-center py-2\", className)}>\n        {pillWidget}\n      </div>\n    );\n  }\n\n  return (\n    <div\n      data-fullscreen-scroll\n      className={cn(\n        \"relative flex min-h-[520px] w-full flex-col justify-between overflow-hidden rounded-2xl border border-neutral-200 bg-neutral-50/70 p-4 sm:p-8 dark:border-neutral-800 dark:bg-neutral-950\",\n        className\n      )}\n    >\n      {/* Header telemetry & branding */}\n      <div className=\"relative z-10 flex flex-wrap items-center justify-between gap-3\">\n        <div className=\"flex items-center gap-2.5\">\n          <div className=\"flex h-8 w-8 items-center justify-center rounded-xl bg-rose-500/10 text-rose-600 dark:bg-rose-500/20 dark:text-rose-400\">\n            <Search className=\"h-4 w-4\" />\n          </div>\n          <div>\n            <div className=\"flex items-center gap-2\">\n              <span className=\"text-sm font-semibold tracking-tight text-neutral-900 dark:text-neutral-100\">\n                Airbnb Expanding Search Pill\n              </span>\n              <span className=\"rounded-full border border-rose-500/30 bg-rose-500/10 px-2 py-0.5 text-[10px] font-semibold text-rose-600 dark:text-rose-400\">\n                Shared Spring Layout\n              </span>\n            </div>\n            <p className=\"text-xs text-neutral-500 dark:text-neutral-400\">\n              Morphs from a compact floating status pill into an interactive multi-segment drawer\n            </p>\n          </div>\n        </div>\n\n        <div className=\"flex items-center gap-2\">\n          <button\n            type=\"button\"\n            onClick={() => {\n              setIsExpanded(!isExpanded);\n              setActiveSegment(isExpanded ? null : \"where\");\n            }}\n            className=\"flex items-center gap-1.5 rounded-lg border border-neutral-200 bg-white px-3 py-1.5 text-xs font-medium text-neutral-700 shadow-xs transition hover:bg-neutral-100 dark:border-neutral-800 dark:bg-neutral-900 dark:text-neutral-300 dark:hover:bg-neutral-800\"\n          >\n            <SlidersHorizontal className=\"h-3 w-3\" />\n            <span>{isExpanded ? \"Collapse Pill\" : \"Expand Pill\"}</span>\n          </button>\n        </div>\n      </div>\n\n      {/* Main Interactive Stage */}\n      <div className=\"relative z-20 my-auto flex flex-col items-center justify-center py-6\">\n        {pillWidget}\n\n        {/* Live Search Results / Simulated Listings Preview */}\n        <div className=\"mt-8 w-full max-w-3xl\">\n          <div className=\"mb-2.5 flex items-center justify-between\">\n            <span className=\"font-mono text-[11px] font-semibold tracking-wider uppercase text-neutral-400\">\n              Matched Escapes for: {destinationSummary} ({guestSummary})\n            </span>\n            <span className=\"text-xs text-rose-500 font-medium\">3 available</span>\n          </div>\n\n          <div className=\"grid grid-cols-1 gap-3 sm:grid-cols-3\">\n            {SAMPLE_LISTINGS.map((listing, idx) => (\n              <div\n                key={idx}\n                className=\"group relative flex flex-col justify-between overflow-hidden rounded-xl border border-neutral-200 bg-white p-3.5 shadow-xs transition hover:shadow-md dark:border-neutral-800 dark:bg-neutral-900\"\n              >\n                <div\n                  className={cn(\n                    \"mb-2.5 h-20 w-full rounded-lg bg-gradient-to-br transition group-hover:scale-[1.02]\",\n                    listing.imageBg\n                  )}\n                />\n                <div>\n                  <div className=\"flex items-center justify-between\">\n                    <span className=\"rounded bg-neutral-100 px-1.5 py-0.5 text-[9px] font-semibold text-neutral-600 dark:bg-neutral-800 dark:text-neutral-300\">\n                      {listing.tag}\n                    </span>\n                    <span className=\"font-mono text-[10px] font-medium text-neutral-500\">\n                      ★ {listing.rating}\n                    </span>\n                  </div>\n                  <h4 className=\"mt-1.5 line-clamp-1 text-xs font-semibold text-neutral-900 dark:text-neutral-100\">\n                    {listing.title}\n                  </h4>\n                  <p className=\"line-clamp-1 text-[11px] text-neutral-500 dark:text-neutral-400\">\n                    {listing.location}\n                  </p>\n                </div>\n                <div className=\"mt-2.5 pt-2 border-t border-neutral-100 dark:border-neutral-800/80 flex items-center justify-between\">\n                  <span className=\"text-xs font-bold text-neutral-900 dark:text-neutral-100\">\n                    {listing.price}\n                  </span>\n                  <ChevronRight className=\"h-3.5 w-3.5 text-neutral-400 transition group-hover:translate-x-0.5\" />\n                </div>\n              </div>\n            ))}\n          </div>\n        </div>\n      </div>\n\n      {/* Bottom Preset Controls */}\n      <div className=\"relative z-10 flex flex-wrap items-center justify-between gap-3 border-t border-neutral-200/80 pt-4 dark:border-neutral-800/80\">\n        <div className=\"flex flex-wrap items-center gap-1.5 text-xs text-neutral-500\">\n          <span className=\"font-medium\">Quick Presets:</span>\n          <button\n            type=\"button\"\n            onClick={() => applyPreset(\"Kyoto, Japan\", \"Autumn Foliage\", 2)}\n            className=\"rounded-md bg-neutral-200/60 px-2 py-0.5 text-[11px] font-medium text-neutral-700 transition hover:bg-neutral-200 dark:bg-neutral-800 dark:text-neutral-300 dark:hover:bg-neutral-700\"\n          >\n            Kyoto · 2 Guests\n          </button>\n          <button\n            type=\"button\"\n            onClick={() => applyPreset(\"Amalfi Coast, Italy\", \"This Weekend\", 2)}\n            className=\"rounded-md bg-neutral-200/60 px-2 py-0.5 text-[11px] font-medium text-neutral-700 transition hover:bg-neutral-200 dark:bg-neutral-800 dark:text-neutral-300 dark:hover:bg-neutral-700\"\n          >\n            Amalfi Coast · Weekend\n          </button>\n          <button\n            type=\"button\"\n            onClick={() => applyPreset(\"Aspen, Colorado\", \"1 Week in July\", 4)}\n            className=\"rounded-md bg-neutral-200/60 px-2 py-0.5 text-[11px] font-medium text-neutral-700 transition hover:bg-neutral-200 dark:bg-neutral-800 dark:text-neutral-300 dark:hover:bg-neutral-700\"\n          >\n            Aspen · 4 Guests\n          </button>\n        </div>\n\n        <button\n          type=\"button\"\n          onClick={handleReset}\n          className=\"text-xs text-neutral-500 underline transition hover:text-neutral-900 dark:text-neutral-400 dark:hover:text-white\"\n        >\n          Reset search\n        </button>\n      </div>\n    </div>\n  );\n}\n\nexport default ExpandingSearchPill;\n",
          "type": "registry:ui",
          "target": "components/ui/expanding-search-pill.tsx"
        },
        {
          "path": "lib/utils.ts",
          "content": "import { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...inputs: ClassValue[]) {\n  return twMerge(clsx(inputs));\n}\n\nexport async function copyToClipboard(text: string): Promise<boolean> {\n  if (typeof window === \"undefined\") return false;\n\n  try {\n    if (navigator.clipboard && window.isSecureContext) {\n      await navigator.clipboard.writeText(text);\n      return true;\n    }\n\n    const textArea = document.createElement(\"textarea\");\n    textArea.value = text;\n    textArea.style.position = \"fixed\";\n    textArea.style.left = \"-999999px\";\n    textArea.style.top = \"-999999px\";\n    document.body.appendChild(textArea);\n    textArea.focus();\n    textArea.select();\n    const succeeded = document.execCommand(\"copy\");\n    textArea.remove();\n    return succeeded;\n  } catch {\n    return false;\n  }\n}\n",
          "type": "registry:lib",
          "target": "lib/utils.ts"
        }
      ]
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "falling-petals",
      "type": "registry:ui",
      "title": "Falling Petals",
      "author": "Rishabh Bose <https://theb0se.vercel.app/>",
      "description": "Botanical particle background rendering organic Bezier cherry blossom petals, autumn maple leaves, and golden ginkgo foliage with 3D pitch/roll/yaw flutter and shared wind gusts.",
      "dependencies": [
        "lucide-react",
        "clsx",
        "tailwind-merge"
      ],
      "files": [
        {
          "path": "components/ui/falling-petals.tsx",
          "content": "\"use client\";\n\nimport React, { useEffect, useRef, useState } from \"react\";\nimport { Flower2, Wind, ArrowDown, Sparkles, RotateCcw } from \"lucide-react\";\nimport { cn } from \"@/lib/utils\";\n\nexport type PetalVariant = \"sakura\" | \"autumn\" | \"golden\";\n\nexport interface FallingPetalsProps {\n  /** Botanical theme preset */\n  variant?: PetalVariant;\n  /** Number of falling petals or leaves */\n  count?: number;\n  /** Horizontal wind drift and gust multiplier */\n  windSpeed?: number;\n  /** Vertical gravity fall velocity multiplier */\n  fallSpeed?: number;\n  /** 3D pitch/roll/yaw rotational flutter intensity */\n  flutter?: number;\n  /** Optional foreground content */\n  children?: React.ReactNode;\n  /** Additional container classes */\n  className?: string;\n}\n\ninterface PetalParticle {\n  x: number;\n  y: number;\n  depth: number;\n  /** 0 = distant small, 1 = crisp mid-ground, 2 = foreground soft bokeh */\n  plane: 0 | 1 | 2;\n  size: number;\n  yaw: number;\n  pitch: number;\n  roll: number;\n  yawSpeed: number;\n  pitchSpeed: number;\n  rollSpeed: number;\n  glidePhase: number;\n  glideFreq: number;\n  glideSpan: number;\n  colorIndex: number;\n}\n\nconst VARIANT_PALETTES: Record<\n  PetalVariant,\n  {\n    label: string;\n    bgTop: string;\n    bgMid: string;\n    bgBottom: string;\n    sunbeam: string;\n    colors: [string, string, string][];\n  }\n> = {\n  sakura: {\n    label: \"Sakura Blossom\",\n    bgTop: \"#0c0614\",\n    bgMid: \"#190c26\",\n    bgBottom: \"#281338\",\n    sunbeam: \"rgba(249, 168, 212, 0.08)\",\n    colors: [\n      [\"#FFF1F2\", \"#FBCFE8\", \"#F472B6\"],\n      [\"#FDF2F8\", \"#F9A8D4\", \"#EC4899\"],\n      [\"#FFE4E6\", \"#FDA4AF\", \"#FB7185\"],\n      [\"#FFFFFF\", \"#FCE7F3\", \"#F43F5E\"],\n    ],\n  },\n  autumn: {\n    label: \"Autumn Maple\",\n    bgTop: \"#110705\",\n    bgMid: \"#210e08\",\n    bgBottom: \"#30150b\",\n    sunbeam: \"rgba(251, 146, 60, 0.09)\",\n    colors: [\n      [\"#FFEDD5\", \"#FB923C\", \"#C2410C\"],\n      [\"#FEE2E2\", \"#F87171\", \"#B91C1C\"],\n      [\"#FEF3C7\", \"#FBBF24\", \"#B45309\"],\n      [\"#FED7AA\", \"#EA580C\", \"#7C2D12\"],\n    ],\n  },\n  golden: {\n    label: \"Golden Ginkgo\",\n    bgTop: \"#0b0904\",\n    bgMid: \"#1a1407\",\n    bgBottom: \"#291f0b\",\n    sunbeam: \"rgba(253, 224, 71, 0.09)\",\n    colors: [\n      [\"#FEFCE8\", \"#FDE047\", \"#CA8A04\"],\n      [\"#FEF9C3\", \"#FACC15\", \"#A16207\"],\n      [\"#FFFBEB\", \"#FBBF24\", \"#B45309\"],\n      [\"#FEF08A\", \"#EAB308\", \"#854D0E\"],\n    ],\n  },\n};\n\nexport function FallingPetals({\n  variant = \"sakura\",\n  count = 65,\n  windSpeed = 1.0,\n  fallSpeed = 1.0,\n  flutter = 1.0,\n  children,\n  className,\n}: FallingPetalsProps) {\n  const containerRef = useRef<HTMLDivElement>(null);\n  const canvasRef = useRef<HTMLCanvasElement>(null);\n\n  const [simVariant, setSimVariant] = useState<PetalVariant>(variant);\n  const [simCount, setSimCount] = useState(count);\n  const [simWind, setSimWind] = useState(windSpeed);\n  const [simFall, setSimFall] = useState(fallSpeed);\n  const [simFlutter, setSimFlutter] = useState(flutter);\n\n  useEffect(() => setSimVariant(variant), [variant]);\n  useEffect(() => setSimCount(count), [count]);\n  useEffect(() => setSimWind(windSpeed), [windSpeed]);\n  useEffect(() => setSimFall(fallSpeed), [fallSpeed]);\n  useEffect(() => setSimFlutter(flutter), [flutter]);\n\n  const pointerRef = useRef<{ x: number; y: number; vx: number }>({\n    x: 0,\n    y: 0,\n    vx: 0,\n  });\n\n  useEffect(() => {\n    const container = containerRef.current;\n    const canvas = canvasRef.current;\n    if (!container || !canvas) return;\n    const ctx = canvas.getContext(\"2d\");\n    if (!ctx) return;\n\n    let width = container.clientWidth || 800;\n    let height = container.clientHeight || 520;\n    let dpr = Math.min(window.devicePixelRatio || 1, 2);\n\n    const createPetal = (\n      w: number,\n      h: number,\n      idx: number,\n      randomY = true\n    ): PetalParticle => {\n      const rollRatio = (idx * 0.61803398875) % 1;\n      let plane: 0 | 1 | 2 = 1;\n      let depth = 0.6;\n      let size = 12;\n\n      if (rollRatio < 0.3) {\n        plane = 0;\n        depth = 0.28 + Math.random() * 0.22;\n        size = 5.5 + Math.random() * 3.5;\n      } else if (rollRatio < 0.86) {\n        plane = 1;\n        depth = 0.52 + Math.random() * 0.34;\n        size = 9.5 + Math.random() * 6.5;\n      } else {\n        plane = 2;\n        depth = 0.92 + Math.random() * 0.32;\n        size = 22 + Math.random() * 14;\n      }\n\n      return {\n        x: Math.random() * w,\n        y: randomY ? Math.random() * h : -40 - Math.random() * 45,\n        depth,\n        plane,\n        size,\n        yaw: Math.random() * Math.PI * 2,\n        pitch: Math.random() * Math.PI * 2,\n        roll: Math.random() * Math.PI * 2,\n        yawSpeed: (Math.random() - 0.5) * 0.018,\n        pitchSpeed: 0.018 + Math.random() * 0.025,\n        rollSpeed: 0.014 + Math.random() * 0.022,\n        glidePhase: Math.random() * Math.PI * 2,\n        glideFreq: 0.85 + Math.random() * 0.75,\n        glideSpan: 1.1 + Math.random() * 1.35,\n        colorIndex: idx % 4,\n      };\n    };\n\n    let petals: PetalParticle[] = Array.from({ length: simCount }, (_, i) =>\n      createPetal(width, height, i, true)\n    );\n\n    const updateSize = () => {\n      if (!container || !canvas) return;\n      width = container.clientWidth || 800;\n      height = container.clientHeight || 520;\n      dpr = Math.min(window.devicePixelRatio || 1, 2);\n      canvas.width = Math.floor(width * dpr);\n      canvas.height = Math.floor(height * dpr);\n      ctx.setTransform(dpr, 0, 0, dpr, 0, 0);\n    };\n\n    updateSize();\n    const observer = new ResizeObserver(updateSize);\n    observer.observe(container);\n\n    let rafId = 0;\n    let time = 0;\n\n    const drawSakuraPetal = (r: number, showVeins: boolean) => {\n      // Realistic notched heart-shaped sakura petal\n      ctx.beginPath();\n      ctx.moveTo(0, r * 1.05);\n      ctx.bezierCurveTo(\n        r * 0.92,\n        r * 0.62,\n        r * 1.08,\n        -r * 0.48,\n        r * 0.32,\n        -r * 1.02\n      );\n      ctx.lineTo(0, -r * 0.68);\n      ctx.lineTo(-r * 0.32, -r * 1.02);\n      ctx.bezierCurveTo(\n        -r * 1.08,\n        -r * 0.48,\n        -r * 0.92,\n        r * 0.62,\n        0,\n        r * 1.05\n      );\n      ctx.closePath();\n      ctx.fill();\n\n      if (showVeins) {\n        ctx.strokeStyle = \"rgba(255, 255, 255, 0.35)\";\n        ctx.lineWidth = 0.6;\n        ctx.beginPath();\n        ctx.moveTo(0, r * 0.92);\n        ctx.quadraticCurveTo(r * 0.08, 0, r * 0.16, -r * 0.62);\n        ctx.moveTo(0, r * 0.92);\n        ctx.quadraticCurveTo(-r * 0.08, 0, -r * 0.16, -r * 0.62);\n        ctx.stroke();\n      }\n    };\n\n    const drawAutumnMapleLeaf = (r: number, showVeins: boolean) => {\n      // Serrated 5-lobe maple/oak autumn leaf silhouette\n      ctx.beginPath();\n      ctx.moveTo(0, r * 1.05);\n      ctx.lineTo(r * 0.18, r * 0.65);\n      ctx.lineTo(r * 0.88, r * 0.48);\n      ctx.lineTo(r * 0.52, r * 0.12);\n      ctx.lineTo(r * 1.05, -r * 0.35);\n      ctx.lineTo(r * 0.42, -r * 0.42);\n      ctx.lineTo(0, -r * 1.15);\n      ctx.lineTo(-r * 0.42, -r * 0.42);\n      ctx.lineTo(-r * 1.05, -r * 0.35);\n      ctx.lineTo(-r * 0.52, r * 0.12);\n      ctx.lineTo(-r * 0.88, r * 0.48);\n      ctx.lineTo(-r * 0.18, r * 0.65);\n      ctx.closePath();\n      ctx.fill();\n\n      if (showVeins) {\n        ctx.strokeStyle = \"rgba(255, 247, 237, 0.32)\";\n        ctx.lineWidth = 0.75;\n        ctx.beginPath();\n        ctx.moveTo(0, r * 1.25);\n        ctx.lineTo(0, -r * 0.92);\n        ctx.moveTo(0, r * 0.25);\n        ctx.lineTo(r * 0.68, -r * 0.22);\n        ctx.moveTo(0, r * 0.25);\n        ctx.lineTo(-r * 0.68, -r * 0.22);\n        ctx.stroke();\n      }\n    };\n\n    const drawGoldenGinkgo = (r: number, showVeins: boolean) => {\n      // Fan-shaped golden ginkgo biloba leaf with stem & cleft\n      ctx.beginPath();\n      ctx.moveTo(0, r * 1.05);\n      ctx.quadraticCurveTo(r * 0.22, r * 0.32, r * 1.12, -r * 0.38);\n      ctx.bezierCurveTo(\n        r * 0.92,\n        -r * 1.05,\n        r * 0.24,\n        -r * 0.98,\n        0,\n        -r * 0.52\n      );\n      ctx.bezierCurveTo(\n        -r * 0.24,\n        -r * 0.98,\n        -r * 0.92,\n        -r * 1.05,\n        -r * 1.12,\n        -r * 0.38\n      );\n      ctx.quadraticCurveTo(-r * 0.22, r * 0.32, 0, r * 1.05);\n      ctx.closePath();\n      ctx.fill();\n\n      if (showVeins) {\n        ctx.strokeStyle = \"rgba(254, 240, 138, 0.38)\";\n        ctx.lineWidth = 0.65;\n        ctx.beginPath();\n        ctx.moveTo(0, r * 1.32);\n        ctx.lineTo(0, -r * 0.45);\n        ctx.moveTo(0, r * 0.65);\n        ctx.lineTo(r * 0.52, -r * 0.55);\n        ctx.moveTo(0, r * 0.65);\n        ctx.lineTo(-r * 0.52, -r * 0.55);\n        ctx.stroke();\n      }\n    };\n\n    const render = () => {\n      time += 0.016;\n      const palette = VARIANT_PALETTES[simVariant];\n\n      if (petals.length < simCount) {\n        while (petals.length < simCount) {\n          petals.push(createPetal(width, height, petals.length, true));\n        }\n      } else if (petals.length > simCount) {\n        petals.length = simCount;\n      }\n\n      // Rich botanical twilight gradient\n      const bgGrad = ctx.createLinearGradient(0, 0, 0, height);\n      bgGrad.addColorStop(0, palette.bgTop);\n      bgGrad.addColorStop(0.55, palette.bgMid);\n      bgGrad.addColorStop(1, palette.bgBottom);\n      ctx.fillStyle = bgGrad;\n      ctx.fillRect(0, 0, width, height);\n\n      // Diagonal ambient sunbeams\n      ctx.save();\n      ctx.globalCompositeOperation = \"screen\";\n      for (let b = 0; b < 3; b++) {\n        const bx = width * (0.25 + b * 0.26) + Math.sin(time * 0.3 + b) * 30;\n        const beamGrad = ctx.createLinearGradient(\n          bx,\n          0,\n          bx - width * 0.25,\n          height\n        );\n        beamGrad.addColorStop(0, palette.sunbeam);\n        beamGrad.addColorStop(1, \"rgba(0, 0, 0, 0)\");\n        ctx.fillStyle = beamGrad;\n        ctx.beginPath();\n        ctx.moveTo(bx - 70, 0);\n        ctx.lineTo(bx + 70, 0);\n        ctx.lineTo(bx - width * 0.25 + 150, height);\n        ctx.lineTo(bx - width * 0.25 - 150, height);\n        ctx.closePath();\n        ctx.fill();\n      }\n      ctx.restore();\n\n      const globalGust =\n        (Math.sin(time * 0.52) * 0.55 + Math.sin(time * 1.18) * 0.35 + 0.6) *\n        simWind;\n\n      pointerRef.current.vx *= 0.92;\n\n      const updateAndDrawPetal = (p: PetalParticle) => {\n        // Aerodynamic flutter-and-stall pendulum glide physics:\n        // Horizontal velocity peaks in the middle of the swing and stalls at the apex,\n        // while vertical descent slows during horizontal glide (aerodynamic lift) and drops at the stall apex.\n        p.glidePhase += 0.026 * p.glideFreq * (0.55 + 0.45 * simFlutter);\n        const sinPhase = Math.sin(p.glidePhase);\n        const cosPhase = Math.cos(p.glidePhase);\n\n        // Horizontal velocity is proportional to cos(glidePhase) -> stalls smoothly at sinPhase = +-1\n        const aeroGlideVx = cosPhase * p.glideSpan * (0.65 + 0.55 * simFlutter);\n        // Lift peaks when horizontal glide velocity is highest (|cosPhase| near 1)\n        const aeroLift = (1 - Math.abs(cosPhase) * 0.48) * simFall;\n\n        p.x +=\n          (globalGust * 1.25 + aeroGlideVx + pointerRef.current.vx * 0.08) *\n          p.depth;\n        p.y += (0.95 + p.depth * 1.05) * aeroLift;\n\n        // Bank angle coupled to aerodynamic glide + gentle 3D pitch/roll rotation\n        p.yaw += p.yawSpeed * simFlutter;\n        p.pitch += p.pitchSpeed * simFlutter;\n        p.roll += p.rollSpeed * simFlutter;\n\n        const margin = p.plane === 2 ? 55 : 35;\n        if (p.y > height + margin) {\n          p.y = -margin;\n          p.x = Math.random() * width;\n        }\n        if (p.x > width + margin) p.x = -margin;\n        if (p.x < -margin) p.x = width + margin;\n\n        const scaleX = 0.26 + Math.abs(Math.cos(p.roll + sinPhase * 0.6)) * 0.74;\n        const scaleY = 0.28 + Math.abs(Math.sin(p.pitch)) * 0.72;\n        const bankAngle = p.yaw + sinPhase * 0.48 * simFlutter;\n\n        const [tipColor, midColor, baseColor] =\n          palette.colors[p.colorIndex % palette.colors.length];\n\n        ctx.save();\n        ctx.translate(p.x, p.y);\n        ctx.rotate(bankAngle);\n        ctx.scale(scaleX, scaleY);\n\n        if (p.plane === 2) {\n          // Out-of-focus foreground bokeh petal\n          ctx.globalAlpha = 0.26;\n          const bokehGrad = ctx.createRadialGradient(\n            0,\n            0,\n            p.size * 0.1,\n            0,\n            0,\n            p.size * 1.1\n          );\n          bokehGrad.addColorStop(0, tipColor);\n          bokehGrad.addColorStop(0.55, midColor);\n          bokehGrad.addColorStop(1, \"rgba(255, 255, 255, 0)\");\n          ctx.fillStyle = bokehGrad;\n        } else {\n          ctx.globalAlpha = p.plane === 0 ? 0.48 : 0.92;\n          const pGrad = ctx.createLinearGradient(\n            -p.size * 0.5,\n            -p.size,\n            p.size * 0.5,\n            p.size\n          );\n          pGrad.addColorStop(0, tipColor);\n          pGrad.addColorStop(0.55, midColor);\n          pGrad.addColorStop(1, baseColor);\n          ctx.fillStyle = pGrad;\n        }\n\n        const showVeins = p.plane === 1;\n        if (simVariant === \"sakura\") {\n          drawSakuraPetal(p.size, showVeins);\n        } else if (simVariant === \"autumn\") {\n          drawAutumnMapleLeaf(p.size, showVeins);\n        } else {\n          drawGoldenGinkgo(p.size, showVeins);\n        }\n\n        ctx.restore();\n      };\n\n      // Render across 3 optical depth-of-field planes\n      for (const p of petals) {\n        if (p.plane === 0) updateAndDrawPetal(p);\n      }\n      for (const p of petals) {\n        if (p.plane === 1) updateAndDrawPetal(p);\n      }\n      for (const p of petals) {\n        if (p.plane === 2) updateAndDrawPetal(p);\n      }\n\n      rafId = requestAnimationFrame(render);\n    };\n\n    rafId = requestAnimationFrame(render);\n\n    return () => {\n      cancelAnimationFrame(rafId);\n      observer.disconnect();\n    };\n  }, [simVariant, simCount, simWind, simFall, simFlutter]);\n\n  const handlePointerMove = (e: React.PointerEvent<HTMLDivElement>) => {\n    const rect = e.currentTarget.getBoundingClientRect();\n    const nx = e.clientX - rect.left;\n    const dx = nx - pointerRef.current.x;\n    pointerRef.current.x = nx;\n    pointerRef.current.y = e.clientY - rect.top;\n    pointerRef.current.vx = Math.max(-18, Math.min(18, dx));\n  };\n\n  const resetDefaults = () => {\n    setSimVariant(variant);\n    setSimCount(count);\n    setSimWind(windSpeed);\n    setSimFall(fallSpeed);\n    setSimFlutter(flutter);\n  };\n\n  return (\n    <div\n      ref={containerRef}\n      data-fullscreen-scroll\n      onPointerMove={handlePointerMove}\n      className={cn(\n        \"relative w-full min-h-[520px] overflow-hidden rounded-2xl bg-[#0c0614] text-slate-100 select-none\",\n        className\n      )}\n    >\n      <canvas\n        ref={canvasRef}\n        className=\"pointer-events-none absolute inset-0 h-full w-full\"\n      />\n\n      {children && (\n        <div className=\"relative z-10 flex min-h-[520px] w-full flex-col\">\n          {children}\n        </div>\n      )}\n    </div>\n  );\n}\n\nexport default FallingPetals;\n",
          "type": "registry:ui",
          "target": "components/ui/falling-petals.tsx"
        },
        {
          "path": "lib/utils.ts",
          "content": "import { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...inputs: ClassValue[]) {\n  return twMerge(clsx(inputs));\n}\n\nexport async function copyToClipboard(text: string): Promise<boolean> {\n  if (typeof window === \"undefined\") return false;\n\n  try {\n    if (navigator.clipboard && window.isSecureContext) {\n      await navigator.clipboard.writeText(text);\n      return true;\n    }\n\n    const textArea = document.createElement(\"textarea\");\n    textArea.value = text;\n    textArea.style.position = \"fixed\";\n    textArea.style.left = \"-999999px\";\n    textArea.style.top = \"-999999px\";\n    document.body.appendChild(textArea);\n    textArea.focus();\n    textArea.select();\n    const succeeded = document.execCommand(\"copy\");\n    textArea.remove();\n    return succeeded;\n  } catch {\n    return false;\n  }\n}\n",
          "type": "registry:lib",
          "target": "lib/utils.ts"
        }
      ]
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "feature-card",
      "type": "registry:ui",
      "title": "Feature Card",
      "author": "Rishabh Bose <https://theb0se.vercel.app/>",
      "description": "Large rounded showcase card with an eyebrow badge, headline, concise copy, interactive media stage, and smooth spring hover lift.",
      "dependencies": [
        "framer-motion",
        "lucide-react",
        "clsx",
        "tailwind-merge"
      ],
      "files": [
        {
          "path": "components/ui/feature-card.tsx",
          "content": "\"use client\";\n\nimport React, { useState } from \"react\";\nimport { motion, useReducedMotion } from \"framer-motion\";\nimport { ArrowUpRight, Sparkles, Layers, Cpu } from \"lucide-react\";\nimport { cn } from \"@/lib/utils\";\n\nexport interface FeatureCardProps {\n  /** Eyebrow label above the headline */\n  eyebrow?: string;\n  /** Main card headline */\n  title?: string;\n  /** Short descriptive copy */\n  description?: string;\n  /** Optional CTA label */\n  ctaLabel?: string;\n  /** Optional link or click handler */\n  onAction?: () => void;\n  /** Custom media element rendered inside the media stage */\n  media?: React.ReactNode;\n  /** Card layout orientation. Default: \"vertical\" */\n  layout?: \"vertical\" | \"horizontal\";\n  className?: string;\n}\n\nexport function FeatureCard({\n  eyebrow = \"Apple Silicon Architecture\",\n  title = \"Engineered for fluid 120Hz motion.\",\n  description = \"Every interaction responds with spring physics, hardware-accelerated transforms, and zero layout shift across light and dark appearances.\",\n  ctaLabel = \"Explore Architecture\",\n  onAction,\n  media,\n  layout = \"vertical\",\n  className,\n}: FeatureCardProps) {\n  const shouldReduceMotion = useReducedMotion() ?? false;\n  const [hovered, setHovered] = useState(false);\n\n  return (\n    <motion.article\n      onMouseEnter={() => setHovered(true)}\n      onMouseLeave={() => setHovered(false)}\n      animate={{\n        y: hovered && !shouldReduceMotion ? -6 : 0,\n      }}\n      transition={{ type: \"spring\", stiffness: 360, damping: 28 }}\n      className={cn(\n        \"group relative flex w-full max-w-md overflow-hidden rounded-[28px] border border-neutral-200/90 bg-white p-6 shadow-sm transition-shadow duration-300 hover:shadow-xl dark:border-neutral-800/90 dark:bg-[#0A0A0A] dark:hover:border-neutral-700\",\n        layout === \"horizontal\"\n          ? \"max-w-2xl flex-col gap-6 sm:flex-row sm:items-center\"\n          : \"flex-col justify-between gap-6\",\n        className\n      )}\n    >\n      {/* Text Copy Block */}\n      <div className={cn(\"flex flex-col\", layout === \"horizontal\" && \"sm:w-1/2\")}>\n        {eyebrow && (\n          <span className=\"inline-flex items-center gap-1.5 font-mono text-[11px] font-semibold uppercase tracking-wider text-neutral-500 dark:text-neutral-400\">\n            <Sparkles className=\"h-3 w-3\" />\n            {eyebrow}\n          </span>\n        )}\n\n        <h3 className=\"mt-2 text-xl font-bold tracking-tight text-neutral-950 dark:text-white sm:text-2xl\">\n          {title}\n        </h3>\n\n        <p className=\"mt-2 text-xs leading-relaxed text-neutral-600 dark:text-neutral-400 sm:text-sm\">\n          {description}\n        </p>\n\n        {ctaLabel && (\n          <div className=\"mt-4\">\n            <button\n              type=\"button\"\n              onClick={onAction}\n              className=\"inline-flex items-center gap-1.5 rounded-full bg-neutral-900 px-4 py-2 text-xs font-semibold text-white transition-transform active:scale-95 dark:bg-white dark:text-black\"\n            >\n              <span>{ctaLabel}</span>\n              <ArrowUpRight className=\"h-3.5 w-3.5 transition-transform group-hover:-translate-y-0.5 group-hover:translate-x-0.5\" />\n            </button>\n          </div>\n        )}\n      </div>\n\n      {/* Media Area */}\n      <div\n        className={cn(\n          \"relative overflow-hidden rounded-2xl border border-neutral-200/80 bg-neutral-50 p-5 dark:border-neutral-800/80 dark:bg-[#111111]\",\n          layout === \"horizontal\" ? \"sm:w-1/2\" : \"w-full\"\n        )}\n      >\n        {media ?? (\n          <div className=\"flex flex-col gap-3\">\n            {/* Simulated Hardware Telemetry Media Stage */}\n            <div className=\"flex items-center justify-between\">\n              <div className=\"flex items-center gap-2\">\n                <span className=\"flex h-7 w-7 items-center justify-center rounded-lg bg-neutral-900 text-white dark:bg-white dark:text-black\">\n                  <Cpu className=\"h-3.5 w-3.5\" />\n                </span>\n                <div>\n                  <div className=\"text-xs font-semibold text-neutral-950 dark:text-white\">\n                    Spring Compositor\n                  </div>\n                  <div className=\"font-mono text-[10px] text-neutral-500\">\n                    120 FPS · GPU Layer\n                  </div>\n                </div>\n              </div>\n              <span className=\"rounded-full border border-neutral-200 bg-white px-2.5 py-0.5 font-mono text-[10px] font-medium text-neutral-700 dark:border-neutral-800 dark:bg-neutral-950 dark:text-neutral-300\">\n                Active\n              </span>\n            </div>\n\n            {/* Animated Bars inside Media Area */}\n            <div className=\"mt-1 space-y-2 rounded-xl border border-neutral-200/70 bg-white p-3 dark:border-neutral-800 dark:bg-[#0A0A0A]\">\n              {[\n                { label: \"Frame Budget\", pct: hovered ? \"94%\" : \"78%\", val: \"8.3ms\" },\n                { label: \"Spring Velocity\", pct: hovered ? \"86%\" : \"62%\", val: \"420 N/m\" },\n              ].map((metric) => (\n                <div key={metric.label} className=\"space-y-1\">\n                  <div className=\"flex justify-between font-mono text-[10px]\">\n                    <span className=\"text-neutral-500\">{metric.label}</span>\n                    <span className=\"font-semibold text-neutral-900 dark:text-white\">\n                      {metric.val}\n                    </span>\n                  </div>\n                  <div className=\"h-1.5 w-full overflow-hidden rounded-full bg-neutral-100 dark:bg-neutral-900\">\n                    <motion.div\n                      animate={{ width: metric.pct }}\n                      transition={{ type: \"spring\", stiffness: 260, damping: 26 }}\n                      className=\"h-full rounded-full bg-neutral-900 dark:bg-white\"\n                    />\n                  </div>\n                </div>\n              ))}\n            </div>\n          </div>\n        )}\n      </div>\n    </motion.article>\n  );\n}\n\nexport default FeatureCard;\n",
          "type": "registry:ui",
          "target": "components/ui/feature-card.tsx"
        },
        {
          "path": "lib/utils.ts",
          "content": "import { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...inputs: ClassValue[]) {\n  return twMerge(clsx(inputs));\n}\n\nexport async function copyToClipboard(text: string): Promise<boolean> {\n  if (typeof window === \"undefined\") return false;\n\n  try {\n    if (navigator.clipboard && window.isSecureContext) {\n      await navigator.clipboard.writeText(text);\n      return true;\n    }\n\n    const textArea = document.createElement(\"textarea\");\n    textArea.value = text;\n    textArea.style.position = \"fixed\";\n    textArea.style.left = \"-999999px\";\n    textArea.style.top = \"-999999px\";\n    document.body.appendChild(textArea);\n    textArea.focus();\n    textArea.select();\n    const succeeded = document.execCommand(\"copy\");\n    textArea.remove();\n    return succeeded;\n  } catch {\n    return false;\n  }\n}\n",
          "type": "registry:lib",
          "target": "lib/utils.ts"
        }
      ]
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "file-tree",
      "type": "registry:ui",
      "title": "File Tree",
      "author": "Rishabh Bose <https://theb0se.vercel.app/>",
      "description": "Hierarchical file and folder explorer with animated expand/collapse transitions, instant file search filtering, and active path tracking.",
      "dependencies": [
        "framer-motion",
        "lucide-react",
        "clsx",
        "tailwind-merge"
      ],
      "files": [
        {
          "path": "components/ui/file-tree.tsx",
          "content": "\"use client\";\n\nimport React, { useState, useMemo } from \"react\";\nimport { AnimatePresence, motion, useReducedMotion } from \"framer-motion\";\nimport {\n  Check,\n  ChevronRight,\n  Copy,\n  FileCode2,\n  FileJson,\n  FileText,\n  Folder,\n  FolderOpen,\n  Search,\n} from \"lucide-react\";\nimport { cn } from \"@/lib/utils\";\n\nasync function copyToClipboard(text: string): Promise<boolean> {\n  if (typeof window === \"undefined\") return false;\n  try {\n    if (navigator.clipboard && window.isSecureContext) {\n      await navigator.clipboard.writeText(text);\n      return true;\n    }\n    const textArea = document.createElement(\"textarea\");\n    textArea.value = text;\n    textArea.style.position = \"fixed\";\n    textArea.style.left = \"-999999px\";\n    textArea.style.top = \"-999999px\";\n    document.body.appendChild(textArea);\n    textArea.focus();\n    textArea.select();\n    const succeeded = document.execCommand(\"copy\");\n    textArea.remove();\n    return succeeded;\n  } catch {\n    return false;\n  }\n}\n\nexport interface FileTreeNode {\n  id: string;\n  name: string;\n  type: \"file\" | \"folder\";\n  badge?: string;\n  children?: FileTreeNode[];\n}\n\nexport interface FileTreeProps {\n  /** Hierarchical file tree data */\n  data?: FileTreeNode[];\n  /** Default expanded folder IDs */\n  defaultExpandedIds?: string[];\n  /** Default selected file/folder ID */\n  defaultSelectedId?: string;\n  /** Callback when a node is clicked */\n  onSelect?: (node: FileTreeNode) => void;\n  /** Show top search filter input */\n  searchable?: boolean;\n  /** Additional container class names */\n  className?: string;\n}\n\nconst DEFAULT_TREE: FileTreeNode[] = [\n  {\n    id: \"src\",\n    name: \"src\",\n    type: \"folder\",\n    children: [\n      {\n        id: \"src/app\",\n        name: \"app\",\n        type: \"folder\",\n        children: [\n          { id: \"src/app/layout.tsx\", name: \"layout.tsx\", type: \"file\", badge: \"TSX\" },\n          { id: \"src/app/page.tsx\", name: \"page.tsx\", type: \"file\", badge: \"TSX\" },\n          { id: \"src/app/globals.css\", name: \"globals.css\", type: \"file\", badge: \"CSS\" },\n        ],\n      },\n      {\n        id: \"src/components\",\n        name: \"components\",\n        type: \"folder\",\n        children: [\n          {\n            id: \"src/components/ui\",\n            name: \"ui\",\n            type: \"folder\",\n            children: [\n              { id: \"src/components/ui/Autocomplete.tsx\", name: \"Autocomplete.tsx\", type: \"file\", badge: \"NEW\" },\n              { id: \"src/components/ui/FileTree.tsx\", name: \"FileTree.tsx\", type: \"file\", badge: \"NEW\" },\n              { id: \"src/components/ui/MagneticButton.tsx\", name: \"MagneticButton.tsx\", type: \"file\" },\n            ],\n          },\n        ],\n      },\n      {\n        id: \"src/lib\",\n        name: \"lib\",\n        type: \"folder\",\n        children: [\n          { id: \"src/lib/utils.ts\", name: \"utils.ts\", type: \"file\", badge: \"TS\" },\n        ],\n      },\n    ],\n  },\n  { id: \"package.json\", name: \"package.json\", type: \"file\", badge: \"JSON\" },\n  { id: \"README.md\", name: \"README.md\", type: \"file\", badge: \"MD\" },\n];\n\nfunction collectFolderIds(nodes: FileTreeNode[]): string[] {\n  const ids: string[] = [];\n  for (const node of nodes) {\n    if (node.type === \"folder\") {\n      ids.push(node.id);\n      if (node.children) {\n        ids.push(...collectFolderIds(node.children));\n      }\n    }\n  }\n  return ids;\n}\n\nfunction getFileIcon(name: string) {\n  if (name.endsWith(\".json\")) {\n    return <FileJson className=\"h-3.5 w-3.5 shrink-0 text-neutral-400\" />;\n  }\n  if (name.endsWith(\".md\") || name.endsWith(\".txt\")) {\n    return <FileText className=\"h-3.5 w-3.5 shrink-0 text-neutral-400\" />;\n  }\n  return <FileCode2 className=\"h-3.5 w-3.5 shrink-0 text-neutral-400\" />;\n}\n\nfunction filterTree(nodes: FileTreeNode[], query: string): FileTreeNode[] {\n  if (!query.trim()) return nodes;\n  const lower = query.toLowerCase();\n\n  return nodes.reduce<FileTreeNode[]>((acc, node) => {\n    const matchesSelf = node.name.toLowerCase().includes(lower);\n    if (node.type === \"folder\" && node.children) {\n      const filteredChildren = filterTree(node.children, query);\n      if (matchesSelf || filteredChildren.length > 0) {\n        acc.push({\n          ...node,\n          children: filteredChildren.length > 0 ? filteredChildren : node.children,\n        });\n      }\n    } else if (matchesSelf) {\n      acc.push(node);\n    }\n    return acc;\n  }, []);\n}\n\nexport function FileTree({\n  data = DEFAULT_TREE,\n  defaultExpandedIds = [\"src\", \"src/components\", \"src/components/ui\"],\n  defaultSelectedId = \"src/components/ui/FileTree.tsx\",\n  onSelect,\n  searchable = true,\n  className,\n}: FileTreeProps) {\n  const shouldReduceMotion = useReducedMotion();\n  const [expanded, setExpanded] = useState<Set<string>>(\n    () => new Set(defaultExpandedIds)\n  );\n  const [selectedId, setSelectedId] = useState<string>(defaultSelectedId);\n  const [query, setQuery] = useState(\"\");\n  const [copiedPath, setCopiedPath] = useState(false);\n\n  const allFolderIds = useMemo(() => collectFolderIds(data), [data]);\n  const visibleData = useMemo(() => filterTree(data, query), [data, query]);\n\n  const toggleFolder = (id: string) => {\n    setExpanded((prev) => {\n      const next = new Set(prev);\n      if (next.has(id)) next.delete(id);\n      else next.add(id);\n      return next;\n    });\n  };\n\n  const handleCopyPath = async () => {\n    const ok = await copyToClipboard(selectedId);\n    if (ok) {\n      setCopiedPath(true);\n      setTimeout(() => setCopiedPath(false), 1500);\n    }\n  };\n\n  const renderNode = (node: FileTreeNode, depth = 0) => {\n    const isFolder = node.type === \"folder\";\n    const isOpen = query.trim().length > 0 || expanded.has(node.id);\n    const isSelected = selectedId === node.id;\n\n    return (\n      <div\n        key={node.id}\n        role=\"treeitem\"\n        aria-expanded={isFolder ? isOpen : undefined}\n        aria-selected={isSelected}\n      >\n        <button\n          type=\"button\"\n          onClick={() => {\n            setSelectedId(node.id);\n            onSelect?.(node);\n            if (isFolder) toggleFolder(node.id);\n          }}\n          style={{ paddingLeft: `${depth * 14 + 10}px` }}\n          className={cn(\n            \"group flex w-full cursor-pointer items-center justify-between gap-2 rounded-lg py-1.5 pr-2.5 text-left text-xs transition-colors\",\n            isSelected\n              ? \"bg-black font-medium text-white dark:bg-white dark:text-black\"\n              : \"text-neutral-700 hover:bg-neutral-100 hover:text-black dark:text-neutral-300 dark:hover:bg-[#141414] dark:hover:text-white\"\n          )}\n        >\n          <span className=\"flex min-w-0 items-center gap-1.5\">\n            {isFolder ? (\n              <>\n                <ChevronRight\n                  className={cn(\n                    \"h-3.5 w-3.5 shrink-0 transition-transform duration-150\",\n                    isOpen && \"rotate-90\",\n                    isSelected\n                      ? \"text-white dark:text-black\"\n                      : \"text-neutral-400\"\n                  )}\n                />\n                {isOpen ? (\n                  <FolderOpen\n                    className={cn(\n                      \"h-3.5 w-3.5 shrink-0\",\n                      isSelected\n                        ? \"text-white dark:text-black\"\n                        : \"text-neutral-600 dark:text-neutral-300\"\n                    )}\n                  />\n                ) : (\n                  <Folder\n                    className={cn(\n                      \"h-3.5 w-3.5 shrink-0\",\n                      isSelected\n                        ? \"text-white dark:text-black\"\n                        : \"text-neutral-500 dark:text-neutral-400\"\n                    )}\n                  />\n                )}\n              </>\n            ) : (\n              <>\n                <span className=\"w-3.5 shrink-0\" />\n                {getFileIcon(node.name)}\n              </>\n            )}\n            <span className=\"truncate font-mono text-[11.5px]\">{node.name}</span>\n          </span>\n\n          {node.badge && (\n            <span\n              className={cn(\n                \"rounded px-1.5 py-0.5 font-mono text-[9px] uppercase tracking-wider\",\n                isSelected\n                  ? \"bg-white/20 text-white dark:bg-black/15 dark:text-black\"\n                  : \"border border-neutral-200 bg-neutral-50 text-neutral-500 dark:border-[#262626] dark:bg-[#121212] dark:text-neutral-400\"\n              )}\n            >\n              {node.badge}\n            </span>\n          )}\n        </button>\n\n        <AnimatePresence initial={false}>\n          {isFolder && isOpen && node.children && node.children.length > 0 && (\n            <motion.div\n              role=\"group\"\n              initial={shouldReduceMotion ? { opacity: 0 } : { height: 0, opacity: 0 }}\n              animate={\n                shouldReduceMotion ? { opacity: 1 } : { height: \"auto\", opacity: 1 }\n              }\n              exit={shouldReduceMotion ? { opacity: 0 } : { height: 0, opacity: 0 }}\n              transition={{ duration: shouldReduceMotion ? 0 : 0.18, ease: \"easeOut\" }}\n              className=\"overflow-hidden\"\n            >\n              {node.children.map((child) => renderNode(child, depth + 1))}\n            </motion.div>\n          )}\n        </AnimatePresence>\n      </div>\n    );\n  };\n\n  return (\n    <div\n      role=\"tree\"\n      aria-label=\"File explorer\"\n      className={cn(\n        \"w-full max-w-sm overflow-hidden rounded-2xl border border-neutral-200 bg-white dark:border-[#222222] dark:bg-[#0A0A0A]\",\n        className\n      )}\n    >\n      {searchable && (\n        <div className=\"flex items-center justify-between gap-2 border-b border-neutral-200 px-3 py-2 dark:border-[#1F1F1F]\">\n          <div className=\"flex flex-1 items-center gap-2\">\n            <Search className=\"h-3.5 w-3.5 shrink-0 text-neutral-400\" />\n            <input\n              type=\"text\"\n              value={query}\n              onChange={(e) => setQuery(e.target.value)}\n              placeholder=\"Filter files...\"\n              aria-label=\"Filter files\"\n              className=\"w-full bg-transparent font-mono text-xs text-black placeholder:text-neutral-400 focus:outline-none dark:text-white dark:placeholder:text-neutral-500\"\n            />\n          </div>\n          <button\n            type=\"button\"\n            onClick={() =>\n              setExpanded((prev) =>\n                prev.size >= allFolderIds.length\n                  ? new Set()\n                  : new Set(allFolderIds)\n              )\n            }\n            className=\"shrink-0 cursor-pointer rounded border border-neutral-200 px-1.5 py-0.5 font-mono text-[10px] text-neutral-500 transition-colors hover:border-black hover:text-black dark:border-[#262626] dark:hover:border-white dark:hover:text-white\"\n          >\n            {expanded.size >= allFolderIds.length ? \"Collapse\" : \"Expand\"}\n          </button>\n        </div>\n      )}\n\n      <div className=\"max-h-72 overflow-y-auto p-2\">\n        {visibleData.length === 0 ? (\n          <div className=\"py-6 text-center text-xs text-neutral-400\">\n            No matching files\n          </div>\n        ) : (\n          visibleData.map((node) => renderNode(node, 0))\n        )}\n      </div>\n\n      <div className=\"flex items-center justify-between gap-2 border-t border-neutral-200 bg-neutral-50/70 px-3 py-2 font-mono text-[10px] text-neutral-500 dark:border-[#1F1F1F] dark:bg-[#050505]\">\n        <span className=\"truncate\">{selectedId}</span>\n        <button\n          type=\"button\"\n          onClick={handleCopyPath}\n          aria-label=\"Copy selected file path\"\n          className=\"inline-flex shrink-0 cursor-pointer items-center gap-1 rounded px-1.5 py-0.5 text-neutral-500 transition-colors hover:text-black dark:hover:text-white\"\n        >\n          {copiedPath ? (\n            <>\n              <Check className=\"h-3 w-3\" />\n              <span>Copied</span>\n            </>\n          ) : (\n            <>\n              <Copy className=\"h-3 w-3\" />\n              <span>Copy</span>\n            </>\n          )}\n        </button>\n      </div>\n    </div>\n  );\n}\n\nexport default FileTree;\n",
          "type": "registry:ui",
          "target": "components/ui/file-tree.tsx"
        },
        {
          "path": "lib/utils.ts",
          "content": "import { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...inputs: ClassValue[]) {\n  return twMerge(clsx(inputs));\n}\n\nexport async function copyToClipboard(text: string): Promise<boolean> {\n  if (typeof window === \"undefined\") return false;\n\n  try {\n    if (navigator.clipboard && window.isSecureContext) {\n      await navigator.clipboard.writeText(text);\n      return true;\n    }\n\n    const textArea = document.createElement(\"textarea\");\n    textArea.value = text;\n    textArea.style.position = \"fixed\";\n    textArea.style.left = \"-999999px\";\n    textArea.style.top = \"-999999px\";\n    document.body.appendChild(textArea);\n    textArea.focus();\n    textArea.select();\n    const succeeded = document.execCommand(\"copy\");\n    textArea.remove();\n    return succeeded;\n  } catch {\n    return false;\n  }\n}\n",
          "type": "registry:lib",
          "target": "lib/utils.ts"
        }
      ]
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "fireflies",
      "type": "registry:ui",
      "title": "Fireflies",
      "author": "Rishabh Bose <https://theb0se.vercel.app/>",
      "description": "Enchanted twilight forest background with bioluminescent firefly orbs drifting along smooth organic trajectories and pulsing with soft radial halos.",
      "dependencies": [
        "lucide-react",
        "clsx",
        "tailwind-merge"
      ],
      "files": [
        {
          "path": "components/ui/fireflies.tsx",
          "content": "\"use client\";\n\nimport React, { useEffect, useRef, useState } from \"react\";\nimport { Sparkles, Trees, Gauge, Activity, RotateCcw } from \"lucide-react\";\nimport { cn } from \"@/lib/utils\";\n\nexport interface FirefliesProps {\n  /** Number of bioluminescent firefly orbs */\n  count?: number;\n  /** Primary firefly bioluminescence color in hex */\n  glowColor?: string;\n  /** Drift velocity multiplier */\n  speed?: number;\n  /** Bioluminescent pulse cycle speed multiplier */\n  pulseRate?: number;\n  /** Render multi-layered twilight pine forest silhouette */\n  showForest?: boolean;\n  /** Attract nearby fireflies gently toward the cursor */\n  interactive?: boolean;\n  /** Optional overlay content */\n  children?: React.ReactNode;\n  /** Additional container classes */\n  className?: string;\n}\n\ninterface FireflyParticle {\n  x: number;\n  y: number;\n  vx: number;\n  vy: number;\n  radius: number;\n  phase: number;\n  pulseFreq: number;\n  noiseSeedX: number;\n  noiseSeedY: number;\n  depth: number;\n  /** 0 = distant pinprick, 1 = sharp mid-ground with curved trail, 2 = foreground out-of-focus bokeh disc */\n  plane: 0 | 1 | 2;\n  trail: { x: number; y: number }[];\n}\n\ninterface TreeRidge {\n  points: { x: number; y: number; treeHeight: number; width: number }[];\n  baseHeight: number;\n  color: string;\n}\n\ninterface GrassBlade {\n  x: number;\n  height: number;\n  thickness: number;\n  lean: number;\n  swayFreq: number;\n  swayPhase: number;\n  color: string;\n}\n\nfunction hexToRgb(hex: string): { r: number; g: number; b: number } {\n  const clean = hex.replace(\"#\", \"\").trim();\n  const full =\n    clean.length === 3\n      ? clean\n          .split(\"\")\n          .map((c) => c + c)\n          .join(\"\")\n      : clean;\n  const num = parseInt(full, 16);\n  if (Number.isNaN(num)) return { r: 217, g: 249, b: 157 };\n  return {\n    r: (num >> 16) & 255,\n    g: (num >> 8) & 255,\n    b: num & 255,\n  };\n}\n\nconst COLOR_PRESETS = [\n  { label: \"Lime Glow\", hex: \"#D9F99D\" },\n  { label: \"Amber Gold\", hex: \"#FDE047\" },\n  { label: \"Cyan Sprite\", hex: \"#67E8F9\" },\n  { label: \"Fairy Rose\", hex: \"#F9A8D4\" },\n];\n\nexport function Fireflies({\n  count = 55,\n  glowColor = \"#D9F99D\",\n  speed = 1.0,\n  pulseRate = 1.0,\n  showForest = true,\n  interactive = true,\n  children,\n  className,\n}: FirefliesProps) {\n  const containerRef = useRef<HTMLDivElement>(null);\n  const canvasRef = useRef<HTMLCanvasElement>(null);\n\n  const [simCount, setSimCount] = useState(count);\n  const [simColor, setSimColor] = useState(glowColor);\n  const [simSpeed, setSimSpeed] = useState(speed);\n  const [simPulse, setSimPulse] = useState(pulseRate);\n  const [simForest, setSimForest] = useState(showForest);\n\n  useEffect(() => setSimCount(count), [count]);\n  useEffect(() => setSimColor(glowColor), [glowColor]);\n  useEffect(() => setSimSpeed(speed), [speed]);\n  useEffect(() => setSimPulse(pulseRate), [pulseRate]);\n  useEffect(() => setSimForest(showForest), [showForest]);\n\n  const pointerRef = useRef<{ x: number; y: number; active: boolean }>({\n    x: 0,\n    y: 0,\n    active: false,\n  });\n\n  useEffect(() => {\n    const container = containerRef.current;\n    const canvas = canvasRef.current;\n    if (!container || !canvas) return;\n    const ctx = canvas.getContext(\"2d\");\n    if (!ctx) return;\n\n    let width = container.clientWidth || 800;\n    let height = container.clientHeight || 520;\n    let dpr = Math.min(window.devicePixelRatio || 1, 2);\n\n    const buildMountainRidge = (w: number, h: number) => {\n      const pts: { x: number; y: number }[] = [];\n      const segments = 32;\n      for (let i = 0; i <= segments; i++) {\n        const u = i / segments;\n        const elev =\n          Math.sin(u * Math.PI * 2.2 + 0.4) * 38 +\n          Math.cos(u * Math.PI * 5.5 - 1.1) * 16 +\n          Math.sin(u * Math.PI * 11.0) * 6;\n        pts.push({\n          x: u * w,\n          y: h * 0.67 - elev,\n        });\n      }\n      return pts;\n    };\n\n    const buildForestRidges = (w: number, h: number): TreeRidge[] => {\n      const layerConfigs = [\n        { baseHeight: h * 0.24, color: \"#0b1a2c\", density: 32, scale: 0.72 },\n        { baseHeight: h * 0.14, color: \"#050f1c\", density: 42, scale: 1.08 },\n      ];\n      return layerConfigs.map((cfg, idx) => {\n        const points = [];\n        const step = w / cfg.density;\n        for (let i = -1; i <= cfg.density + 1; i++) {\n          const seed = Math.sin(i * 12.9898 + idx * 78.233) * 43758.5453;\n          const rand = seed - Math.floor(seed);\n          const x = i * step + (rand - 0.5) * step * 0.5;\n          const hillOffset =\n            Math.sin(i * 0.22 + idx * 1.7) * 24 +\n            Math.cos(i * 0.11 - idx) * 12;\n          const treeHeight = (34 + rand * 58) * cfg.scale;\n          const widthTree = (15 + rand * 20) * cfg.scale;\n          points.push({\n            x,\n            y: h - cfg.baseHeight + hillOffset,\n            treeHeight,\n            width: widthTree,\n          });\n        }\n        return {\n          points,\n          baseHeight: cfg.baseHeight,\n          color: cfg.color,\n        };\n      });\n    };\n\n    const buildForegroundGrass = (w: number): GrassBlade[] => {\n      const bladeCount = Math.max(90, Math.floor(w / 7));\n      const blades: GrassBlade[] = [];\n      for (let i = 0; i < bladeCount; i++) {\n        const seed = Math.sin(i * 93.17) * 43758.5453;\n        const r1 = seed - Math.floor(seed);\n        const r2 = ((seed * 1.73) % 1 + 1) % 1;\n        blades.push({\n          x: (i / bladeCount) * w + (r1 - 0.5) * 12,\n          height: 26 + r1 * 56,\n          thickness: 1.4 + r2 * 1.8,\n          lean: (r1 - 0.5) * 22,\n          swayFreq: 0.8 + r2 * 1.1,\n          swayPhase: r1 * Math.PI * 2,\n          color: i % 3 === 0 ? \"#040b14\" : \"#02060c\",\n        });\n      }\n      return blades;\n    };\n\n    let mountainPts = buildMountainRidge(width, height);\n    let ridges = buildForestRidges(width, height);\n    let grassBlades = buildForegroundGrass(width);\n\n    const createFirefly = (w: number, h: number, idx: number): FireflyParticle => {\n      const roll = (idx * 0.61803398875) % 1;\n      let plane: 0 | 1 | 2 = 1;\n      let depth = 0.6;\n      let radius = 2.0;\n\n      if (roll < 0.34) {\n        // Distant pinpricks\n        plane = 0;\n        depth = 0.25 + Math.random() * 0.25;\n        radius = 0.8 + Math.random() * 0.9;\n      } else if (roll < 0.84) {\n        // Sharp mid-ground fireflies with trails\n        plane = 1;\n        depth = 0.52 + Math.random() * 0.32;\n        radius = 1.6 + Math.random() * 1.6;\n      } else {\n        // Out-of-focus foreground bokeh discs\n        plane = 2;\n        depth = 0.88 + Math.random() * 0.35;\n        radius = 16 + Math.random() * 18;\n      }\n\n      return {\n        x: Math.random() * w,\n        y:\n          plane === 2\n            ? h * 0.18 + Math.random() * (h * 0.75)\n            : h * 0.1 + Math.random() * (h * 0.78),\n        vx: (Math.random() - 0.5) * 0.6,\n        vy: (Math.random() - 0.5) * 0.4,\n        radius,\n        phase: Math.random() * Math.PI * 2,\n        pulseFreq: 0.75 + Math.random() * 1.35,\n        noiseSeedX: Math.random() * 100,\n        noiseSeedY: Math.random() * 100,\n        depth,\n        plane,\n        trail: [],\n      };\n    };\n\n    let particles: FireflyParticle[] = Array.from({ length: simCount }, (_, i) =>\n      createFirefly(width, height, i)\n    );\n\n    const stars = Array.from({ length: 75 }, (_, i) => ({\n      u: ((Math.sin(i * 91.3) * 43758.5453) % 1 + 1) % 1,\n      v: (((Math.cos(i * 47.7) * 23421.631) % 1 + 1) % 1) * 0.62,\n      size: 0.5 + ((i * 19) % 10) * 0.11,\n      twinklePhase: i * 1.3,\n    }));\n\n    const updateCanvasSize = () => {\n      if (!container || !canvas) return;\n      width = container.clientWidth || 800;\n      height = container.clientHeight || 520;\n      dpr = Math.min(window.devicePixelRatio || 1, 2);\n      canvas.width = Math.floor(width * dpr);\n      canvas.height = Math.floor(height * dpr);\n      ctx.setTransform(dpr, 0, 0, dpr, 0, 0);\n      mountainPts = buildMountainRidge(width, height);\n      ridges = buildForestRidges(width, height);\n      grassBlades = buildForegroundGrass(width);\n    };\n\n    updateCanvasSize();\n    const observer = new ResizeObserver(updateCanvasSize);\n    observer.observe(container);\n\n    let rafId = 0;\n    let time = 0;\n    const rgb = hexToRgb(simColor);\n\n    const drawPine = (\n      cx: number,\n      baseY: number,\n      treeH: number,\n      treeW: number,\n      fill: string\n    ) => {\n      ctx.fillStyle = fill;\n      const tiers = 4;\n      for (let t = 0; t < tiers; t++) {\n        const tierProgress = t / tiers;\n        const topY = baseY - treeH + tierProgress * (treeH * 0.58);\n        const bottomY = baseY - (tiers - 1 - t) * (treeH * 0.2);\n        const halfW = treeW * (0.38 + tierProgress * 0.62) * 0.52;\n        ctx.beginPath();\n        ctx.moveTo(cx, topY);\n        ctx.quadraticCurveTo(cx - halfW * 0.35, (topY + bottomY) * 0.5, cx - halfW, bottomY);\n        ctx.lineTo(cx + halfW, bottomY);\n        ctx.quadraticCurveTo(cx + halfW * 0.35, (topY + bottomY) * 0.5, cx, topY);\n        ctx.closePath();\n        ctx.fill();\n      }\n    };\n\n    const drawCrepuscularMoonbeams = () => {\n      ctx.save();\n      ctx.globalCompositeOperation = \"screen\";\n      const rays = [\n        { x: width * 0.18, w: width * 0.16, alpha: 0.045 },\n        { x: width * 0.42, w: width * 0.22, alpha: 0.06 },\n        { x: width * 0.68, w: width * 0.18, alpha: 0.05 },\n        { x: width * 0.86, w: width * 0.14, alpha: 0.035 },\n      ];\n      for (let i = 0; i < rays.length; i++) {\n        const r = rays[i];\n        const drift = Math.sin(time * 0.25 + i * 1.7) * 28;\n        const topX = r.x + drift;\n        const botX = topX - width * 0.22;\n        const grad = ctx.createLinearGradient(topX, 0, botX, height * 0.92);\n        grad.addColorStop(0, `rgba(186, 230, 253, ${r.alpha})`);\n        grad.addColorStop(\n          0.55,\n          `rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, ${(r.alpha * 0.55).toFixed(4)})`\n        );\n        grad.addColorStop(1, \"rgba(15, 23, 42, 0)\");\n\n        ctx.fillStyle = grad;\n        ctx.beginPath();\n        ctx.moveTo(topX - r.w * 0.35, -10);\n        ctx.lineTo(topX + r.w * 0.35, -10);\n        ctx.lineTo(botX + r.w * 0.95, height);\n        ctx.lineTo(botX - r.w * 0.95, height);\n        ctx.closePath();\n        ctx.fill();\n      }\n      ctx.restore();\n    };\n\n    const render = () => {\n      time += 0.016;\n\n      if (particles.length < simCount) {\n        while (particles.length < simCount) {\n          particles.push(createFirefly(width, height, particles.length));\n        }\n      } else if (particles.length > simCount) {\n        particles.length = simCount;\n      }\n\n      // Deep enchanted twilight sky gradient\n      const skyGrad = ctx.createLinearGradient(0, 0, 0, height);\n      skyGrad.addColorStop(0, \"#02050d\");\n      skyGrad.addColorStop(0.42, \"#071226\");\n      skyGrad.addColorStop(0.76, \"#0d2138\");\n      skyGrad.addColorStop(1, \"#061320\");\n      ctx.fillStyle = skyGrad;\n      ctx.fillRect(0, 0, width, height);\n\n      // Faint background stars\n      for (const s of stars) {\n        const sx = s.u * width;\n        const sy = s.v * height;\n        const alpha = 0.18 + 0.38 * Math.sin(time * 1.4 + s.twinklePhase);\n        ctx.fillStyle = `rgba(226, 232, 240, ${alpha.toFixed(3)})`;\n        ctx.beginPath();\n        ctx.arc(sx, sy, s.size, 0, Math.PI * 2);\n        ctx.fill();\n      }\n\n      // Diagonal crepuscular moonbeams filtering through twilight mist\n      drawCrepuscularMoonbeams();\n\n      // Layer 1 of forest: Distant misty mountain ridge\n      if (simForest && mountainPts.length > 0) {\n        const mtnGrad = ctx.createLinearGradient(0, height * 0.55, 0, height);\n        mtnGrad.addColorStop(0, \"#0d2136\");\n        mtnGrad.addColorStop(1, \"#081524\");\n        ctx.fillStyle = mtnGrad;\n        ctx.beginPath();\n        ctx.moveTo(0, height);\n        for (const pt of mountainPts) {\n          ctx.lineTo(pt.x, pt.y);\n        }\n        ctx.lineTo(width, height);\n        ctx.closePath();\n        ctx.fill();\n\n        // Valley mist blanket over mountain base\n        const mistGrad = ctx.createLinearGradient(\n          0,\n          height * 0.62,\n          0,\n          height * 0.85\n        );\n        mistGrad.addColorStop(0, \"rgba(18, 42, 66, 0)\");\n        mistGrad.addColorStop(\n          0.5,\n          `rgba(${Math.round(rgb.r * 0.4 + 20)}, ${Math.round(\n            rgb.g * 0.4 + 45\n          )}, ${Math.round(rgb.b * 0.4 + 65)}, 0.16)`\n        );\n        mistGrad.addColorStop(1, \"rgba(8, 20, 34, 0)\");\n        ctx.fillStyle = mistGrad;\n        ctx.fillRect(0, height * 0.62, width, height * 0.25);\n      }\n\n      const updateAndDrawFirefly = (p: FireflyParticle) => {\n        const angleX =\n          Math.sin(time * 0.68 * simSpeed + p.noiseSeedX) * 1.2 +\n          Math.cos(time * 0.34 * simSpeed + p.noiseSeedY * 0.5) * 0.85;\n        const angleY =\n          Math.cos(time * 0.52 * simSpeed + p.noiseSeedY) * 0.9 +\n          Math.sin(time * 0.29 * simSpeed + p.noiseSeedX) * 0.65;\n\n        p.vx += (angleX * 0.42 * p.depth * simSpeed - p.vx) * 0.04;\n        p.vy += ((angleY - 0.1) * 0.35 * p.depth * simSpeed - p.vy) * 0.04;\n\n        if (interactive && pointerRef.current.active) {\n          const dx = pointerRef.current.x - p.x;\n          const dy = pointerRef.current.y - p.y;\n          const distSq = dx * dx + dy * dy;\n          if (distSq < 42000 && distSq > 25) {\n            const dist = Math.sqrt(distSq);\n            const pull = (1 - dist / 205) * 0.04 * p.depth;\n            p.vx += (dx / dist) * pull;\n            p.vy += (dy / dist) * pull;\n          }\n        }\n\n        p.x += p.vx;\n        p.y += p.vy;\n\n        const margin = p.plane === 2 ? 50 : 30;\n        if (p.x < -margin) p.x = width + margin;\n        if (p.x > width + margin) p.x = -margin;\n        if (p.y < -margin) p.y = height - 30;\n        if (p.y > height + margin) p.y = 20;\n\n        p.phase += 0.034 * p.pulseFreq * simPulse;\n        const rawSine = (Math.sin(p.phase) + 1) * 0.5;\n        const pulse = 0.1 + Math.pow(rawSine, 2.5) * 0.9;\n\n        if (p.plane === 0) {\n          // Distant tiny bioluminescent pinpricks\n          const r = p.radius * (3.2 + pulse * 2.5);\n          const g = ctx.createRadialGradient(p.x, p.y, 0, p.x, p.y, r);\n          g.addColorStop(\n            0,\n            `rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, ${(0.75 * pulse).toFixed(3)})`\n          );\n          g.addColorStop(1, `rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, 0)`);\n          ctx.fillStyle = g;\n          ctx.beginPath();\n          ctx.arc(p.x, p.y, r, 0, Math.PI * 2);\n          ctx.fill();\n        } else if (p.plane === 1) {\n          // Sharp mid-ground fireflies with curved glowing trails & warm incandescent cores\n          p.trail.unshift({ x: p.x, y: p.y });\n          if (p.trail.length > 12) p.trail.pop();\n\n          if (p.trail.length > 3) {\n            for (let i = 0; i < p.trail.length - 1; i++) {\n              const tRatio = 1 - i / p.trail.length;\n              ctx.strokeStyle = `rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, ${(\n                pulse *\n                0.28 *\n                tRatio *\n                tRatio\n              ).toFixed(3)})`;\n              ctx.lineWidth = p.radius * 0.85 * tRatio;\n              ctx.lineCap = \"round\";\n              ctx.beginPath();\n              ctx.moveTo(p.trail[i].x, p.trail[i].y);\n              ctx.lineTo(p.trail[i + 1].x, p.trail[i + 1].y);\n              ctx.stroke();\n            }\n          }\n\n          const haloRadius = p.radius * (7.0 + pulse * 6.0);\n          const grad = ctx.createRadialGradient(\n            p.x,\n            p.y,\n            0,\n            p.x,\n            p.y,\n            haloRadius\n          );\n          grad.addColorStop(\n            0,\n            `rgba(255, 255, 240, ${(0.98 * pulse).toFixed(3)})`\n          );\n          grad.addColorStop(\n            0.2,\n            `rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, ${(0.82 * pulse).toFixed(3)})`\n          );\n          grad.addColorStop(\n            0.52,\n            `rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, ${(0.24 * pulse).toFixed(3)})`\n          );\n          grad.addColorStop(1, `rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, 0)`);\n\n          ctx.fillStyle = grad;\n          ctx.beginPath();\n          ctx.arc(p.x, p.y, haloRadius, 0, Math.PI * 2);\n          ctx.fill();\n\n          // Warm incandescent core\n          ctx.fillStyle = `rgba(255, 255, 248, ${(0.55 + 0.45 * pulse).toFixed(\n            3\n          )})`;\n          ctx.beginPath();\n          ctx.arc(p.x, p.y, p.radius * (0.72 + 0.35 * pulse), 0, Math.PI * 2);\n          ctx.fill();\n        } else {\n          // Plane 2: Large out-of-focus foreground optical bokeh discs (soft translucent rings)\n          const bokehAlpha = (0.04 + pulse * 0.16) * 0.95;\n          const r = p.radius * (0.9 + pulse * 0.22);\n          const bokehGrad = ctx.createRadialGradient(p.x, p.y, r * 0.1, p.x, p.y, r);\n          bokehGrad.addColorStop(\n            0,\n            `rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, ${(bokehAlpha * 0.55).toFixed(3)})`\n          );\n          bokehGrad.addColorStop(\n            0.72,\n            `rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, ${(bokehAlpha * 0.85).toFixed(3)})`\n          );\n          bokehGrad.addColorStop(\n            0.9,\n            `rgba(255, 255, 245, ${(bokehAlpha * 1.35).toFixed(3)})`\n          );\n          bokehGrad.addColorStop(1, `rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, 0)`);\n\n          ctx.fillStyle = bokehGrad;\n          ctx.beginPath();\n          ctx.arc(p.x, p.y, r, 0, Math.PI * 2);\n          ctx.fill();\n        }\n      };\n\n      // Render distant pinprick fireflies (behind mid-ground conifers)\n      for (const p of particles) {\n        if (p.plane === 0) updateAndDrawFirefly(p);\n      }\n\n      // Layers 2 & 3 of forest: Mid-ground conifers & Near woodland trees\n      if (simForest) {\n        ridges.forEach((ridge, idx) => {\n          ctx.fillStyle = ridge.color;\n          ctx.beginPath();\n          ctx.moveTo(0, height);\n          for (const pt of ridge.points) {\n            ctx.lineTo(pt.x, pt.y);\n          }\n          ctx.lineTo(width, height);\n          ctx.closePath();\n          ctx.fill();\n\n          for (const pt of ridge.points) {\n            drawPine(pt.x, pt.y + 6, pt.treeHeight, pt.width, ridge.color);\n          }\n\n          if (idx === 0) {\n            const fogY = height - ridge.baseHeight - 30;\n            const fogG = ctx.createLinearGradient(0, fogY - 35, 0, height);\n            fogG.addColorStop(0, \"rgba(15, 32, 52, 0)\");\n            fogG.addColorStop(0.5, \"rgba(18, 42, 64, 0.28)\");\n            fogG.addColorStop(1, \"rgba(4, 10, 18, 0)\");\n            ctx.fillStyle = fogG;\n            ctx.fillRect(0, fogY - 35, width, 100);\n          }\n        });\n      }\n\n      // Render sharp mid-ground fireflies\n      for (const p of particles) {\n        if (p.plane === 1) updateAndDrawFirefly(p);\n      }\n\n      // Layer 4 of forest: Detailed foreground swaying grass blades along the bottom\n      if (simForest) {\n        ctx.fillStyle = \"#02060c\";\n        ctx.fillRect(0, height - 10, width, 12);\n\n        for (const blade of grassBlades) {\n          const windSway =\n            Math.sin(time * 1.45 * blade.swayFreq + blade.swayPhase) * 9 +\n            Math.cos(time * 0.7 + blade.x * 0.02) * 4;\n          const tipX = blade.x + blade.lean + windSway;\n          const tipY = height - blade.height;\n          const ctrlX = blade.x + (blade.lean + windSway) * 0.45;\n          const ctrlY = height - blade.height * 0.52;\n\n          ctx.fillStyle = blade.color;\n          ctx.beginPath();\n          ctx.moveTo(blade.x - blade.thickness, height);\n          ctx.quadraticCurveTo(ctrlX - blade.thickness * 0.4, ctrlY, tipX, tipY);\n          ctx.quadraticCurveTo(\n            ctrlX + blade.thickness * 0.4,\n            ctrlY,\n            blade.x + blade.thickness,\n            height\n          );\n          ctx.closePath();\n          ctx.fill();\n        }\n      }\n\n      // Render out-of-focus foreground bokeh fireflies in front of everything\n      ctx.save();\n      ctx.globalCompositeOperation = \"screen\";\n      for (const p of particles) {\n        if (p.plane === 2) updateAndDrawFirefly(p);\n      }\n      ctx.restore();\n\n      rafId = requestAnimationFrame(render);\n    };\n\n    rafId = requestAnimationFrame(render);\n\n    return () => {\n      cancelAnimationFrame(rafId);\n      observer.disconnect();\n    };\n  }, [simCount, simColor, simSpeed, simPulse, simForest, interactive]);\n\n  const handlePointerMove = (e: React.PointerEvent<HTMLDivElement>) => {\n    const rect = e.currentTarget.getBoundingClientRect();\n    pointerRef.current = {\n      x: e.clientX - rect.left,\n      y: e.clientY - rect.top,\n      active: true,\n    };\n  };\n\n  const handlePointerLeave = () => {\n    pointerRef.current.active = false;\n  };\n\n  const resetDefaults = () => {\n    setSimCount(count);\n    setSimColor(glowColor);\n    setSimSpeed(speed);\n    setSimPulse(pulseRate);\n    setSimForest(showForest);\n  };\n\n  return (\n    <div\n      ref={containerRef}\n      data-fullscreen-scroll\n      onPointerMove={handlePointerMove}\n      onPointerLeave={handlePointerLeave}\n      className={cn(\n        \"relative w-full min-h-[520px] overflow-hidden rounded-2xl bg-[#02050d] text-slate-100 select-none\",\n        className\n      )}\n    >\n      <canvas\n        ref={canvasRef}\n        className=\"pointer-events-none absolute inset-0 h-full w-full\"\n      />\n\n      {children && (\n        <div className=\"relative z-10 flex min-h-[520px] w-full flex-col\">\n          {children}\n        </div>\n      )}\n    </div>\n  );\n}\n\nexport default Fireflies;\n",
          "type": "registry:ui",
          "target": "components/ui/fireflies.tsx"
        },
        {
          "path": "lib/utils.ts",
          "content": "import { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...inputs: ClassValue[]) {\n  return twMerge(clsx(inputs));\n}\n\nexport async function copyToClipboard(text: string): Promise<boolean> {\n  if (typeof window === \"undefined\") return false;\n\n  try {\n    if (navigator.clipboard && window.isSecureContext) {\n      await navigator.clipboard.writeText(text);\n      return true;\n    }\n\n    const textArea = document.createElement(\"textarea\");\n    textArea.value = text;\n    textArea.style.position = \"fixed\";\n    textArea.style.left = \"-999999px\";\n    textArea.style.top = \"-999999px\";\n    document.body.appendChild(textArea);\n    textArea.focus();\n    textArea.select();\n    const succeeded = document.execCommand(\"copy\");\n    textArea.remove();\n    return succeeded;\n  } catch {\n    return false;\n  }\n}\n",
          "type": "registry:lib",
          "target": "lib/utils.ts"
        }
      ]
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "floating-compass-nav",
      "type": "registry:ui",
      "title": "Floating Compass Nav",
      "author": "Rishabh Bose <https://theb0se.vercel.app/>",
      "description": "Viewport-anchored floating navigation pod that snaps elastically across four corner quadrants (NW, NE, SW, SE) via spring layout projection.",
      "dependencies": [
        "framer-motion",
        "lucide-react",
        "clsx",
        "tailwind-merge"
      ],
      "files": [
        {
          "path": "components/ui/floating-compass-nav.tsx",
          "content": "\"use client\";\n\nimport React, { useState } from \"react\";\nimport { motion, useReducedMotion } from \"framer-motion\";\nimport { Compass, CornerUpLeft, CornerUpRight, CornerDownLeft, CornerDownRight } from \"lucide-react\";\nimport { cn } from \"@/lib/utils\";\n\nexport type QuadrantId = \"NW\" | \"NE\" | \"SW\" | \"SE\";\n\nexport interface FloatingCompassNavProps {\n  /** Initial corner quadrant. Default: \"SE\" */\n  defaultQuadrant?: QuadrantId;\n  /** Spring stiffness coefficient for corner snap projection. Default: 300 */\n  stiffness?: number;\n  /** Spring damping coefficient for corner snap projection. Default: 24 */\n  damping?: number;\n  className?: string;\n}\n\nconst QUADRANTS: Array<{ id: QuadrantId; label: string; classes: string }> = [\n  { id: \"NW\", label: \"Top-Left\", classes: \"top-3 left-3\" },\n  { id: \"NE\", label: \"Top-Right\", classes: \"top-3 right-3\" },\n  { id: \"SW\", label: \"Bottom-Left\", classes: \"bottom-3 left-3\" },\n  { id: \"SE\", label: \"Bottom-Right\", classes: \"bottom-3 right-3\" },\n];\n\nexport function FloatingCompassNav({\n  defaultQuadrant = \"SE\",\n  stiffness = 300,\n  damping = 24,\n  className,\n}: FloatingCompassNavProps) {\n  const shouldReduceMotion = useReducedMotion() ?? false;\n  const [quadrant, setQuadrant] = useState<QuadrantId>(defaultQuadrant);\n\n  const activeSpec =\n    QUADRANTS.find((q) => q.id === quadrant) || QUADRANTS[3]!;\n\n  return (\n    <div\n      className={cn(\n        \"relative flex h-[230px] w-full max-w-md select-none items-center justify-center overflow-hidden rounded-3xl border border-neutral-200 bg-neutral-50/70 p-4 dark:border-[#222222] dark:bg-[#0A0A0A]\",\n        className\n      )}\n    >\n      {/* Corner Quadrant Targets */}\n      {QUADRANTS.map((q) => (\n        <button\n          key={q.id}\n          type=\"button\"\n          aria-label={`Snap navigation pod to ${q.label} (${q.id})`}\n          onClick={() => setQuadrant(q.id)}\n          className={cn(\n            \"absolute flex h-9 w-9 items-center justify-center rounded-xl border border-dashed font-mono text-[10px] font-semibold transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-black dark:focus-visible:ring-white\",\n            q.classes,\n            quadrant === q.id\n              ? \"border-transparent opacity-0\"\n              : \"border-neutral-300 text-neutral-400 hover:border-black hover:text-black dark:border-[#2A2A2A] dark:hover:border-white dark:hover:text-white\"\n          )}\n        >\n          {q.id}\n        </button>\n      ))}\n\n      {/* Center Stage Prompt */}\n      <div className=\"text-center\">\n        <div className=\"font-mono text-[11px] font-semibold uppercase tracking-widest text-neutral-400\">\n          QUADRANT_ANCHOR // {quadrant}\n        </div>\n        <p className=\"mt-1 text-xs text-neutral-500 dark:text-neutral-400\">\n          Click any corner marker or directional button to snap pod\n        </p>\n      </div>\n\n      {/* Spring-Projected Floating Navigation Pod */}\n      <motion.div\n        layout\n        transition={\n          shouldReduceMotion\n            ? { duration: 0.01 }\n            : { type: \"spring\", stiffness, damping }\n        }\n        className={cn(\n          \"absolute z-10 flex items-center gap-1.5 rounded-2xl border border-black bg-black p-1.5 text-white shadow-lg dark:border-white dark:bg-white dark:text-black\",\n          activeSpec.classes\n        )}\n      >\n        <div className=\"flex items-center gap-1.5 px-2 font-mono text-[11px] font-bold\">\n          <Compass className=\"h-3.5 w-3.5\" />\n          <span>{quadrant}</span>\n        </div>\n\n        <div className=\"flex items-center gap-0.5 rounded-xl bg-white/15 p-0.5 dark:bg-black/10\">\n          <button\n            type=\"button\"\n            aria-label=\"Snap North-West\"\n            onClick={() => setQuadrant(\"NW\")}\n            className=\"rounded-lg p-1 hover:bg-white/20 dark:hover:bg-black/15\"\n          >\n            <CornerUpLeft className=\"h-3 w-3\" />\n          </button>\n          <button\n            type=\"button\"\n            aria-label=\"Snap North-East\"\n            onClick={() => setQuadrant(\"NE\")}\n            className=\"rounded-lg p-1 hover:bg-white/20 dark:hover:bg-black/15\"\n          >\n            <CornerUpRight className=\"h-3 w-3\" />\n          </button>\n          <button\n            type=\"button\"\n            aria-label=\"Snap South-West\"\n            onClick={() => setQuadrant(\"SW\")}\n            className=\"rounded-lg p-1 hover:bg-white/20 dark:hover:bg-black/15\"\n          >\n            <CornerDownLeft className=\"h-3 w-3\" />\n          </button>\n          <button\n            type=\"button\"\n            aria-label=\"Snap South-East\"\n            onClick={() => setQuadrant(\"SE\")}\n            className=\"rounded-lg p-1 hover:bg-white/20 dark:hover:bg-black/15\"\n          >\n            <CornerDownRight className=\"h-3 w-3\" />\n          </button>\n        </div>\n      </motion.div>\n    </div>\n  );\n}\n\nexport default FloatingCompassNav;\n",
          "type": "registry:ui",
          "target": "components/ui/floating-compass-nav.tsx"
        },
        {
          "path": "lib/utils.ts",
          "content": "import { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...inputs: ClassValue[]) {\n  return twMerge(clsx(inputs));\n}\n\nexport async function copyToClipboard(text: string): Promise<boolean> {\n  if (typeof window === \"undefined\") return false;\n\n  try {\n    if (navigator.clipboard && window.isSecureContext) {\n      await navigator.clipboard.writeText(text);\n      return true;\n    }\n\n    const textArea = document.createElement(\"textarea\");\n    textArea.value = text;\n    textArea.style.position = \"fixed\";\n    textArea.style.left = \"-999999px\";\n    textArea.style.top = \"-999999px\";\n    document.body.appendChild(textArea);\n    textArea.focus();\n    textArea.select();\n    const succeeded = document.execCommand(\"copy\");\n    textArea.remove();\n    return succeeded;\n  } catch {\n    return false;\n  }\n}\n",
          "type": "registry:lib",
          "target": "lib/utils.ts"
        }
      ]
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "floating-label-input",
      "type": "registry:ui",
      "title": "Text Field with Floating Label",
      "author": "Rishabh Bose <https://theb0se.vercel.app/>",
      "description": "Soft rounded input field with a spring-animated floating label, accent focus ring, inline clear button, password visibility toggle, and validation caption.",
      "dependencies": [
        "framer-motion",
        "lucide-react",
        "clsx",
        "tailwind-merge"
      ],
      "files": [
        {
          "path": "components/ui/floating-label-input.tsx",
          "content": "\"use client\";\n\nimport React, { useState, useId } from \"react\";\nimport { motion, useReducedMotion } from \"framer-motion\";\nimport { X, Eye, EyeOff, CheckCircle2, AlertCircle } from \"lucide-react\";\nimport { cn } from \"@/lib/utils\";\n\nexport interface FloatingLabelInputProps {\n  /** Floating label text */\n  label?: string;\n  /** Controlled input value */\n  value?: string;\n  /** Initial value for uncontrolled mode */\n  defaultValue?: string;\n  /** Callback fired when input value changes */\n  onChange?: (value: string) => void;\n  /** Input type. Default: \"text\" */\n  type?: \"text\" | \"email\" | \"password\" | \"url\";\n  /** Optional helper text below the field */\n  helperText?: string;\n  /** Optional error message (renders error ring and alert icon) */\n  error?: string;\n  /** Show clear (X) button when field has text. Default: true */\n  clearable?: boolean;\n  /** Disable input */\n  disabled?: boolean;\n  className?: string;\n}\n\nexport function FloatingLabelInput({\n  label = \"Apple ID or Email Address\",\n  value: controlledValue,\n  defaultValue = \"rishabh@boseui.com\",\n  onChange,\n  type = \"email\",\n  helperText = \"Your email is used for CLI registry authentication.\",\n  error,\n  clearable = true,\n  disabled = false,\n  className,\n}: FloatingLabelInputProps) {\n  const shouldReduceMotion = useReducedMotion() ?? false;\n  const inputId = useId();\n  const isControlled = controlledValue !== undefined;\n\n  const [internalValue, setInternalValue] = useState(defaultValue);\n  const [focused, setFocused] = useState(false);\n  const [showPassword, setShowPassword] = useState(false);\n\n  const currentValue = isControlled ? controlledValue : internalValue;\n  const isFloated = focused || currentValue.length > 0;\n\n  const updateValue = (next: string) => {\n    if (!isControlled) {\n      setInternalValue(next);\n    }\n    onChange?.(next);\n  };\n\n  const resolvedType =\n    type === \"password\" ? (showPassword ? \"text\" : \"password\") : type;\n\n  return (\n    <div className={cn(\"w-full max-w-sm\", className)}>\n      <div\n        className={cn(\n          \"relative flex h-14 w-full items-center rounded-2xl border bg-white px-4 transition-all dark:bg-[#0A0A0A]\",\n          error\n            ? \"border-red-500 ring-3 ring-red-500/15 dark:border-red-500\"\n            : focused\n              ? \"border-neutral-900 ring-3 ring-neutral-900/10 dark:border-white dark:ring-white/15\"\n              : \"border-neutral-200 hover:border-neutral-300 dark:border-neutral-800 dark:hover:border-neutral-700\",\n          disabled && \"cursor-not-allowed opacity-50\"\n        )}\n      >\n        {/* Floating Label */}\n        <motion.label\n          htmlFor={inputId}\n          initial={false}\n          animate={{\n            y: isFloated ? -10 : 0,\n            scale: isFloated ? 0.82 : 1,\n          }}\n          transition={\n            shouldReduceMotion\n              ? { duration: 0 }\n              : { type: \"spring\", stiffness: 420, damping: 30 }\n          }\n          style={{ originX: 0 }}\n          className={cn(\n            \"pointer-events-none absolute left-4 select-none text-sm font-medium transition-colors\",\n            error\n              ? \"text-red-600 dark:text-red-400\"\n              : focused\n                ? \"text-neutral-900 dark:text-white\"\n                : \"text-neutral-400 dark:text-neutral-500\"\n          )}\n        >\n          {label}\n        </motion.label>\n\n        {/* Native Input */}\n        <input\n          id={inputId}\n          type={resolvedType}\n          disabled={disabled}\n          value={currentValue}\n          onFocus={() => setFocused(true)}\n          onBlur={() => setFocused(false)}\n          onChange={(e) => updateValue(e.target.value)}\n          className=\"mt-4 w-full bg-transparent text-sm font-medium text-neutral-950 focus:outline-none disabled:cursor-not-allowed dark:text-white\"\n        />\n\n        {/* Right Controls: Clear / Password Toggle / Status */}\n        <div className=\"ml-2 flex shrink-0 items-center gap-1\">\n          {type === \"password\" && (\n            <button\n              type=\"button\"\n              aria-label={showPassword ? \"Hide password\" : \"Show password\"}\n              onClick={() => setShowPassword((v) => !v)}\n              className=\"rounded-lg p-1 text-neutral-400 transition-colors hover:bg-neutral-100 hover:text-neutral-900 dark:hover:bg-neutral-900 dark:hover:text-white\"\n            >\n              {showPassword ? (\n                <EyeOff className=\"h-4 w-4\" />\n              ) : (\n                <Eye className=\"h-4 w-4\" />\n              )}\n            </button>\n          )}\n\n          {clearable && currentValue.length > 0 && !disabled && (\n            <button\n              type=\"button\"\n              aria-label=\"Clear input\"\n              onMouseDown={(e) => e.preventDefault()}\n              onClick={() => updateValue(\"\")}\n              className=\"rounded-full bg-neutral-100 p-1 text-neutral-500 transition-colors hover:bg-neutral-200 hover:text-neutral-900 dark:bg-neutral-900 dark:text-neutral-400 dark:hover:bg-neutral-800 dark:hover:text-white\"\n            >\n              <X className=\"h-3 w-3\" />\n            </button>\n          )}\n        </div>\n      </div>\n\n      {/* Helper or Error Caption */}\n      {(error || helperText) && (\n        <div className=\"mt-1.5 flex items-center gap-1.5 px-1 text-[11px]\">\n          {error ? (\n            <>\n              <AlertCircle className=\"h-3.5 w-3.5 shrink-0 text-red-500\" />\n              <span className=\"font-medium text-red-600 dark:text-red-400\">\n                {error}\n              </span>\n            </>\n          ) : (\n            <>\n              <CheckCircle2 className=\"h-3.5 w-3.5 shrink-0 text-neutral-400\" />\n              <span className=\"text-neutral-500 dark:text-neutral-400\">\n                {helperText}\n              </span>\n            </>\n          )}\n        </div>\n      )}\n    </div>\n  );\n}\n\nexport default FloatingLabelInput;\n",
          "type": "registry:ui",
          "target": "components/ui/floating-label-input.tsx"
        },
        {
          "path": "lib/utils.ts",
          "content": "import { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...inputs: ClassValue[]) {\n  return twMerge(clsx(inputs));\n}\n\nexport async function copyToClipboard(text: string): Promise<boolean> {\n  if (typeof window === \"undefined\") return false;\n\n  try {\n    if (navigator.clipboard && window.isSecureContext) {\n      await navigator.clipboard.writeText(text);\n      return true;\n    }\n\n    const textArea = document.createElement(\"textarea\");\n    textArea.value = text;\n    textArea.style.position = \"fixed\";\n    textArea.style.left = \"-999999px\";\n    textArea.style.top = \"-999999px\";\n    document.body.appendChild(textArea);\n    textArea.focus();\n    textArea.select();\n    const succeeded = document.execCommand(\"copy\");\n    textArea.remove();\n    return succeeded;\n  } catch {\n    return false;\n  }\n}\n",
          "type": "registry:lib",
          "target": "lib/utils.ts"
        }
      ]
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "galaxy-nebula",
      "type": "registry:ui",
      "title": "Galaxy & Nebula",
      "author": "Rishabh Bose <https://theb0se.vercel.app/>",
      "description": "Real-time WebGL fragment shader rendering a rotating spiral galaxy and cosmic dust nebula using 5-octave Fractional Brownian Motion (FBM) noise.",
      "dependencies": [
        "lucide-react",
        "clsx",
        "tailwind-merge"
      ],
      "files": [
        {
          "path": "components/ui/galaxy-nebula.tsx",
          "content": "\"use client\";\n\nimport React, { useEffect, useRef, useState } from \"react\";\nimport { Sparkles } from \"lucide-react\";\nimport { cn } from \"@/lib/utils\";\n\nexport interface GalaxyNebulaProps {\n  /** Animation speed multiplier. Default: 1 */\n  speed?: number;\n  /** Spiral rotation speed. Default: 0.25 */\n  rotationSpeed?: number;\n  /** Primary nebula core hex color. Default: \"#8B5CF6\" */\n  primaryColor?: string;\n  /** Secondary outer dust hex color. Default: \"#06B6D4\" */\n  secondaryColor?: string;\n  /** Optional foreground content */\n  children?: React.ReactNode;\n  className?: string;\n}\n\nfunction hexToRgbNormalized(hex: string): [number, number, number] {\n  const clean = hex.replace(\"#\", \"\");\n  const num = parseInt(clean.length === 3 ? clean.replace(/(.)/g, \"$1$1\") : clean, 16) || 0;\n  return [((num >> 16) & 255) / 255, ((num >> 8) & 255) / 255, (num & 255) / 255];\n}\n\nconst VERTEX_SHADER = `\n  attribute vec2 position;\n  void main() {\n    gl_Position = vec4(position, 0.0, 1.0);\n  }\n`;\n\nconst FRAGMENT_SHADER = `\n  precision mediump float;\n  uniform vec2 u_resolution;\n  uniform float u_time;\n  uniform float u_rotSpeed;\n  uniform vec3 u_color1;\n  uniform vec3 u_color2;\n\n  float hash(vec2 p) {\n    p = fract(p * vec2(123.34, 456.21));\n    p += dot(p, p + 45.32);\n    return fract(p.x * p.y);\n  }\n\n  float noise(vec2 p) {\n    vec2 i = floor(p);\n    vec2 f = fract(p);\n    f = f * f * (3.0 - 2.0 * f);\n    float a = hash(i);\n    float b = hash(i + vec2(1.0, 0.0));\n    float c = hash(i + vec2(0.0, 1.0));\n    float d = hash(i + vec2(1.0, 1.0));\n    return mix(mix(a, b, f.x), mix(c, d, f.x), f.y);\n  }\n\n  float fbm(vec2 p) {\n    float v = 0.0;\n    float a = 0.5;\n    mat2 rot = mat2(cos(0.5), sin(0.5), -sin(0.5), cos(0.5));\n    for (int i = 0; i < 5; i++) {\n      v += a * noise(p);\n      p = rot * p * 2.02 + vec2(100.0);\n      a *= 0.5;\n    }\n    return v;\n  }\n\n  void main() {\n    vec2 uv = (gl_FragCoord.xy - 0.5 * u_resolution.xy) / min(u_resolution.x, u_resolution.y);\n    float r = length(uv);\n    float angle = atan(uv.y, uv.x);\n\n    // Spiral arm twist + slow rotation\n    float swirl = angle + r * 3.2 - u_time * u_rotSpeed;\n    vec2 spiralUv = vec2(cos(swirl), sin(swirl)) * r * 2.4;\n\n    float n1 = fbm(spiralUv + u_time * 0.08);\n    float n2 = fbm(spiralUv * 1.8 - u_time * 0.05 + n1);\n\n    float nebulaMask = smoothstep(0.95, 0.05, r) * (n1 * 0.65 + n2 * 0.55);\n    float coreGlow = exp(-r * 4.2);\n\n    vec3 col = mix(vec3(0.02, 0.02, 0.05), u_color2, nebulaMask);\n    col = mix(col, u_color1, clamp(n2 * nebulaMask * 1.4, 0.0, 1.0));\n    col += vec3(1.0, 0.96, 0.9) * coreGlow * 0.85;\n\n    gl_FragColor = vec4(col, 1.0);\n  }\n`;\n\nexport function GalaxyNebula({\n  speed = 1,\n  rotationSpeed = 0.25,\n  primaryColor = \"#8B5CF6\",\n  secondaryColor = \"#06B6D4\",\n  children,\n  className,\n}: GalaxyNebulaProps) {\n  const canvasRef = useRef<HTMLCanvasElement>(null);\n  const [preset, setPreset] = useState<\"Andromeda\" | \"Orion\" | \"Supernova\">(\n    \"Andromeda\"\n  );\n\n  const palettes = {\n    Andromeda: { c1: primaryColor, c2: secondaryColor },\n    Orion: { c1: \"#EC4899\", c2: \"#6366F1\" },\n    Supernova: { c1: \"#F97316\", c2: \"#8B5CF6\" },\n  };\n\n  const activePalette = palettes[preset];\n\n  useEffect(() => {\n    const canvas = canvasRef.current;\n    if (!canvas) return;\n    const gl = canvas.getContext(\"webgl\");\n    if (!gl) return;\n\n    const compile = (type: number, src: string) => {\n      const sh = gl.createShader(type);\n      if (!sh) return null;\n      gl.shaderSource(sh, src);\n      gl.compileShader(sh);\n      return sh;\n    };\n\n    const vs = compile(gl.VERTEX_SHADER, VERTEX_SHADER);\n    const fs = compile(gl.FRAGMENT_SHADER, FRAGMENT_SHADER);\n    if (!vs || !fs) return;\n\n    const prog = gl.createProgram();\n    if (!prog) return;\n    gl.attachShader(prog, vs);\n    gl.attachShader(prog, fs);\n    gl.linkProgram(prog);\n    gl.useProgram(prog);\n\n    const buf = gl.createBuffer();\n    gl.bindBuffer(gl.ARRAY_BUFFER, buf);\n    gl.bufferData(\n      gl.ARRAY_BUFFER,\n      new Float32Array([-1, -1, 1, -1, -1, 1, -1, 1, 1, -1, 1, 1]),\n      gl.STATIC_DRAW\n    );\n\n    const posLoc = gl.getAttribLocation(prog, \"position\");\n    gl.enableVertexAttribArray(posLoc);\n    gl.vertexAttribPointer(posLoc, 2, gl.FLOAT, false, 0, 0);\n\n    const uRes = gl.getUniformLocation(prog, \"u_resolution\");\n    const uTime = gl.getUniformLocation(prog, \"u_time\");\n    const uRot = gl.getUniformLocation(prog, \"u_rotSpeed\");\n    const uCol1 = gl.getUniformLocation(prog, \"u_color1\");\n    const uCol2 = gl.getUniformLocation(prog, \"u_color2\");\n\n    const rgb1 = hexToRgbNormalized(activePalette.c1);\n    const rgb2 = hexToRgbNormalized(activePalette.c2);\n\n    let rafId: number;\n    const start = performance.now();\n\n    const render = (now: number) => {\n      const w = (canvas.width = canvas.offsetWidth || 600);\n      const h = (canvas.height = canvas.offsetHeight || 360);\n      gl.viewport(0, 0, w, h);\n\n      gl.uniform2f(uRes, w, h);\n      gl.uniform1f(uTime, ((now - start) * 0.001) * speed);\n      gl.uniform1f(uRot, rotationSpeed);\n      gl.uniform3f(uCol1, rgb1[0], rgb1[1], rgb1[2]);\n      gl.uniform3f(uCol2, rgb2[0], rgb2[1], rgb2[2]);\n\n      gl.drawArrays(gl.TRIANGLES, 0, 6);\n      rafId = requestAnimationFrame(render);\n    };\n\n    rafId = requestAnimationFrame(render);\n    return () => cancelAnimationFrame(rafId);\n  }, [speed, rotationSpeed, activePalette.c1, activePalette.c2]);\n\n  return (\n    <div\n      data-fullscreen-scroll\n      className={cn(\n        \"relative flex min-h-[360px] w-full flex-col justify-between overflow-hidden rounded-3xl border border-neutral-800 bg-[#05050D] p-6 text-white shadow-sm\",\n        className\n      )}\n    >\n      <canvas\n        ref={canvasRef}\n        aria-hidden=\"true\"\n        className=\"pointer-events-none absolute inset-0 h-full w-full\"\n      />\n\n      <div className=\"relative z-10 flex flex-1 flex-col justify-between\">\n        {children ?? (\n          <>\n            <div className=\"flex flex-wrap items-center justify-between gap-2\">\n              <span className=\"inline-flex items-center gap-1.5 rounded-full border border-white/15 bg-black/40 px-3 py-1 font-mono text-[11px] font-medium text-white backdrop-blur-md\">\n                <Sparkles className=\"h-3.5 w-3.5 text-violet-300\" />\n                WebGL FBM Nebula\n              </span>\n\n              <div className=\"flex items-center gap-1 rounded-full border border-white/15 bg-black/40 p-1 backdrop-blur-md\">\n                {([\"Andromeda\", \"Orion\", \"Supernova\"] as const).map((name) => (\n                  <button\n                    key={name}\n                    type=\"button\"\n                    onClick={() => setPreset(name)}\n                    className={cn(\n                      \"rounded-full px-2.5 py-0.5 font-mono text-[10px] font-semibold transition-colors\",\n                      preset === name\n                        ? \"bg-white text-black\"\n                        : \"text-white/75 hover:text-white\"\n                    )}\n                  >\n                    {name}\n                  </button>\n                ))}\n              </div>\n            </div>\n\n            <div className=\"my-auto max-w-md py-8\">\n              <h3 className=\"text-2xl font-bold tracking-tight text-white drop-shadow-sm sm:text-3xl\">\n                Spiral Galaxy & FBM Nebula\n              </h3>\n              <p className=\"mt-2 text-xs leading-relaxed text-white/80 sm:text-sm\">\n                Real-time WebGL fragment shader computing 5-octave Fractional\n                Brownian Motion (<code className=\"font-mono\">fbm</code>) with\n                polar spiral distortion.\n              </p>\n            </div>\n\n            <div className=\"font-mono text-[11px] text-white/55\">\n              GLSL Fragment Shader · 5-Octave FBM Noise · Spiral Swirl\n            </div>\n          </>\n        )}\n      </div>\n    </div>\n  );\n}\n\nexport default GalaxyNebula;\n",
          "type": "registry:ui",
          "target": "components/ui/galaxy-nebula.tsx"
        },
        {
          "path": "lib/utils.ts",
          "content": "import { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...inputs: ClassValue[]) {\n  return twMerge(clsx(inputs));\n}\n\nexport async function copyToClipboard(text: string): Promise<boolean> {\n  if (typeof window === \"undefined\") return false;\n\n  try {\n    if (navigator.clipboard && window.isSecureContext) {\n      await navigator.clipboard.writeText(text);\n      return true;\n    }\n\n    const textArea = document.createElement(\"textarea\");\n    textArea.value = text;\n    textArea.style.position = \"fixed\";\n    textArea.style.left = \"-999999px\";\n    textArea.style.top = \"-999999px\";\n    document.body.appendChild(textArea);\n    textArea.focus();\n    textArea.select();\n    const succeeded = document.execCommand(\"copy\");\n    textArea.remove();\n    return succeeded;\n  } catch {\n    return false;\n  }\n}\n",
          "type": "registry:lib",
          "target": "lib/utils.ts"
        }
      ]
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "globe-arcs",
      "type": "registry:ui",
      "title": "Globe Arcs",
      "author": "Rishabh Bose <https://theb0se.vercel.app/>",
      "description": "Interactive 3D dotted Canvas globe featuring glowing multi-point transaction flight arcs, traveling light pulses, drag-to-rotate interaction with inertia dampening, and global city routing nodes.",
      "dependencies": [
        "framer-motion",
        "lucide-react",
        "clsx",
        "tailwind-merge"
      ],
      "files": [
        {
          "path": "components/ui/globe-arcs.tsx",
          "content": "\"use client\";\n\nimport React, { useRef, useEffect, useState, useCallback } from \"react\";\nimport { motion } from \"framer-motion\";\nimport {\n  Globe,\n  RotateCcw,\n  Play,\n  Pause,\n  Zap,\n  Sparkles,\n  Sliders,\n  MapPin,\n  Send,\n} from \"lucide-react\";\nimport { cn } from \"@/lib/utils\";\n\ninterface City {\n  name: string;\n  lat: number;\n  lon: number;\n  region: string;\n}\n\nconst CITIES: City[] = [\n  { name: \"San Francisco\", lat: 37.77, lon: -122.42, region: \"US-West\" },\n  { name: \"New York\", lat: 40.71, lon: -74.01, region: \"US-East\" },\n  { name: \"London\", lat: 51.51, lon: -0.13, region: \"EU-West\" },\n  { name: \"Tokyo\", lat: 35.68, lon: 139.65, region: \"AP-North\" },\n  { name: \"Singapore\", lat: 1.35, lon: 103.82, region: \"AP-South\" },\n  { name: \"Sydney\", lat: -33.87, lon: 151.21, region: \"AP-East\" },\n];\n\ninterface ArcRoute {\n  from: City;\n  to: City;\n  color: string;\n  speedMultiplier: number;\n}\n\nconst ROUTES: ArcRoute[] = [\n  { from: CITIES[0], to: CITIES[1], color: \"#6366f1\", speedMultiplier: 1.0 }, // SF -> NY\n  { from: CITIES[1], to: CITIES[2], color: \"#a855f7\", speedMultiplier: 0.9 }, // NY -> London\n  { from: CITIES[2], to: CITIES[4], color: \"#06b6d4\", speedMultiplier: 1.1 }, // London -> Singapore\n  { from: CITIES[4], to: CITIES[3], color: \"#10b981\", speedMultiplier: 1.3 }, // Singapore -> Tokyo\n  { from: CITIES[3], to: CITIES[0], color: \"#f59e0b\", speedMultiplier: 0.8 }, // Tokyo -> SF\n  { from: CITIES[4], to: CITIES[5], color: \"#ec4899\", speedMultiplier: 1.2 }, // Singapore -> Sydney\n];\n\n// Generate dot coordinates on sphere\nfunction generateSphereDots(count: number = 720) {\n  const dots: { x: number; y: number; z: number }[] = [];\n  const phi = (Math.PI * (3 - Math.sqrt(5))); // golden angle\n\n  for (let i = 0; i < count; i++) {\n    const y = 1 - (i / (count - 1)) * 2; // y goes from 1 to -1\n    const radius = Math.sqrt(1 - y * y); // radius at y\n    const theta = phi * i; // golden angle increment\n\n    const x = Math.cos(theta) * radius;\n    const z = Math.sin(theta) * radius;\n    dots.push({ x, y, z });\n  }\n  return dots;\n}\n\nfunction latLonTo3D(lat: number, lon: number, radius: number) {\n  const phi = (90 - lat) * (Math.PI / 180);\n  const theta = (lon + 180) * (Math.PI / 180);\n  return {\n    x: -(radius * Math.sin(phi) * Math.cos(theta)),\n    y: radius * Math.cos(phi),\n    z: radius * Math.sin(phi) * Math.sin(theta),\n  };\n}\n\nexport interface GlobeArcsProps {\n  className?: string;\n  autoRotateSpeed?: number;\n  initialRadius?: number;\n  showHeader?: boolean;\n  showControls?: boolean;\n}\n\nexport function GlobeArcs({\n  className,\n  autoRotateSpeed = 0.004,\n  initialRadius = 160,\n  showHeader = true,\n  showControls = true,\n}: GlobeArcsProps) {\n  const canvasRef = useRef<HTMLCanvasElement | null>(null);\n  const isDragging = useRef(false);\n  const lastMousePos = useRef<{ x: number; y: number }>({ x: 0, y: 0 });\n  const rotVelocity = useRef<{ x: number; y: number }>({ x: 0, y: 0 });\n  const rotation = useRef<{ x: number; y: number }>({ x: 0.25, y: -0.8 });\n  const animFrameId = useRef<number | null>(null);\n\n  const [isRotating, setIsRotating] = useState(true);\n  const [speed, setSpeed] = useState(autoRotateSpeed);\n  const [activeCity, setActiveCity] = useState<City>(CITIES[0]);\n  const [transactionCount, setTransactionCount] = useState(14820);\n\n  const sphereDots = useRef(generateSphereDots(820));\n\n  const resetOrientation = () => {\n    rotation.current = { x: 0.25, y: -0.8 };\n    rotVelocity.current = { x: 0, y: 0 };\n  };\n\n  const triggerTransaction = () => {\n    setTransactionCount((prev) => prev + 1);\n    const randomCity = CITIES[Math.floor(Math.random() * CITIES.length)];\n    setActiveCity(randomCity);\n  };\n\n  useEffect(() => {\n    const canvas = canvasRef.current;\n    if (!canvas) return;\n    const ctx = canvas.getContext(\"2d\");\n    if (!ctx) return;\n\n    let time = 0;\n\n    const render = () => {\n      time += 0.015;\n\n      const rect = canvas.getBoundingClientRect();\n      const dpr = window.devicePixelRatio || 1;\n      const width = rect.width;\n      const height = rect.height;\n\n      if (canvas.width !== width * dpr || canvas.height !== height * dpr) {\n        canvas.width = width * dpr;\n        canvas.height = height * dpr;\n      }\n\n      ctx.save();\n      ctx.scale(dpr, dpr);\n      ctx.clearRect(0, 0, width, height);\n\n      const centerX = width / 2;\n      const centerY = height / 2;\n      const R = Math.min(width, height) * 0.36;\n\n      // Handle drag inertia & continuous rotation\n      if (isRotating && !isDragging.current) {\n        rotation.current.y += speed;\n      }\n\n      if (!isDragging.current) {\n        rotation.current.y += rotVelocity.current.y;\n        rotation.current.x += rotVelocity.current.x;\n        rotVelocity.current.x *= 0.92;\n        rotVelocity.current.y *= 0.92;\n      }\n\n      // Clamp X rotation to prevent flipping upside down\n      rotation.current.x = Math.max(-1.1, Math.min(1.1, rotation.current.x));\n\n      const cosX = Math.cos(rotation.current.x);\n      const sinX = Math.sin(rotation.current.x);\n      const cosY = Math.cos(rotation.current.y);\n      const sinY = Math.sin(rotation.current.y);\n\n      // Rotate point helper\n      const project = (x: number, y: number, z: number) => {\n        // Rotate around Y\n        const x1 = x * cosY - z * sinY;\n        const z1 = z * cosY + x * sinY;\n        // Rotate around X\n        const y2 = y * cosX - z1 * sinX;\n        const z2 = z1 * cosX + y * sinX;\n\n        return {\n          px: centerX + x1,\n          py: centerY - y2,\n          pz: z2,\n        };\n      };\n\n      // Draw Atmospheric outer glow\n      const atmosphereGrad = ctx.createRadialGradient(\n        centerX,\n        centerY,\n        R * 0.85,\n        centerX,\n        centerY,\n        R * 1.25\n      );\n      atmosphereGrad.addColorStop(0, \"rgba(99, 102, 241, 0.08)\");\n      atmosphereGrad.addColorStop(0.6, \"rgba(6, 182, 212, 0.04)\");\n      atmosphereGrad.addColorStop(1, \"transparent\");\n      ctx.fillStyle = atmosphereGrad;\n      ctx.beginPath();\n      ctx.arc(centerX, centerY, R * 1.3, 0, Math.PI * 2);\n      ctx.fill();\n\n      // Draw Globe Base Sphere Fill (Dark midnight)\n      const baseGrad = ctx.createRadialGradient(\n        centerX - R * 0.3,\n        centerY - R * 0.3,\n        R * 0.1,\n        centerX,\n        centerY,\n        R\n      );\n      baseGrad.addColorStop(0, \"#0e1329\");\n      baseGrad.addColorStop(0.7, \"#080b18\");\n      baseGrad.addColorStop(1, \"#030409\");\n      ctx.fillStyle = baseGrad;\n      ctx.beginPath();\n      ctx.arc(centerX, centerY, R, 0, Math.PI * 2);\n      ctx.fill();\n\n      // Draw Globe Dotted Point Cloud\n      for (const dot of sphereDots.current) {\n        const { px, py, pz } = project(dot.x * R, dot.y * R, dot.z * R);\n        if (pz > -R * 0.2) {\n          const alpha = (pz + R * 0.2) / (R * 1.2);\n          const size = Math.max(0.75, (pz + R) / (R * 1.2) * 1.4);\n          ctx.fillStyle = `rgba(148, 163, 184, ${alpha * 0.45})`;\n          ctx.beginPath();\n          ctx.arc(px, py, size, 0, Math.PI * 2);\n          ctx.fill();\n        }\n      }\n\n      // Draw Great-Circle Arcs & Traveling Pulse Lights\n      ROUTES.forEach((route, routeIdx) => {\n        const p1_3d = latLonTo3D(route.from.lat, route.from.lon, R);\n        const p2_3d = latLonTo3D(route.to.lat, route.to.lon, R);\n\n        const steps = 36;\n        const arcPoints: { px: number; py: number; pz: number }[] = [];\n\n        for (let i = 0; i <= steps; i++) {\n          const t = i / steps;\n          // Linear blend then normalize to sphere + elevation arc\n          const lx = p1_3d.x + (p2_3d.x - p1_3d.x) * t;\n          const ly = p1_3d.y + (p2_3d.y - p1_3d.y) * t;\n          const lz = p1_3d.z + (p2_3d.z - p1_3d.z) * t;\n          const mag = Math.sqrt(lx * lx + ly * ly + lz * lz) || 1;\n\n          // Arc height peaking at t = 0.5\n          const heightMultiplier = 1 + 0.24 * Math.sin(t * Math.PI);\n          const elevatedR = R * heightMultiplier;\n\n          const ax = (lx / mag) * elevatedR;\n          const ay = (ly / mag) * elevatedR;\n          const az = (lz / mag) * elevatedR;\n\n          arcPoints.push(project(ax, ay, az));\n        }\n\n        // Stroke the Arc\n        ctx.beginPath();\n        let firstVisible = false;\n        arcPoints.forEach((pt, i) => {\n          if (pt.pz > -R * 0.3) {\n            if (!firstVisible) {\n              ctx.moveTo(pt.px, pt.py);\n              firstVisible = true;\n            } else {\n              ctx.lineTo(pt.px, pt.py);\n            }\n          }\n        });\n\n        ctx.strokeStyle = route.color + \"55\"; // translucent trail\n        ctx.lineWidth = 1.4;\n        ctx.stroke();\n\n        // Traveling Light Pulse Head\n        const pulseT = ((time * route.speedMultiplier * 0.4) + routeIdx * 0.18) % 1;\n        const pulseIndex = Math.floor(pulseT * steps);\n        const pulsePt = arcPoints[pulseIndex];\n\n        if (pulsePt && pulsePt.pz > -R * 0.1) {\n          // Glow halo\n          const glow = ctx.createRadialGradient(\n            pulsePt.px,\n            pulsePt.py,\n            0,\n            pulsePt.px,\n            pulsePt.py,\n            9\n          );\n          glow.addColorStop(0, \"#ffffff\");\n          glow.addColorStop(0.4, route.color);\n          glow.addColorStop(1, \"transparent\");\n          ctx.fillStyle = glow;\n          ctx.beginPath();\n          ctx.arc(pulsePt.px, pulsePt.py, 9, 0, Math.PI * 2);\n          ctx.fill();\n\n          // Core point\n          ctx.fillStyle = \"#ffffff\";\n          ctx.beginPath();\n          ctx.arc(pulsePt.px, pulsePt.py, 2.2, 0, Math.PI * 2);\n          ctx.fill();\n        }\n      });\n\n      // Draw Cities\n      CITIES.forEach((city) => {\n        const c3d = latLonTo3D(city.lat, city.lon, R);\n        const { px, py, pz } = project(c3d.x, c3d.y, c3d.z);\n\n        if (pz > 0) {\n          const isSelected = activeCity.name === city.name;\n\n          // Pulsing City Ring\n          const ringRadius = isSelected ? 6 + Math.sin(time * 5) * 2 : 4;\n          ctx.strokeStyle = isSelected ? \"#38bdf8\" : \"rgba(255, 255, 255, 0.6)\";\n          ctx.lineWidth = 1.2;\n          ctx.beginPath();\n          ctx.arc(px, py, ringRadius, 0, Math.PI * 2);\n          ctx.stroke();\n\n          // City Dot Core\n          ctx.fillStyle = isSelected ? \"#38bdf8\" : \"#ffffff\";\n          ctx.beginPath();\n          ctx.arc(px, py, 2.2, 0, Math.PI * 2);\n          ctx.fill();\n\n          // City Label\n          ctx.fillStyle = isSelected ? \"#ffffff\" : \"rgba(226, 232, 240, 0.75)\";\n          ctx.font = isSelected\n            ? \"bold 10px ui-sans-serif, system-ui, sans-serif\"\n            : \"9px ui-sans-serif, system-ui, sans-serif\";\n          ctx.fillText(city.name, px + 8, py + 3);\n        }\n      });\n\n      ctx.restore();\n      animFrameId.current = requestAnimationFrame(render);\n    };\n\n    render();\n\n    return () => {\n      if (animFrameId.current) cancelAnimationFrame(animFrameId.current);\n    };\n  }, [speed, isRotating, activeCity]);\n\n  // Pointer drag interactions\n  const handlePointerDown = (e: React.PointerEvent) => {\n    isDragging.current = true;\n    lastMousePos.current = { x: e.clientX, y: e.clientY };\n  };\n\n  const handlePointerMove = (e: React.PointerEvent) => {\n    if (!isDragging.current) return;\n    const dx = e.clientX - lastMousePos.current.x;\n    const dy = e.clientY - lastMousePos.current.y;\n\n    rotation.current.y += dx * 0.006;\n    rotation.current.x -= dy * 0.006;\n\n    rotVelocity.current = { x: -dy * 0.002, y: dx * 0.002 };\n    lastMousePos.current = { x: e.clientX, y: e.clientY };\n  };\n\n  const handlePointerUp = () => {\n    isDragging.current = false;\n  };\n\n  return (\n    <div\n      data-fullscreen-scroll\n      className={cn(\n        \"relative w-full min-h-[520px] overflow-hidden rounded-2xl border border-neutral-800 bg-[#050711] text-white flex flex-col justify-between shadow-2xl selection:bg-indigo-500/30\",\n        className\n      )}\n    >\n      {/* Top Header Overlay */}\n      {showHeader && (\n        <div className=\"relative z-10 p-6 flex flex-wrap items-center justify-between gap-4 pointer-events-none\">\n          <div>\n            <div className=\"flex items-center gap-2\">\n              <div className=\"h-7 w-7 rounded-lg bg-indigo-600/20 border border-indigo-500/40 flex items-center justify-center\">\n                <Globe className=\"h-4 w-4 text-indigo-400\" />\n              </div>\n              <h2 className=\"text-lg font-semibold tracking-tight text-white\">\n                Global Transaction Arcs\n              </h2>\n            </div>\n            <p className=\"text-xs text-neutral-400 mt-1\">\n              Real-time inter-continental payment routing across Tier-1 datacenters\n            </p>\n          </div>\n\n          {/* Live Transaction Pill */}\n          <div className=\"pointer-events-auto flex items-center gap-3 bg-neutral-900/80 border border-neutral-800 px-3.5 py-1.5 rounded-full backdrop-blur-md shadow-lg\">\n            <span className=\"flex h-2 w-2 rounded-full bg-emerald-400 animate-pulse\" />\n            <span className=\"text-xs font-mono text-neutral-300\">\n              {transactionCount.toLocaleString()} Settled\n            </span>\n            <button\n              onClick={triggerTransaction}\n              className=\"flex items-center gap-1 text-[11px] font-medium text-indigo-300 hover:text-white px-2 py-0.5 rounded bg-indigo-600/30 hover:bg-indigo-600/50 transition-colors\"\n            >\n              <Send className=\"h-3 w-3\" />\n              <span>Emit Pulse</span>\n            </button>\n          </div>\n        </div>\n      )}\n\n      {/* Interactive 3D Dotted Canvas */}\n      <div\n        className=\"relative flex-1 w-full flex items-center justify-center cursor-grab active:cursor-grabbing touch-none select-none\"\n        onPointerDown={handlePointerDown}\n        onPointerMove={handlePointerMove}\n        onPointerUp={handlePointerUp}\n        onPointerLeave={handlePointerUp}\n      >\n        <canvas\n          ref={canvasRef}\n          className=\"w-full h-full min-h-[360px]\"\n          style={{ width: \"100%\", height: \"100%\" }}\n        />\n\n        {/* Floating City Card Overlay */}\n        <div className=\"absolute bottom-6 left-6 z-10 bg-neutral-900/80 border border-neutral-800/90 rounded-xl p-3 backdrop-blur-md text-xs shadow-xl hidden sm:block\">\n          <div className=\"flex items-center gap-1.5 text-neutral-400 font-mono text-[11px]\">\n            <MapPin className=\"h-3.5 w-3.5 text-indigo-400\" />\n            <span>Active Edge Node</span>\n          </div>\n          <div className=\"font-semibold text-white mt-0.5\">{activeCity.name}</div>\n          <div className=\"text-[10px] text-indigo-300 font-mono\">{activeCity.region} &bull; 1.8ms RTT</div>\n        </div>\n      </div>\n\n      {/* Interactive Controls Stage Footer */}\n      {showControls && (\n        <div className=\"relative z-10 px-6 py-4 border-t border-neutral-800/80 bg-neutral-950/80 backdrop-blur-md flex flex-wrap items-center justify-between gap-4 text-xs\">\n          <div className=\"flex flex-wrap items-center gap-2\">\n            <span className=\"text-neutral-400 font-medium\">Focus Node:</span>\n            {CITIES.map((c) => (\n              <button\n                key={c.name}\n                onClick={() => setActiveCity(c)}\n                className={cn(\n                  \"px-2.5 py-1 rounded text-xs transition-colors\",\n                  activeCity.name === c.name\n                    ? \"bg-indigo-600 text-white font-semibold\"\n                    : \"bg-neutral-800/70 text-neutral-400 hover:text-white\"\n                )}\n              >\n                {c.name}\n              </button>\n            ))}\n          </div>\n\n          <div className=\"flex flex-wrap items-center gap-4 text-neutral-400\">\n            <div className=\"flex items-center gap-2\">\n              <span>Spin Speed:</span>\n              <input\n                type=\"range\"\n                min=\"0.001\"\n                max=\"0.015\"\n                step=\"0.001\"\n                value={speed}\n                onChange={(e) => setSpeed(Number(e.target.value))}\n                className=\"w-20 accent-indigo-500\"\n              />\n            </div>\n\n            <button\n              onClick={() => setIsRotating(!isRotating)}\n              className={cn(\n                \"p-1.5 rounded-lg border transition-colors flex items-center gap-1 text-xs\",\n                isRotating\n                  ? \"bg-indigo-500/20 border-indigo-500/40 text-indigo-300\"\n                  : \"bg-neutral-800/60 border-neutral-700 text-neutral-400\"\n              )}\n              title={isRotating ? \"Pause auto-rotation\" : \"Resume auto-rotation\"}\n            >\n              {isRotating ? <Pause className=\"h-3.5 w-3.5\" /> : <Play className=\"h-3.5 w-3.5\" />}\n              <span>{isRotating ? \"Auto-Spin: ON\" : \"Paused\"}</span>\n            </button>\n\n            <button\n              onClick={resetOrientation}\n              className=\"p-1.5 rounded-lg border border-neutral-700 bg-neutral-800/60 text-neutral-400 hover:text-white transition-colors\"\n              title=\"Reset sphere orientation\"\n            >\n              <RotateCcw className=\"h-3.5 w-3.5\" />\n            </button>\n          </div>\n        </div>\n      )}\n    </div>\n  );\n}\n\nexport default GlobeArcs;\n",
          "type": "registry:ui",
          "target": "components/ui/globe-arcs.tsx"
        },
        {
          "path": "lib/utils.ts",
          "content": "import { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...inputs: ClassValue[]) {\n  return twMerge(clsx(inputs));\n}\n\nexport async function copyToClipboard(text: string): Promise<boolean> {\n  if (typeof window === \"undefined\") return false;\n\n  try {\n    if (navigator.clipboard && window.isSecureContext) {\n      await navigator.clipboard.writeText(text);\n      return true;\n    }\n\n    const textArea = document.createElement(\"textarea\");\n    textArea.value = text;\n    textArea.style.position = \"fixed\";\n    textArea.style.left = \"-999999px\";\n    textArea.style.top = \"-999999px\";\n    document.body.appendChild(textArea);\n    textArea.focus();\n    textArea.select();\n    const succeeded = document.execCommand(\"copy\");\n    textArea.remove();\n    return succeeded;\n  } catch {\n    return false;\n  }\n}\n",
          "type": "registry:lib",
          "target": "lib/utils.ts"
        }
      ]
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "glow-border-card",
      "type": "registry:ui",
      "title": "Glow Border Card",
      "author": "Rishabh Bose <https://theb0se.vercel.app/>",
      "description": "High-gloss feature cards with thin glowing gradient borders and interactive face overlays that dynamically illuminate and follow cursor coordinates using radial gradient masking.",
      "dependencies": [
        "framer-motion",
        "lucide-react",
        "clsx",
        "tailwind-merge"
      ],
      "files": [
        {
          "path": "components/ui/glow-border-card.tsx",
          "content": "\"use client\";\n\nimport React, { useState, useRef } from \"react\";\nimport { motion } from \"framer-motion\";\nimport {\n  ShieldCheck,\n  Globe2,\n  Sparkles,\n  Cpu,\n  ArrowUpRight,\n  Zap,\n  Sliders,\n  CheckCircle,\n  Layers,\n} from \"lucide-react\";\nimport { cn } from \"@/lib/utils\";\n\nexport interface GlowPalette {\n  id: string;\n  name: string;\n  gradient: string;\n  glowColor: string;\n  accentText: string;\n  badgeBg: string;\n}\n\nconst GLOW_PALETTES: GlowPalette[] = [\n  {\n    id: \"stripe-indigo\",\n    name: \"Stripe Indigo / Cyan\",\n    gradient: \"linear-gradient(135deg, #6366f1, #06b6d4)\",\n    glowColor: \"rgba(99, 102, 241, 0.45)\",\n    accentText: \"text-indigo-400\",\n    badgeBg: \"bg-indigo-500/10 border-indigo-500/20 text-indigo-300\",\n  },\n  {\n    id: \"electric-violet\",\n    name: \"Electric Violet\",\n    gradient: \"linear-gradient(135deg, #a855f7, #ec4899)\",\n    glowColor: \"rgba(168, 85, 247, 0.45)\",\n    accentText: \"text-purple-400\",\n    badgeBg: \"bg-purple-500/10 border-purple-500/20 text-purple-300\",\n  },\n  {\n    id: \"emerald-glow\",\n    name: \"Emerald Glow\",\n    gradient: \"linear-gradient(135deg, #10b981, #14b8a6)\",\n    glowColor: \"rgba(16, 185, 129, 0.45)\",\n    accentText: \"text-emerald-400\",\n    badgeBg: \"bg-emerald-500/10 border-emerald-500/20 text-emerald-300\",\n  },\n  {\n    id: \"golden-amber\",\n    name: \"Golden Amber\",\n    gradient: \"linear-gradient(135deg, #f59e0b, #f43f5e)\",\n    glowColor: \"rgba(245, 158, 11, 0.45)\",\n    accentText: \"text-amber-400\",\n    badgeBg: \"bg-amber-500/10 border-amber-500/20 text-amber-300\",\n  },\n];\n\ninterface FeatureCardItem {\n  id: string;\n  badge: string;\n  icon: React.ReactNode;\n  title: string;\n  description: string;\n  metric: string;\n  metricLabel: string;\n}\n\nconst CARD_DATA: FeatureCardItem[] = [\n  {\n    id: \"radar\",\n    badge: \"Machine Learning\",\n    icon: <ShieldCheck className=\"h-5 w-5\" />,\n    title: \"Adaptive 3D Secure\",\n    description:\n      \"Dynamically routes authentications through frictionless SCA exemptions, reducing checkout abandonment by 24%.\",\n    metric: \"99.8%\",\n    metricLabel: \"Fraud prevention accuracy\",\n  },\n  {\n    id: \"payouts\",\n    badge: \"Global Rails\",\n    icon: <Globe2 className=\"h-5 w-5\" />,\n    title: \"Instant Global Payouts\",\n    description:\n      \"Disburse funds in 45+ currencies to linked debit cards and domestic accounts with sub-second finality.\",\n    metric: \"135+\",\n    metricLabel: \"Supported currencies\",\n  },\n  {\n    id: \"dunning\",\n    badge: \"Revenue Recovery\",\n    icon: <Sparkles className=\"h-5 w-5\" />,\n    title: \"Smart Retry Dunning\",\n    description:\n      \"Recovers up to 43% of failed recurring billing renewals with adaptive timing and network token synchronization.\",\n    metric: \"43%\",\n    metricLabel: \"Average recovered ARR\",\n  },\n  {\n    id: \"unified-api\",\n    badge: \"Unified Schema\",\n    icon: <Cpu className=\"h-5 w-5\" />,\n    title: \"Unified Webhook Fabric\",\n    description:\n      \"Single declarative schema syncing subscriptions, dispute events, and balance updates across your tech stack.\",\n    metric: \"0.2ms\",\n    metricLabel: \"Event dispatch latency\",\n  },\n];\n\nexport interface GlowBorderCardProps {\n  className?: string;\n  defaultRadius?: number;\n  defaultIntensity?: number;\n}\n\nexport function GlowBorderCard({\n  className,\n  defaultRadius = 280,\n  defaultIntensity = 0.5,\n}: GlowBorderCardProps) {\n  const [selectedPalette, setSelectedPalette] = useState<string>(\"stripe-indigo\");\n  const [radius, setRadius] = useState<number>(defaultRadius);\n  const [intensity, setIntensity] = useState<number>(defaultIntensity);\n  const [enableLift, setEnableLift] = useState<boolean>(true);\n\n  const activePalette =\n    GLOW_PALETTES.find((p) => p.id === selectedPalette) || GLOW_PALETTES[0];\n\n  return (\n    <div\n      data-fullscreen-scroll\n      className={cn(\n        \"relative w-full min-h-[520px] overflow-hidden rounded-2xl border border-neutral-800 bg-[#070913] p-6 text-white flex flex-col justify-between shadow-2xl selection:bg-indigo-500/30\",\n        className\n      )}\n    >\n      {/* Background ambient lighting */}\n      <div className=\"pointer-events-none absolute inset-0 overflow-hidden\">\n        <div className=\"absolute top-0 right-1/4 h-96 w-96 rounded-full bg-indigo-600/10 blur-[130px]\" />\n        <div className=\"absolute bottom-0 left-1/4 h-80 w-80 rounded-full bg-cyan-600/10 blur-[120px]\" />\n      </div>\n\n      {/* Header Section */}\n      <div className=\"relative z-10 max-w-2xl mb-8\">\n        <div className=\"flex items-center gap-2 mb-2\">\n          <div className=\"h-6 w-6 rounded-md bg-indigo-500/20 border border-indigo-500/30 flex items-center justify-center\">\n            <Layers className=\"h-3.5 w-3.5 text-indigo-400\" />\n          </div>\n          <span className=\"text-xs font-semibold tracking-wider uppercase text-neutral-400\">\n            Reactive Pointer Illumination\n          </span>\n        </div>\n        <h2 className=\"text-2xl sm:text-3xl font-bold tracking-tight text-white\">\n          High-Gloss Glow Border Cards\n        </h2>\n        <p className=\"mt-1.5 text-xs sm:text-sm text-neutral-400 leading-relaxed\">\n          Stripe-style dynamic radial masking that traces cursor movement across borders and faces with zero layout reflow.\n        </p>\n      </div>\n\n      {/* Grid of Glow Border Cards */}\n      <div className=\"relative z-10 grid grid-cols-1 md:grid-cols-2 gap-5 max-w-5xl mx-auto w-full mb-6\">\n        {CARD_DATA.map((card) => (\n          <SingleGlowCard\n            key={card.id}\n            card={card}\n            palette={activePalette}\n            radius={radius}\n            intensity={intensity}\n            enableLift={enableLift}\n          />\n        ))}\n      </div>\n\n      {/* Interactive Controls Stage Footer */}\n      <div className=\"relative z-20 mt-4 pt-4 border-t border-neutral-800/80 bg-neutral-950/80 backdrop-blur-md -mx-6 -mb-6 px-6 py-4 flex flex-wrap items-center justify-between gap-4 text-xs\">\n        {/* Palette Buttons */}\n        <div className=\"flex flex-wrap items-center gap-2\">\n          <span className=\"text-neutral-400 font-medium flex items-center gap-1.5\">\n            <Sliders className=\"h-3.5 w-3.5 text-indigo-400\" />\n            Theme:\n          </span>\n          {GLOW_PALETTES.map((pal) => (\n            <button\n              key={pal.id}\n              onClick={() => setSelectedPalette(pal.id)}\n              className={cn(\n                \"px-2.5 py-1 rounded-md text-xs font-medium transition-colors\",\n                selectedPalette === pal.id\n                  ? \"bg-indigo-600 text-white font-semibold shadow-md shadow-indigo-600/30\"\n                  : \"bg-neutral-800/80 text-neutral-400 hover:text-white\"\n              )}\n            >\n              {pal.name}\n            </button>\n          ))}\n        </div>\n\n        {/* Sliders: Radius & Intensity */}\n        <div className=\"flex flex-wrap items-center gap-4 text-neutral-400\">\n          <div className=\"flex items-center gap-2\">\n            <span>Glow Radius ({radius}px):</span>\n            <input\n              type=\"range\"\n              min=\"160\"\n              max=\"450\"\n              value={radius}\n              onChange={(e) => setRadius(Number(e.target.value))}\n              className=\"w-20 accent-indigo-500\"\n            />\n          </div>\n\n          <div className=\"flex items-center gap-2\">\n            <span>Intensity ({Math.round(intensity * 100)}%):</span>\n            <input\n              type=\"range\"\n              min=\"0.2\"\n              max=\"1.0\"\n              step=\"0.05\"\n              value={intensity}\n              onChange={(e) => setIntensity(Number(e.target.value))}\n              className=\"w-20 accent-indigo-500\"\n            />\n          </div>\n\n          <button\n            onClick={() => setEnableLift(!enableLift)}\n            className={cn(\n              \"px-2.5 py-1 rounded border text-xs font-medium transition-colors\",\n              enableLift\n                ? \"bg-indigo-500/20 border-indigo-500/40 text-indigo-300\"\n                : \"bg-neutral-800/60 border-neutral-700 text-neutral-400\"\n            )}\n          >\n            Hover Lift: {enableLift ? \"ON\" : \"OFF\"}\n          </button>\n        </div>\n      </div>\n    </div>\n  );\n}\n\nfunction SingleGlowCard({\n  card,\n  palette,\n  radius,\n  intensity,\n  enableLift,\n}: {\n  card: FeatureCardItem;\n  palette: GlowPalette;\n  radius: number;\n  intensity: number;\n  enableLift: boolean;\n}) {\n  const cardRef = useRef<HTMLDivElement>(null);\n  const [coords, setCoords] = useState<{ x: number; y: number }>({ x: 0, y: 0 });\n  const [isHovered, setIsHovered] = useState(false);\n\n  const handleMouseMove = (e: React.PointerEvent<HTMLDivElement>) => {\n    if (!cardRef.current) return;\n    const rect = cardRef.current.getBoundingClientRect();\n    setCoords({\n      x: e.clientX - rect.left,\n      y: e.clientY - rect.top,\n    });\n  };\n\n  return (\n    <div\n      ref={cardRef}\n      onPointerMove={handleMouseMove}\n      onPointerEnter={() => setIsHovered(true)}\n      onPointerLeave={() => setIsHovered(false)}\n      className={cn(\n        \"group relative rounded-2xl p-[1px] transition-all duration-300\",\n        enableLift && \"hover:-translate-y-1\"\n      )}\n      style={{\n        background: isHovered\n          ? `radial-gradient(${radius}px circle at ${coords.x}px ${coords.y}px, ${palette.glowColor}, rgba(255,255,255,0.08) 60%, rgba(255,255,255,0.03) 100%)`\n          : \"rgba(255, 255, 255, 0.08)\",\n      }}\n    >\n      {/* Card Content Shell */}\n      <div className=\"relative h-full w-full rounded-2xl bg-[#090b19] p-6 overflow-hidden flex flex-col justify-between\">\n        {/* Subtle face sheen gradient tracking cursor */}\n        <div\n          className=\"pointer-events-none absolute inset-0 transition-opacity duration-300\"\n          style={{\n            opacity: isHovered ? intensity * 0.35 : 0,\n            background: `radial-gradient(${radius * 1.2}px circle at ${coords.x}px ${coords.y}px, ${palette.glowColor}, transparent 70%)`,\n          }}\n        />\n\n        {/* Card Top: Badge + Action Icon */}\n        <div className=\"relative z-10 flex items-center justify-between\">\n          <span\n            className={cn(\n              \"px-2.5 py-1 rounded-full text-[11px] font-medium border flex items-center gap-1.5\",\n              palette.badgeBg\n            )}\n          >\n            <span className=\"h-1.5 w-1.5 rounded-full bg-current\" />\n            {card.badge}\n          </span>\n\n          <div\n            className={cn(\n              \"h-8 w-8 rounded-lg bg-neutral-800/80 border border-neutral-700/60 flex items-center justify-center transition-colors group-hover:text-white\",\n              palette.accentText\n            )}\n          >\n            {card.icon}\n          </div>\n        </div>\n\n        {/* Card Body */}\n        <div className=\"relative z-10 my-4\">\n          <h3 className=\"text-lg font-semibold text-white group-hover:text-neutral-100 transition-colors\">\n            {card.title}\n          </h3>\n          <p className=\"mt-1.5 text-xs text-neutral-400 leading-relaxed\">\n            {card.description}\n          </p>\n        </div>\n\n        {/* Card Footer: Metric */}\n        <div className=\"relative z-10 pt-4 border-t border-neutral-800/80 flex items-end justify-between\">\n          <div>\n            <div className=\"text-xs text-neutral-500 font-mono\">{card.metricLabel}</div>\n            <div className={cn(\"text-xl font-bold tracking-tight mt-0.5\", palette.accentText)}>\n              {card.metric}\n            </div>\n          </div>\n\n          <div className=\"flex items-center gap-1 text-xs text-neutral-400 group-hover:text-white transition-colors cursor-pointer\">\n            <span>Learn more</span>\n            <ArrowUpRight className=\"h-3.5 w-3.5 group-hover:translate-x-0.5 group-hover:-translate-y-0.5 transition-transform\" />\n          </div>\n        </div>\n      </div>\n    </div>\n  );\n}\n\nexport default GlowBorderCard;\n",
          "type": "registry:ui",
          "target": "components/ui/glow-border-card.tsx"
        },
        {
          "path": "lib/utils.ts",
          "content": "import { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...inputs: ClassValue[]) {\n  return twMerge(clsx(inputs));\n}\n\nexport async function copyToClipboard(text: string): Promise<boolean> {\n  if (typeof window === \"undefined\") return false;\n\n  try {\n    if (navigator.clipboard && window.isSecureContext) {\n      await navigator.clipboard.writeText(text);\n      return true;\n    }\n\n    const textArea = document.createElement(\"textarea\");\n    textArea.value = text;\n    textArea.style.position = \"fixed\";\n    textArea.style.left = \"-999999px\";\n    textArea.style.top = \"-999999px\";\n    document.body.appendChild(textArea);\n    textArea.focus();\n    textArea.select();\n    const succeeded = document.execCommand(\"copy\");\n    textArea.remove();\n    return succeeded;\n  } catch {\n    return false;\n  }\n}\n",
          "type": "registry:lib",
          "target": "lib/utils.ts"
        }
      ]
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "gradient-mesh-hero",
      "type": "registry:ui",
      "title": "Gradient Mesh Hero",
      "author": "Rishabh Bose <https://theb0se.vercel.app/>",
      "description": "Stripe-style angled flowing gradient mesh hero section featuring multi-layered organic color blobs, diagonal polygon clip-path, and live palette switching.",
      "dependencies": [
        "framer-motion",
        "lucide-react",
        "clsx",
        "tailwind-merge"
      ],
      "files": [
        {
          "path": "components/ui/gradient-mesh-hero.tsx",
          "content": "\"use client\";\n\nimport React, { useState } from \"react\";\nimport { motion } from \"framer-motion\";\nimport { ArrowRight, Sparkles, Sliders, Shield, Terminal, Zap } from \"lucide-react\";\nimport { cn } from \"@/lib/utils\";\n\nexport interface ColorPreset {\n  id: string;\n  name: string;\n  blob1: string;\n  blob2: string;\n  blob3: string;\n  blob4: string;\n  blob5: string;\n}\n\nconst COLOR_PRESETS: ColorPreset[] = [\n  {\n    id: \"stripe-classic\",\n    name: \"Stripe Classic\",\n    blob1: \"rgba(99, 102, 241, 0.85)\", // Indigo\n    blob2: \"rgba(168, 85, 247, 0.75)\", // Violet\n    blob3: \"rgba(6, 182, 212, 0.7)\",   // Cyan\n    blob4: \"rgba(244, 63, 94, 0.65)\",  // Vermilion / Rose\n    blob5: \"rgba(245, 158, 11, 0.6)\",  // Amber\n  },\n  {\n    id: \"neon-cyber\",\n    name: \"Neon Cyber\",\n    blob1: \"rgba(217, 70, 239, 0.8)\",  // Fuchsia\n    blob2: \"rgba(59, 130, 246, 0.85)\", // Electric Blue\n    blob3: \"rgba(16, 185, 129, 0.75)\", // Emerald\n    blob4: \"rgba(139, 92, 246, 0.7)\",  // Purple\n    blob5: \"rgba(14, 165, 233, 0.65)\", // Sky\n  },\n  {\n    id: \"sunset-ray\",\n    name: \"Sunset Ember\",\n    blob1: \"rgba(239, 68, 68, 0.85)\",  // Red\n    blob2: \"rgba(249, 115, 22, 0.8)\",  // Orange\n    blob3: \"rgba(234, 179, 8, 0.75)\",  // Yellow\n    blob4: \"rgba(219, 39, 119, 0.7)\",  // Pink\n    blob5: \"rgba(147, 51, 234, 0.6)\",  // Deep Purple\n  },\n  {\n    id: \"deep-aurora\",\n    name: \"Deep Aurora\",\n    blob1: \"rgba(16, 185, 129, 0.85)\", // Emerald\n    blob2: \"rgba(20, 184, 166, 0.8)\",  // Teal\n    blob3: \"rgba(99, 102, 241, 0.75)\", // Indigo\n    blob4: \"rgba(6, 182, 212, 0.7)\",   // Cyan\n    blob5: \"rgba(52, 211, 153, 0.6)\",  // Mint\n  },\n];\n\nexport interface GradientMeshHeroProps {\n  className?: string;\n  defaultPreset?: string;\n  preset?: string;\n  enableClipPath?: boolean;\n  headline?: string;\n  description?: string;\n  primaryCtaText?: string;\n  secondaryCtaText?: string;\n  children?: React.ReactNode;\n}\n\nexport function GradientMeshHero({\n  className,\n  defaultPreset = \"stripe-classic\",\n  preset,\n  enableClipPath = true,\n  headline,\n  description,\n  primaryCtaText,\n  secondaryCtaText,\n  children,\n}: GradientMeshHeroProps) {\n  const [selectedPresetId, setSelectedPresetId] = useState(preset || defaultPreset);\n  const [useClip, setUseClip] = useState(enableClipPath);\n  const [speed, setSpeed] = useState<number>(20); // seconds duration\n  const [blurAmount, setBlurAmount] = useState<number>(80);\n\n  const activePreset =\n    COLOR_PRESETS.find((p) => p.id === selectedPresetId) || COLOR_PRESETS[0];\n\n  return (\n    <div\n      data-fullscreen-scroll\n      className={cn(\n        \"relative w-full min-h-[520px] overflow-hidden rounded-2xl border border-neutral-800 bg-[#060814] text-white flex flex-col justify-between shadow-2xl selection:bg-indigo-500/30\",\n        className\n      )}\n    >\n      <style>{`\n        @keyframes meshDrift1 {\n          0% { transform: translate(0%, 0%) rotate(0deg) scale(1); }\n          33% { transform: translate(25%, -20%) rotate(60deg) scale(1.15); }\n          66% { transform: translate(-20%, 15%) rotate(120deg) scale(0.9); }\n          100% { transform: translate(0%, 0%) rotate(180deg) scale(1); }\n        }\n        @keyframes meshDrift2 {\n          0% { transform: translate(0%, 0%) rotate(0deg) scale(1.1); }\n          33% { transform: translate(-30%, 25%) rotate(-80deg) scale(0.85); }\n          66% { transform: translate(20%, -15%) rotate(-140deg) scale(1.2); }\n          100% { transform: translate(0%, 0%) rotate(-200deg) scale(1.1); }\n        }\n        @keyframes meshDrift3 {\n          0% { transform: translate(0%, 0%) scale(0.95); }\n          50% { transform: translate(30%, 30%) scale(1.25); }\n          100% { transform: translate(0%, 0%) scale(0.95); }\n        }\n        @keyframes meshDrift4 {\n          0% { transform: translate(0%, 0%) scale(1.2); }\n          50% { transform: translate(-25%, -25%) scale(0.85); }\n          100% { transform: translate(0%, 0%) scale(1.2); }\n        }\n      `}</style>\n\n      {/* Clipped Mesh Container */}\n      <div\n        className=\"absolute inset-0 overflow-hidden transition-all duration-700 pointer-events-none\"\n        style={{\n          clipPath: useClip\n            ? \"polygon(0 0, 100% 0, 100% 88%, 0 100%)\"\n            : \"polygon(0 0, 100% 0, 100% 100%, 0 100%)\",\n        }}\n      >\n        {/* Deep dark backdrop under mesh */}\n        <div className=\"absolute inset-0 bg-[#090b1c]\" />\n\n        {/* Ambient Gradient Mesh Canvas of Blobs */}\n        <div\n          className=\"absolute inset-0 opacity-80 transition-opacity\"\n          style={{ filter: `blur(${blurAmount}px)` }}\n        >\n          {/* Blob 1 */}\n          <div\n            className=\"absolute -top-1/4 -left-1/4 h-[90%] w-[90%] rounded-full opacity-90 transition-colors duration-700\"\n            style={{\n              background: `radial-gradient(circle, ${activePreset.blob1} 0%, transparent 70%)`,\n              animation: `meshDrift1 ${speed}s ease-in-out infinite alternate`,\n            }}\n          />\n\n          {/* Blob 2 */}\n          <div\n            className=\"absolute top-1/6 -right-1/4 h-[85%] w-[85%] rounded-full opacity-85 transition-colors duration-700\"\n            style={{\n              background: `radial-gradient(circle, ${activePreset.blob2} 0%, transparent 70%)`,\n              animation: `meshDrift2 ${speed * 1.25}s ease-in-out infinite alternate`,\n            }}\n          />\n\n          {/* Blob 3 */}\n          <div\n            className=\"absolute -bottom-1/3 left-1/4 h-[90%] w-[90%] rounded-full opacity-80 transition-colors duration-700\"\n            style={{\n              background: `radial-gradient(circle, ${activePreset.blob3} 0%, transparent 70%)`,\n              animation: `meshDrift3 ${speed * 0.9}s ease-in-out infinite alternate`,\n            }}\n          />\n\n          {/* Blob 4 */}\n          <div\n            className=\"absolute top-1/3 left-1/3 h-[75%] w-[75%] rounded-full opacity-70 transition-colors duration-700\"\n            style={{\n              background: `radial-gradient(circle, ${activePreset.blob4} 0%, transparent 70%)`,\n              animation: `meshDrift4 ${speed * 1.1}s ease-in-out infinite alternate`,\n            }}\n          />\n\n          {/* Blob 5 Accent Core */}\n          <div\n            className=\"absolute bottom-1/6 right-1/4 h-[60%] w-[60%] rounded-full opacity-75 transition-colors duration-700\"\n            style={{\n              background: `radial-gradient(circle, ${activePreset.blob5} 0%, transparent 65%)`,\n              animation: `meshDrift1 ${speed * 1.4}s ease-in-out infinite alternate-reverse`,\n            }}\n          />\n        </div>\n\n        {/* Subtle grid pattern overlay */}\n        <div\n          className=\"absolute inset-0 opacity-[0.15] mix-blend-overlay\"\n          style={{\n            backgroundImage: `linear-gradient(rgba(255,255,255,0.2) 1px, transparent 1px), linear-gradient(90deg, rgba(255,255,255,0.2) 1px, transparent 1px)`,\n            backgroundSize: \"48px 48px\",\n          }}\n        />\n\n        {/* Vignette / dark bottom gradient */}\n        <div className=\"absolute inset-0 bg-gradient-to-b from-transparent via-black/20 to-[#060814]/90\" />\n      </div>\n\n      {/* Hero Foreground Content */}\n      {children ? (\n        <div className=\"relative z-10 w-full\">{children}</div>\n      ) : (\n        <div className=\"relative z-10 max-w-4xl mx-auto px-6 pt-12 pb-6 text-center flex flex-col items-center\">\n          {/* Top Floating Badge */}\n          <motion.div\n            initial={{ opacity: 0, y: -12 }}\n            animate={{ opacity: 1, y: 0 }}\n            transition={{ duration: 0.5 }}\n            className=\"inline-flex items-center gap-2 px-3 py-1 rounded-full bg-white/10 backdrop-blur-md border border-white/20 text-xs font-medium text-white shadow-lg\"\n          >\n            <Sparkles className=\"h-3.5 w-3.5 text-amber-300\" />\n            <span>Stripe-Grade Mesh v4.0</span>\n            <span className=\"h-1 w-1 rounded-full bg-white/50\" />\n            <span className=\"text-white/80 font-normal\">Next-gen Canvas GPU Drift</span>\n          </motion.div>\n\n          {/* Headline */}\n          <motion.h1\n            initial={{ opacity: 0, y: 16 }}\n            animate={{ opacity: 1, y: 0 }}\n            transition={{ duration: 0.6, delay: 0.1 }}\n            className=\"mt-6 text-4xl sm:text-5xl md:text-6xl font-extrabold tracking-tight text-white leading-[1.12]\"\n          >\n            {headline || (\n              <>\n                Financial infrastructure <br />\n                <span className=\"bg-gradient-to-r from-cyan-300 via-indigo-200 to-amber-200 bg-clip-text text-transparent\">\n                  for the modern internet\n                </span>\n              </>\n            )}\n          </motion.h1>\n\n          {/* Subtitle */}\n          <motion.p\n            initial={{ opacity: 0, y: 16 }}\n            animate={{ opacity: 1, y: 0 }}\n            transition={{ duration: 0.6, delay: 0.2 }}\n            className=\"mt-5 max-w-2xl text-base sm:text-lg text-neutral-200/90 leading-relaxed font-light drop-shadow\"\n          >\n            {description ||\n              \"Millions of companies—from fast-growing startups to global enterprises—use Pulse’s software and APIs to accept payments, send payouts, and scale recurring revenue.\"}\n          </motion.p>\n\n          {/* Action CTAs */}\n          <motion.div\n            initial={{ opacity: 0, y: 16 }}\n            animate={{ opacity: 1, y: 0 }}\n            transition={{ duration: 0.6, delay: 0.3 }}\n            className=\"mt-8 flex flex-wrap items-center justify-center gap-4\"\n          >\n            <button className=\"px-6 py-3 rounded-xl bg-white hover:bg-neutral-100 text-neutral-950 font-semibold text-sm shadow-xl shadow-white/10 flex items-center gap-2 transition-all hover:scale-[1.02] active:scale-[0.98]\">\n              <span>{primaryCtaText || \"Start now\"}</span>\n              <ArrowRight className=\"h-4 w-4\" />\n            </button>\n            <button className=\"px-6 py-3 rounded-xl bg-white/10 hover:bg-white/20 text-white font-medium text-sm border border-white/20 backdrop-blur-md transition-all hover:scale-[1.02] active:scale-[0.98]\">\n              {secondaryCtaText || \"Contact sales\"}\n            </button>\n          </motion.div>\n\n          {/* Live Telemetry Metric Strip */}\n          <motion.div\n            initial={{ opacity: 0 }}\n            animate={{ opacity: 1 }}\n            transition={{ duration: 0.6, delay: 0.4 }}\n            className=\"mt-12 w-full grid grid-cols-2 md:grid-cols-4 gap-4 py-4 px-6 rounded-xl bg-neutral-900/60 border border-neutral-800/80 backdrop-blur-xl text-left\"\n          >\n            <div>\n              <div className=\"text-xl font-bold text-white tracking-tight\">$1.4T+</div>\n              <div className=\"text-xs text-neutral-400\">Annual volume</div>\n            </div>\n            <div>\n              <div className=\"text-xl font-bold text-emerald-400 tracking-tight\">99.999%</div>\n              <div className=\"text-xs text-neutral-400\">Historical uptime</div>\n            </div>\n            <div>\n              <div className=\"text-xl font-bold text-cyan-300 tracking-tight\">135+</div>\n              <div className=\"text-xs text-neutral-400\">Currencies supported</div>\n            </div>\n            <div>\n              <div className=\"text-xl font-bold text-purple-300 tracking-tight\">500M+</div>\n              <div className=\"text-xs text-neutral-400\">Daily API queries</div>\n            </div>\n          </motion.div>\n        </div>\n      )}\n\n      {/* Interactive Controls Stage Footer (only when standalone without children) */}\n      {!children && (\n        <div className=\"relative z-20 mt-8 pt-4 pb-2 px-6 border-t border-neutral-800/80 bg-neutral-950/80 backdrop-blur-md\">\n          <div className=\"flex flex-wrap items-center justify-between gap-4 text-xs\">\n            {/* Preset Palettes */}\n            <div className=\"flex items-center gap-2\">\n              <span className=\"text-neutral-400 font-medium flex items-center gap-1.5\">\n                <Sliders className=\"h-3.5 w-3.5 text-indigo-400\" />\n                Presets:\n              </span>\n              <div className=\"flex flex-wrap gap-1.5\">\n                {COLOR_PRESETS.map((preset) => (\n                  <button\n                    key={preset.id}\n                    onClick={() => setSelectedPresetId(preset.id)}\n                    className={cn(\n                      \"px-2.5 py-1 rounded-md transition-all font-medium text-xs\",\n                      selectedPresetId === preset.id\n                        ? \"bg-indigo-600 text-white shadow-md shadow-indigo-600/30\"\n                        : \"bg-neutral-800/80 text-neutral-300 hover:text-white hover:bg-neutral-700/80\"\n                    )}\n                  >\n                    {preset.name}\n                  </button>\n                ))}\n              </div>\n            </div>\n          </div>\n        </div>\n      )}\n    </div>\n  );\n}\n\nexport default GradientMeshHero;\n",
          "type": "registry:ui",
          "target": "components/ui/gradient-mesh-hero.tsx"
        },
        {
          "path": "lib/utils.ts",
          "content": "import { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...inputs: ClassValue[]) {\n  return twMerge(clsx(inputs));\n}\n\nexport async function copyToClipboard(text: string): Promise<boolean> {\n  if (typeof window === \"undefined\") return false;\n\n  try {\n    if (navigator.clipboard && window.isSecureContext) {\n      await navigator.clipboard.writeText(text);\n      return true;\n    }\n\n    const textArea = document.createElement(\"textarea\");\n    textArea.value = text;\n    textArea.style.position = \"fixed\";\n    textArea.style.left = \"-999999px\";\n    textArea.style.top = \"-999999px\";\n    document.body.appendChild(textArea);\n    textArea.focus();\n    textArea.select();\n    const succeeded = document.execCommand(\"copy\");\n    textArea.remove();\n    return succeeded;\n  } catch {\n    return false;\n  }\n}\n",
          "type": "registry:lib",
          "target": "lib/utils.ts"
        }
      ]
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "gravity-well-portal",
      "type": "registry:ui",
      "title": "Gravity Well Portal",
      "author": "Rishabh Bose <https://theb0se.vercel.app/>",
      "description": "Multi-node gravitational field stage where spring-tethered telemetry badges warp toward or repel from the pointer with polarity inversion.",
      "dependencies": [
        "framer-motion",
        "lucide-react",
        "clsx",
        "tailwind-merge"
      ],
      "files": [
        {
          "path": "components/ui/gravity-well-portal.tsx",
          "content": "\"use client\";\n\nimport React, { useRef, useState } from \"react\";\nimport {\n  motion,\n  useMotionValue,\n  useSpring,\n  useTransform,\n  useReducedMotion,\n  type MotionValue,\n} from \"framer-motion\";\nimport { Magnet, Sparkles } from \"lucide-react\";\nimport { cn } from \"@/lib/utils\";\n\nexport interface GravityWellPortalProps {\n  /** Gravitational pull radius in pixels around the pointer. Default: 180 */\n  pullRadius?: number;\n  /** Peak attraction displacement factor (0.1 to 0.9). Default: 0.55 */\n  pullStrength?: number;\n  /** Hooke's Law spring stiffness coefficient. Default: 240 */\n  stiffness?: number;\n  /** Spring damping coefficient. Default: 20 */\n  damping?: number;\n  className?: string;\n}\n\ninterface OrbitalNodeSpec {\n  id: string;\n  label: string;\n  xPct: number;\n  yPct: number;\n}\n\nconst ORBITAL_NODES: OrbitalNodeSpec[] = [\n  { id: \"n1\", label: \"k=240\", xPct: 20, yPct: 26 },\n  { id: \"n2\", label: \"ζ=0.65\", xPct: 78, yPct: 24 },\n  { id: \"n3\", label: \"m=0.4\", xPct: 16, yPct: 74 },\n  { id: \"n4\", label: \"60fps\", xPct: 82, yPct: 72 },\n  { id: \"n5\", label: \"F=-kx\", xPct: 50, yPct: 18 },\n  { id: \"n6\", label: \"GPU\", xPct: 50, yPct: 82 },\n];\n\ninterface tetheredNodeProps {\n  node: OrbitalNodeSpec;\n  mouseX: MotionValue<number>;\n  mouseY: MotionValue<number>;\n  containerRef: React.RefObject<HTMLDivElement | null>;\n  pullRadius: number;\n  pullStrength: number;\n  stiffness: number;\n  damping: number;\n  impulseMultiplier: number;\n  shouldReduceMotion: boolean;\n}\n\nfunction TetheredNode({\n  node,\n  mouseX,\n  mouseY,\n  containerRef,\n  pullRadius,\n  pullStrength,\n  stiffness,\n  damping,\n  impulseMultiplier,\n  shouldReduceMotion,\n}: tetheredNodeProps) {\n  const offsetX = useTransform([mouseX, mouseY], ([mx, my]) => {\n    const el = containerRef.current;\n    if (!el || mx === -Infinity || my === -Infinity) return 0;\n    const rect = el.getBoundingClientRect();\n    const anchorX = (node.xPct / 100) * rect.width;\n    const anchorY = (node.yPct / 100) * rect.height;\n    const dx = (mx as number) - anchorX;\n    const dy = (my as number) - anchorY;\n    const dist = Math.sqrt(dx * dx + dy * dy);\n    if (dist >= pullRadius || dist === 0) return 0;\n    const falloff = 1 - dist / pullRadius;\n    return dx * falloff * pullStrength * impulseMultiplier;\n  });\n\n  const offsetY = useTransform([mouseX, mouseY], ([mx, my]) => {\n    const el = containerRef.current;\n    if (!el || mx === -Infinity || my === -Infinity) return 0;\n    const rect = el.getBoundingClientRect();\n    const anchorX = (node.xPct / 100) * rect.width;\n    const anchorY = (node.yPct / 100) * rect.height;\n    const dx = (mx as number) - anchorX;\n    const dy = (my as number) - anchorY;\n    const dist = Math.sqrt(dx * dx + dy * dy);\n    if (dist >= pullRadius || dist === 0) return 0;\n    const falloff = 1 - dist / pullRadius;\n    return dy * falloff * pullStrength * impulseMultiplier;\n  });\n\n  const springX = useSpring(offsetX, { stiffness, damping, mass: 0.45 });\n  const springY = useSpring(offsetY, { stiffness, damping, mass: 0.45 });\n\n  return (\n    <motion.div\n      aria-hidden=\"true\"\n      style={{\n        left: `${node.xPct}%`,\n        top: `${node.yPct}%`,\n        x: shouldReduceMotion ? 0 : springX,\n        y: shouldReduceMotion ? 0 : springY,\n      }}\n      className=\"pointer-events-none absolute -translate-x-1/2 -translate-y-1/2 rounded-full border border-neutral-200 bg-white/95 px-2.5 py-1 font-mono text-[10px] font-semibold text-neutral-700 shadow-sm backdrop-blur-md dark:border-[#262626] dark:bg-[#141414]/95 dark:text-neutral-300\"\n    >\n      {node.label}\n    </motion.div>\n  );\n}\n\nexport function GravityWellPortal({\n  pullRadius = 180,\n  pullStrength = 0.55,\n  stiffness = 240,\n  damping = 20,\n  className,\n}: GravityWellPortalProps) {\n  const containerRef = useRef<HTMLDivElement | null>(null);\n  const shouldReduceMotion = useReducedMotion() ?? false;\n  const [repelMode, setRepelMode] = useState(false);\n\n  const mouseX = useMotionValue(-Infinity);\n  const mouseY = useMotionValue(-Infinity);\n\n  const handleMouseMove = (e: React.MouseEvent<HTMLDivElement>) => {\n    if (shouldReduceMotion) return;\n    const el = containerRef.current;\n    if (!el) return;\n    const rect = el.getBoundingClientRect();\n    mouseX.set(e.clientX - rect.left);\n    mouseY.set(e.clientY - rect.top);\n  };\n\n  const handleMouseLeave = () => {\n    mouseX.set(-Infinity);\n    mouseY.set(-Infinity);\n  };\n\n  return (\n    <div\n      ref={containerRef}\n      role=\"region\"\n      aria-label=\"Interactive gravitational spring field\"\n      onMouseMove={handleMouseMove}\n      onMouseLeave={handleMouseLeave}\n      onClick={() => setRepelMode((prev) => !prev)}\n      className={cn(\n        \"relative flex min-h-[240px] w-full max-w-md cursor-pointer select-none flex-col items-center justify-center overflow-hidden rounded-2xl border border-neutral-200 bg-white p-6 dark:border-[#222222] dark:bg-[#0A0A0A]\",\n        className\n      )}\n    >\n      {/* Orbital Rings */}\n      <div\n        aria-hidden=\"true\"\n        className=\"pointer-events-none absolute h-44 w-44 rounded-full border border-dashed border-neutral-200/80 dark:border-[#1F1F1F]\"\n      />\n      <div\n        aria-hidden=\"true\"\n        className=\"pointer-events-none absolute h-28 w-28 rounded-full border border-neutral-200/60 dark:border-[#1A1A1A]\"\n      />\n\n      {/* Tethered Telemetry Nodes */}\n      {ORBITAL_NODES.map((node) => (\n        <TetheredNode\n          key={node.id}\n          node={node}\n          mouseX={mouseX}\n          mouseY={mouseY}\n          containerRef={containerRef}\n          pullRadius={pullRadius}\n          pullStrength={pullStrength}\n          stiffness={stiffness}\n          damping={damping}\n          impulseMultiplier={repelMode ? -1.15 : 1}\n          shouldReduceMotion={shouldReduceMotion}\n        />\n      ))}\n\n      {/* Central Singularity Core */}\n      <div className=\"relative z-10 flex flex-col items-center text-center\">\n        <button\n          type=\"button\"\n          onClick={(e) => {\n            e.stopPropagation();\n            setRepelMode((prev) => !prev);\n          }}\n          className=\"inline-flex items-center gap-1.5 rounded-full border border-neutral-300 bg-neutral-50 px-3 py-1.5 text-xs font-semibold text-black shadow-sm transition-colors hover:border-black focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-black dark:border-[#2E2E2E] dark:bg-[#141414] dark:text-white dark:hover:border-white dark:focus-visible:ring-white\"\n        >\n          {repelMode ? (\n            <Sparkles className=\"h-3.5 w-3.5\" />\n          ) : (\n            <Magnet className=\"h-3.5 w-3.5\" />\n          )}\n          <span>{repelMode ? \"Polarity: Repel\" : \"Polarity: Attract\"}</span>\n        </button>\n        <p className=\"mt-2 text-[11px] text-neutral-500 dark:text-neutral-400\">\n          Move cursor to warp nodes • Click to invert polarity\n        </p>\n      </div>\n    </div>\n  );\n}\n\nexport default GravityWellPortal;\n",
          "type": "registry:ui",
          "target": "components/ui/gravity-well-portal.tsx"
        },
        {
          "path": "lib/utils.ts",
          "content": "import { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...inputs: ClassValue[]) {\n  return twMerge(clsx(inputs));\n}\n\nexport async function copyToClipboard(text: string): Promise<boolean> {\n  if (typeof window === \"undefined\") return false;\n\n  try {\n    if (navigator.clipboard && window.isSecureContext) {\n      await navigator.clipboard.writeText(text);\n      return true;\n    }\n\n    const textArea = document.createElement(\"textarea\");\n    textArea.value = text;\n    textArea.style.position = \"fixed\";\n    textArea.style.left = \"-999999px\";\n    textArea.style.top = \"-999999px\";\n    document.body.appendChild(textArea);\n    textArea.focus();\n    textArea.select();\n    const succeeded = document.execCommand(\"copy\");\n    textArea.remove();\n    return succeeded;\n  } catch {\n    return false;\n  }\n}\n",
          "type": "registry:lib",
          "target": "lib/utils.ts"
        }
      ]
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "grid-horizon",
      "type": "registry:ui",
      "title": "Grid Horizon",
      "author": "Rishabh Bose <https://theb0se.vercel.app/>",
      "description": "Pure CSS 3D perspective synthwave horizon using `perspective(320px) rotateX(64deg)` and `background-position-y` animation for an endless wireframe road effect.",
      "dependencies": [
        "lucide-react",
        "clsx",
        "tailwind-merge"
      ],
      "files": [
        {
          "path": "components/ui/grid-horizon.tsx",
          "content": "\"use client\";\n\nimport React, { useState } from \"react\";\nimport { Compass } from \"lucide-react\";\nimport { cn } from \"@/lib/utils\";\n\nexport interface GridHorizonProps {\n  /** Forward road scroll speed multiplier (1 = default). Default: 1 */\n  speed?: number;\n  /** Grid line color. Default: \"rgba(236, 72, 153, 0.55)\" */\n  gridColor?: string;\n  /** Horizon sun gradient color. Default: \"#F97316\" */\n  sunColor?: string;\n  /** Grid cell size in pixels. Default: 44 */\n  gridSize?: number;\n  /** Display the retro segmented sun on the horizon. Default: true */\n  showSun?: boolean;\n  /** Optional foreground content */\n  children?: React.ReactNode;\n  className?: string;\n}\n\nexport function GridHorizon({\n  speed = 1,\n  gridColor = \"rgba(236, 72, 153, 0.55)\",\n  sunColor = \"#F97316\",\n  gridSize = 44,\n  showSun = true,\n  children,\n  className,\n}: GridHorizonProps) {\n  const [theme, setTheme] = useState<\"synthwave\" | \"cyber\" | \"mono\">(\n    \"synthwave\"\n  );\n\n  const palettes = {\n    synthwave: {\n      grid: gridColor,\n      sun: sunColor,\n      glow: \"#EC4899\",\n    },\n    cyber: {\n      grid: \"rgba(6, 182, 212, 0.55)\",\n      sun: \"#38BDF8\",\n      glow: \"#06B6D4\",\n    },\n    mono: {\n      grid: \"rgba(255, 255, 255, 0.35)\",\n      sun: \"#FFFFFF\",\n      glow: \"#A3A3A3\",\n    },\n  };\n\n  const active = palettes[theme];\n  const duration = Math.max(0.4, 1.8 / Math.max(0.2, speed));\n\n  return (\n    <div\n      data-fullscreen-scroll\n      className={cn(\n        \"relative flex min-h-[360px] w-full flex-col justify-between overflow-hidden rounded-3xl border border-neutral-800 bg-[#06040F] p-6 text-white shadow-sm\",\n        className\n      )}\n    >\n      <style>{`\n        @keyframes bose-grid-scroll {\n          0% { background-position: 0px 0px; }\n          100% { background-position: 0px ${gridSize}px; }\n        }\n      `}</style>\n\n      {/* Sky Backdrop & Segmented Synthwave Sun */}\n      <div\n        aria-hidden=\"true\"\n        className=\"pointer-events-none absolute inset-x-0 top-0 h-[52%] overflow-hidden bg-gradient-to-b from-[#05030D] via-[#130926] to-[#2E1045]\"\n      >\n        {showSun && (\n          <div\n            style={{\n              background: `linear-gradient(180deg, #FDE047 0%, ${active.sun} 55%, ${active.glow} 100%)`,\n              boxShadow: `0 0 60px ${active.glow}`,\n              WebkitMaskImage:\n                \"repeating-linear-gradient(to bottom, black 0px, black 8px, transparent 8px, transparent 11px)\",\n              maskImage:\n                \"repeating-linear-gradient(to bottom, black 0px, black 8px, transparent 8px, transparent 11px)\",\n            }}\n            className=\"absolute bottom-[-28px] left-1/2 h-36 w-36 -translate-x-1/2 rounded-full\"\n          />\n        )}\n      </div>\n\n      {/* Glowing Horizon Divider Line */}\n      <div\n        aria-hidden=\"true\"\n        style={{\n          background: active.glow,\n          boxShadow: `0 0 24px 3px ${active.glow}`,\n        }}\n        className=\"pointer-events-none absolute inset-x-0 top-[52%] z-10 h-[2px]\"\n      />\n\n      {/* 3D Perspective Infinite Scrolling Grid Plane */}\n      <div\n        aria-hidden=\"true\"\n        style={{ perspective: \"320px\" }}\n        className=\"pointer-events-none absolute inset-x-0 bottom-0 h-[48%] overflow-hidden bg-[#06030E]\"\n      >\n        <div\n          style={{\n            transform: \"rotateX(64deg) scale(2.2)\",\n            transformOrigin: \"top center\",\n            backgroundImage: `linear-gradient(to right, ${active.grid} 1px, transparent 1px), linear-gradient(to bottom, ${active.grid} 1px, transparent 1px)`,\n            backgroundSize: `${gridSize}px ${gridSize}px`,\n            animation: `bose-grid-scroll ${duration}s linear infinite`,\n          }}\n          className=\"h-[220%] w-full\"\n        />\n\n        {/* Distance Fog Fade at Horizon */}\n        <div className=\"absolute inset-x-0 top-0 h-16 bg-gradient-to-b from-[#130926] to-transparent\" />\n      </div>\n\n      {/* Foreground Content */}\n      <div className=\"relative z-20 flex flex-1 flex-col justify-between\">\n        {children ?? (\n          <>\n            <div className=\"flex flex-wrap items-center justify-between gap-2\">\n              <span className=\"inline-flex items-center gap-1.5 rounded-full border border-white/15 bg-black/40 px-3 py-1 font-mono text-[11px] font-medium text-white backdrop-blur-md\">\n                <Compass className=\"h-3.5 w-3.5 text-pink-400\" />\n                Grid Horizon · rotateX(64deg)\n              </span>\n\n              <div className=\"flex items-center gap-1 rounded-full border border-white/15 bg-black/40 p-1 backdrop-blur-md\">\n                {([\"synthwave\", \"cyber\", \"mono\"] as const).map((t) => (\n                  <button\n                    key={t}\n                    type=\"button\"\n                    onClick={() => setTheme(t)}\n                    className={cn(\n                      \"rounded-full px-2.5 py-0.5 font-mono text-[10px] font-semibold uppercase transition-colors\",\n                      theme === t\n                        ? \"bg-white text-black\"\n                        : \"text-white/75 hover:text-white\"\n                    )}\n                  >\n                    {t}\n                  </button>\n                ))}\n              </div>\n            </div>\n\n            <div className=\"my-auto max-w-md py-6\">\n              <h3 className=\"text-2xl font-bold tracking-tight text-white drop-shadow-md sm:text-3xl\">\n                Perspective Grid Horizon\n              </h3>\n              <p className=\"mt-2 text-xs leading-relaxed text-white/85 drop-shadow-xs sm:text-sm\">\n                Pure CSS <code className=\"font-mono\">perspective(320px)</code>{\" \"}\n                plane tilted at 64° with an endless{\" \"}\n                <code className=\"font-mono\">background-position-y</code> loop\n                and a scanline horizon sun.\n              </p>\n            </div>\n\n            <div className=\"font-mono text-[11px] text-white/60\">\n              Pure CSS 3D Transform · Endless Loop · 0 JS Per-Frame Cost\n            </div>\n          </>\n        )}\n      </div>\n    </div>\n  );\n}\n\nexport default GridHorizon;\n",
          "type": "registry:ui",
          "target": "components/ui/grid-horizon.tsx"
        },
        {
          "path": "lib/utils.ts",
          "content": "import { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...inputs: ClassValue[]) {\n  return twMerge(clsx(inputs));\n}\n\nexport async function copyToClipboard(text: string): Promise<boolean> {\n  if (typeof window === \"undefined\") return false;\n\n  try {\n    if (navigator.clipboard && window.isSecureContext) {\n      await navigator.clipboard.writeText(text);\n      return true;\n    }\n\n    const textArea = document.createElement(\"textarea\");\n    textArea.value = text;\n    textArea.style.position = \"fixed\";\n    textArea.style.left = \"-999999px\";\n    textArea.style.top = \"-999999px\";\n    document.body.appendChild(textArea);\n    textArea.focus();\n    textArea.select();\n    const succeeded = document.execCommand(\"copy\");\n    textArea.remove();\n    return succeeded;\n  } catch {\n    return false;\n  }\n}\n",
          "type": "registry:lib",
          "target": "lib/utils.ts"
        }
      ]
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "heart-burst-button",
      "type": "registry:ui",
      "title": "Heart Burst Button",
      "author": "Rishabh Bose <https://theb0se.vercel.app/>",
      "description": "Instagram and Twitter-style like button featuring an elastic scale-pop spring, expanding shockwave ring, radial multi-colored particle confetti sparks, and double-tap card preview.",
      "dependencies": [
        "framer-motion",
        "lucide-react",
        "clsx",
        "tailwind-merge"
      ],
      "files": [
        {
          "path": "components/ui/heart-burst-button.tsx",
          "content": "\"use client\";\n\nimport React, { useState } from \"react\";\nimport { motion, AnimatePresence } from \"framer-motion\";\nimport {\n  Heart,\n  Sparkles,\n  Share2,\n  MessageCircle,\n  Bookmark,\n  Volume2,\n  VolumeX,\n  RotateCcw,\n} from \"lucide-react\";\nimport { cn } from \"@/lib/utils\";\n\nexport interface HeartBurstButtonProps {\n  /** Initial like state */\n  initialLiked?: boolean;\n  /** Initial like count */\n  initialCount?: number;\n  /** Size variant */\n  size?: \"sm\" | \"md\" | \"lg\" | \"xl\";\n  /** Color theme */\n  theme?: \"instagram\" | \"crimson\" | \"violet\" | \"gold\";\n  /** Callback when like state changes */\n  onToggle?: (liked: boolean, count: number) => void;\n  /** Extra container className */\n  className?: string;\n}\n\ninterface Particle {\n  id: number;\n  angle: number;\n  distance: number;\n  size: number;\n  color: string;\n}\n\nconst THEME_COLORS: Record<string, { primary: string; glow: string; particles: string[] }> = {\n  instagram: {\n    primary: \"text-rose-500 fill-rose-500\",\n    glow: \"shadow-rose-500/40\",\n    particles: [\"#FF385C\", \"#E0245E\", \"#FF5A5F\", \"#FA709A\", \"#FEE140\", \"#7928CA\"],\n  },\n  crimson: {\n    primary: \"text-red-600 fill-red-600\",\n    glow: \"shadow-red-600/40\",\n    particles: [\"#E50914\", \"#FF1E27\", \"#B81D24\", \"#FF6B6B\", \"#FFA07A\"],\n  },\n  violet: {\n    primary: \"text-fuchsia-500 fill-fuchsia-500\",\n    glow: \"shadow-fuchsia-500/40\",\n    particles: [\"#A855F7\", \"#D946EF\", \"#EC4899\", \"#8B5CF6\", \"#C084FC\"],\n  },\n  gold: {\n    primary: \"text-amber-500 fill-amber-500\",\n    glow: \"shadow-amber-500/40\",\n    particles: [\"#F59E0B\", \"#FBBF24\", \"#FCD34D\", \"#D97706\", \"#FEF08A\"],\n  },\n};\n\nconst SIZES = {\n  sm: { icon: \"h-4 w-4\", btn: \"h-8 px-2.5 text-xs gap-1.5\", ring: \"w-8 h-8\" },\n  md: { icon: \"h-5 w-5\", btn: \"h-10 px-3.5 text-sm gap-2\", ring: \"w-10 h-10\" },\n  lg: { icon: \"h-7 w-7\", btn: \"h-12 px-4.5 text-base gap-2.5\", ring: \"w-12 h-12\" },\n  xl: { icon: \"h-9 w-9\", btn: \"h-16 px-6 text-lg gap-3\", ring: \"w-16 h-16\" },\n};\n\nexport function HeartBurstButton({\n  initialLiked = false,\n  initialCount = 1420,\n  size = \"md\",\n  theme = \"instagram\",\n  onToggle,\n  className,\n}: HeartBurstButtonProps) {\n  const [isLiked, setIsLiked] = useState(initialLiked);\n  const [likeCount, setLikeCount] = useState(initialCount);\n  const [activeTheme, setActiveTheme] = useState<\"instagram\" | \"crimson\" | \"violet\" | \"gold\">(theme);\n  const [activeSize, setActiveSize] = useState<\"sm\" | \"md\" | \"lg\" | \"xl\">(size);\n  const [burstKey, setBurstKey] = useState(0);\n  const [cardDoubleTapBurst, setCardDoubleTapBurst] = useState<{ id: number; x: number; y: number } | null>(null);\n  const [soundEnabled, setSoundEnabled] = useState(false);\n\n  const colors = THEME_COLORS[activeTheme];\n  const sizeConfig = SIZES[activeSize];\n\n  // Generate 12 radial particles\n  const particles: Particle[] = Array.from({ length: 12 }).map((_, i) => {\n    const angle = (i * (360 / 12)) + (i % 2 === 0 ? 8 : -8);\n    const distance = 28 + (i % 3) * 10;\n    const pSize = 4 + (i % 3) * 2;\n    const color = colors.particles[i % colors.particles.length];\n    return { id: i, angle, distance, size: pSize, color };\n  });\n\n  const triggerLike = (forceState?: boolean) => {\n    const nextState = forceState !== undefined ? forceState : !isLiked;\n    setIsLiked(nextState);\n    const newCount = nextState ? likeCount + 1 : Math.max(0, likeCount - 1);\n    setLikeCount(newCount);\n    if (nextState) {\n      setBurstKey((prev) => prev + 1);\n    }\n    onToggle?.(nextState, newCount);\n  };\n\n  const handleCardDoubleClick = (e: React.MouseEvent<HTMLDivElement>) => {\n    const rect = e.currentTarget.getBoundingClientRect();\n    const x = e.clientX - rect.left;\n    const y = e.clientY - rect.top;\n\n    setCardDoubleTapBurst({ id: Date.now(), x, y });\n    if (!isLiked) {\n      triggerLike(true);\n    } else {\n      setBurstKey((prev) => prev + 1);\n    }\n  };\n\n  return (\n    <div\n      data-fullscreen-scroll\n      className={cn(\n        \"relative flex min-h-[520px] w-full flex-col justify-between overflow-hidden rounded-2xl border border-neutral-200 bg-neutral-50/70 p-4 sm:p-8 dark:border-neutral-800 dark:bg-neutral-950\",\n        className\n      )}\n    >\n      {/* Header bar */}\n      <div className=\"relative z-10 flex flex-wrap items-center justify-between gap-3 pb-3\">\n        <div className=\"flex items-center gap-3\">\n          <div className=\"flex h-9 w-9 items-center justify-center rounded-xl bg-rose-500/10 text-rose-600 dark:bg-rose-500/20 dark:text-rose-400\">\n            <Heart className=\"h-4 w-4 fill-rose-500\" />\n          </div>\n          <div>\n            <div className=\"flex items-center gap-2\">\n              <span className=\"text-sm font-semibold tracking-tight text-neutral-900 dark:text-neutral-100\">\n                Instagram Heart Burst Button\n              </span>\n              <span className=\"rounded-full bg-rose-500/10 px-2 py-0.5 text-[10px] font-semibold text-rose-600 dark:text-rose-400\">\n                Confetti &amp; Shockwave\n              </span>\n            </div>\n            <p className=\"text-xs text-neutral-500 dark:text-neutral-400\">\n              Elastic pop spring, expanding shockwave ring, radial particles, and photo double-tap\n            </p>\n          </div>\n        </div>\n\n        <div className=\"flex items-center gap-2\">\n          <button\n            type=\"button\"\n            onClick={() => setSoundEnabled(!soundEnabled)}\n            className=\"flex items-center gap-1.5 rounded-lg border border-neutral-200 bg-white px-2.5 py-1.5 text-xs font-medium text-neutral-700 shadow-xs transition hover:bg-neutral-100 dark:border-neutral-800 dark:bg-neutral-900 dark:text-neutral-300 dark:hover:bg-neutral-800\"\n          >\n            {soundEnabled ? (\n              <>\n                <Volume2 className=\"h-3.5 w-3.5 text-rose-500\" />\n                <span>Haptic Audio On</span>\n              </>\n            ) : (\n              <>\n                <VolumeX className=\"h-3.5 w-3.5\" />\n                <span>Mute Audio</span>\n              </>\n            )}\n          </button>\n        </div>\n      </div>\n\n      {/* Main Showcase Stage */}\n      <div className=\"relative z-10 my-auto flex flex-col items-center justify-center py-6 sm:flex-row sm:gap-12\">\n        {/* Instagram Post Card with Double Tap Burst */}\n        <div className=\"relative w-full max-w-sm rounded-3xl border border-neutral-200/90 bg-white shadow-xl shadow-neutral-950/5 dark:border-neutral-800/90 dark:bg-neutral-900 dark:shadow-black/40\">\n          {/* Post Header */}\n          <div className=\"flex items-center justify-between border-b border-neutral-100 p-3.5 dark:border-neutral-800\">\n            <div className=\"flex items-center gap-2.5\">\n              <div className=\"h-8 w-8 rounded-full bg-gradient-to-tr from-amber-500 via-rose-500 to-purple-600 p-0.5\">\n                <div className=\"h-full w-full rounded-full bg-white dark:bg-neutral-900 flex items-center justify-center text-[11px] font-bold\">\n                  P\n                </div>\n              </div>\n              <div>\n                <div className=\"text-xs font-bold text-neutral-900 dark:text-white\">\n                  pulse.ui\n                </div>\n                <div className=\"text-[10px] text-neutral-400\">Kyoto, Japan</div>\n              </div>\n            </div>\n            <Sparkles className=\"h-4 w-4 text-neutral-400\" />\n          </div>\n\n          {/* Post Photo Canvas (Double Clickable) */}\n          <div\n            onDoubleClick={handleCardDoubleClick}\n            className=\"group relative h-64 w-full cursor-pointer select-none overflow-hidden bg-gradient-to-br from-indigo-900 via-slate-900 to-rose-950\"\n          >\n            {/* Visual backdrop details */}\n            <div className=\"absolute inset-0 flex flex-col items-center justify-center p-6 text-center text-white/90\">\n              <div className=\"mb-2 rounded-full border border-white/20 bg-white/10 px-3 py-1 text-[11px] font-medium backdrop-blur-md\">\n                Double tap anywhere to like\n              </div>\n              <p className=\"max-w-[200px] text-xs font-light text-white/70\">\n                Cherry blossoms blooming along the Philosopher&apos;s Path at dawn.\n              </p>\n            </div>\n\n            {/* Central Double Tap Big Heart Pop */}\n            <AnimatePresence>\n              {cardDoubleTapBurst && (\n                <motion.div\n                  key={cardDoubleTapBurst.id}\n                  initial={{ scale: 0, opacity: 0, rotate: -15 }}\n                  animate={{\n                    scale: [0, 1.4, 1.1, 1.2],\n                    opacity: [0, 1, 0.95, 0],\n                    rotate: [0, 10, -5, 0],\n                    y: [0, -20],\n                  }}\n                  transition={{ duration: 0.85, ease: [0.175, 0.885, 0.32, 1.275] }}\n                  style={{\n                    position: \"absolute\",\n                    left: cardDoubleTapBurst.x - 36,\n                    top: cardDoubleTapBurst.y - 36,\n                  }}\n                  className=\"pointer-events-none z-30\"\n                >\n                  <Heart className=\"h-20 w-20 fill-white text-white drop-shadow-2xl\" />\n                </motion.div>\n              )}\n            </AnimatePresence>\n          </div>\n\n          {/* Post Action Bar */}\n          <div className=\"p-3.5\">\n            <div className=\"flex items-center justify-between\">\n              <div className=\"flex items-center gap-3\">\n                {/* Heart Burst Action */}\n                <div className=\"relative\">\n                  {/* Expanding Shockwave Ring */}\n                  <AnimatePresence>\n                    {isLiked && (\n                      <motion.div\n                        key={`ring-${burstKey}`}\n                        initial={{ scale: 0.2, opacity: 0.9 }}\n                        animate={{ scale: 2.4, opacity: 0 }}\n                        exit={{ opacity: 0 }}\n                        transition={{ duration: 0.5, ease: \"easeOut\" }}\n                        className={cn(\n                          \"pointer-events-none absolute left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2 rounded-full border-2 border-rose-500\",\n                          sizeConfig.ring\n                        )}\n                      />\n                    )}\n                  </AnimatePresence>\n\n                  {/* Confetti Particles */}\n                  <AnimatePresence>\n                    {isLiked && (\n                      <div className=\"pointer-events-none absolute left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2\">\n                        {particles.map((p) => {\n                          const rad = (p.angle * Math.PI) / 180;\n                          const targetX = Math.cos(rad) * p.distance;\n                          const targetY = Math.sin(rad) * p.distance;\n\n                          return (\n                            <motion.span\n                              key={`p-${burstKey}-${p.id}`}\n                              initial={{ scale: 0, x: 0, y: 0, opacity: 1 }}\n                              animate={{\n                                scale: [0, 1.3, 0],\n                                x: targetX,\n                                y: targetY,\n                                opacity: [1, 0.9, 0],\n                              }}\n                              transition={{\n                                duration: 0.55,\n                                ease: \"easeOut\",\n                                delay: (p.id % 4) * 0.02,\n                              }}\n                              style={{\n                                width: p.size,\n                                height: p.size,\n                                backgroundColor: p.color,\n                              }}\n                              className=\"absolute -translate-x-1/2 -translate-y-1/2 rounded-full shadow-xs\"\n                            />\n                          );\n                        })}\n                      </div>\n                    )}\n                  </AnimatePresence>\n\n                  {/* Elastic Heart Icon Button */}\n                  <motion.button\n                    type=\"button\"\n                    onClick={() => triggerLike()}\n                    whileTap={{ scale: 0.8 }}\n                    aria-label={isLiked ? \"Unlike post\" : \"Like post\"}\n                    className=\"relative z-10 flex items-center justify-center transition-colors focus-visible:outline-none\"\n                  >\n                    <motion.div\n                      key={`heart-${burstKey}`}\n                      animate={\n                        isLiked\n                          ? {\n                              scale: [1, 0.65, 1.45, 0.92, 1],\n                              rotate: [0, -12, 12, -4, 0],\n                            }\n                          : { scale: 1 }\n                      }\n                      transition={{ duration: 0.45, ease: \"easeInOut\" }}\n                    >\n                      <Heart\n                        className={cn(\n                          sizeConfig.icon,\n                          \"transition-colors duration-150\",\n                          isLiked\n                            ? colors.primary\n                            : \"text-neutral-700 hover:text-neutral-900 dark:text-neutral-300 dark:hover:text-white\"\n                        )}\n                      />\n                    </motion.div>\n                  </motion.button>\n                </div>\n\n                <MessageCircle className=\"h-5 w-5 text-neutral-700 hover:text-neutral-900 dark:text-neutral-300 dark:hover:text-white cursor-pointer\" />\n                <Share2 className=\"h-5 w-5 text-neutral-700 hover:text-neutral-900 dark:text-neutral-300 dark:hover:text-white cursor-pointer\" />\n              </div>\n\n              <Bookmark className=\"h-5 w-5 text-neutral-700 hover:text-neutral-900 dark:text-neutral-300 dark:hover:text-white cursor-pointer\" />\n            </div>\n\n            {/* Like Counter with Number Spring Animation */}\n            <div className=\"mt-2.5 flex items-center gap-1.5\">\n              <span className=\"text-xs font-bold text-neutral-900 dark:text-white\">\n                <AnimatePresence mode=\"popLayout\" initial={false}>\n                  <motion.span\n                    key={likeCount}\n                    initial={{ y: 8, opacity: 0 }}\n                    animate={{ y: 0, opacity: 1 }}\n                    exit={{ y: -8, opacity: 0 }}\n                    transition={{ duration: 0.2 }}\n                    className=\"inline-block font-mono\"\n                  >\n                    {likeCount.toLocaleString()}\n                  </motion.span>\n                </AnimatePresence>{\" \"}\n                likes\n              </span>\n            </div>\n\n            <p className=\"mt-1 text-xs text-neutral-700 dark:text-neutral-300\">\n              <span className=\"font-bold\">pulse.ui</span> Spring physics make tactile consumer interactions irresistible.\n            </p>\n          </div>\n        </div>\n\n        {/* Standalone Button Inspector & Variations */}\n        <div className=\"mt-6 flex flex-col items-center gap-5 sm:mt-0\">\n          <div className=\"text-center\">\n            <span className=\"text-[11px] font-semibold uppercase tracking-wider text-neutral-400\">\n              Standalone Interactive Button\n            </span>\n            <div className=\"mt-3 flex items-center justify-center\">\n              <button\n                type=\"button\"\n                onClick={() => triggerLike()}\n                className={cn(\n                  \"relative flex items-center rounded-full border border-neutral-200 bg-white shadow-md transition-all hover:shadow-lg dark:border-neutral-800 dark:bg-neutral-900\",\n                  sizeConfig.btn\n                )}\n              >\n                <motion.div\n                  key={`standalone-heart-${burstKey}`}\n                  animate={\n                    isLiked\n                      ? { scale: [1, 0.6, 1.45, 0.9, 1] }\n                      : { scale: 1 }\n                  }\n                  transition={{ duration: 0.4 }}\n                >\n                  <Heart\n                    className={cn(\n                      sizeConfig.icon,\n                      \"transition-colors\",\n                      isLiked ? colors.primary : \"text-neutral-400\"\n                    )}\n                  />\n                </motion.div>\n                <span className=\"font-mono font-semibold text-neutral-800 dark:text-neutral-200\">\n                  {likeCount.toLocaleString()}\n                </span>\n              </button>\n            </div>\n          </div>\n\n          {/* Theme Palette Chooser */}\n          <div className=\"rounded-2xl border border-neutral-200 bg-white p-3.5 shadow-xs dark:border-neutral-800 dark:bg-neutral-900\">\n            <div className=\"mb-2 text-[11px] font-medium text-neutral-500\">\n              Confetti Sparkle Theme:\n            </div>\n            <div className=\"flex items-center gap-2\">\n              {([\"instagram\", \"crimson\", \"violet\", \"gold\"] as const).map((t) => (\n                <button\n                  key={t}\n                  type=\"button\"\n                  onClick={() => setActiveTheme(t)}\n                  className={cn(\n                    \"capitalize rounded-lg px-2.5 py-1 text-xs font-semibold transition\",\n                    activeTheme === t\n                      ? \"bg-neutral-900 text-white dark:bg-white dark:text-neutral-900\"\n                      : \"bg-neutral-100 text-neutral-600 hover:bg-neutral-200 dark:bg-neutral-800 dark:text-neutral-300 dark:hover:bg-neutral-700\"\n                  )}\n                >\n                  {t}\n                </button>\n              ))}\n            </div>\n\n            <div className=\"mt-3 border-t border-neutral-100 pt-3 dark:border-neutral-800\">\n              <div className=\"mb-2 text-[11px] font-medium text-neutral-500\">\n                Button Size:\n              </div>\n              <div className=\"flex items-center gap-1.5\">\n                {([\"sm\", \"md\", \"lg\", \"xl\"] as const).map((s) => (\n                  <button\n                    key={s}\n                    type=\"button\"\n                    onClick={() => setActiveSize(s)}\n                    className={cn(\n                      \"uppercase rounded-md px-2 py-0.5 text-[11px] font-mono font-medium transition\",\n                      activeSize === s\n                        ? \"bg-rose-500 text-white\"\n                        : \"bg-neutral-100 text-neutral-600 hover:bg-neutral-200 dark:bg-neutral-800 dark:text-neutral-300\"\n                    )}\n                  >\n                    {s}\n                  </button>\n                ))}\n              </div>\n            </div>\n          </div>\n        </div>\n      </div>\n\n      {/* Footer reset bar */}\n      <div className=\"relative z-10 flex flex-wrap items-center justify-between gap-3 border-t border-neutral-200/80 pt-4 dark:border-neutral-800/80\">\n        <span className=\"text-xs text-neutral-500\">\n          State: <strong className=\"text-neutral-900 dark:text-white\">{isLiked ? \"Liked\" : \"Unliked\"}</strong> ({likeCount} total)\n        </span>\n        <button\n          type=\"button\"\n          onClick={() => {\n            setIsLiked(false);\n            setLikeCount(initialCount);\n          }}\n          className=\"flex items-center gap-1 text-xs text-neutral-500 underline transition hover:text-neutral-900 dark:text-neutral-400 dark:hover:text-white\"\n        >\n          <RotateCcw className=\"h-3 w-3\" />\n          <span>Reset Likes</span>\n        </button>\n      </div>\n    </div>\n  );\n}\n\nexport default HeartBurstButton;\n",
          "type": "registry:ui",
          "target": "components/ui/heart-burst-button.tsx"
        },
        {
          "path": "lib/utils.ts",
          "content": "import { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...inputs: ClassValue[]) {\n  return twMerge(clsx(inputs));\n}\n\nexport async function copyToClipboard(text: string): Promise<boolean> {\n  if (typeof window === \"undefined\") return false;\n\n  try {\n    if (navigator.clipboard && window.isSecureContext) {\n      await navigator.clipboard.writeText(text);\n      return true;\n    }\n\n    const textArea = document.createElement(\"textarea\");\n    textArea.value = text;\n    textArea.style.position = \"fixed\";\n    textArea.style.left = \"-999999px\";\n    textArea.style.top = \"-999999px\";\n    document.body.appendChild(textArea);\n    textArea.focus();\n    textArea.select();\n    const succeeded = document.execCommand(\"copy\");\n    textArea.remove();\n    return succeeded;\n  } catch {\n    return false;\n  }\n}\n",
          "type": "registry:lib",
          "target": "lib/utils.ts"
        }
      ]
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "hold-to-confirm-button",
      "type": "registry:ui",
      "title": "Hold To Confirm Button",
      "author": "Rishabh Bose <https://theb0se.vercel.app/>",
      "description": "Press-and-hold safety action button with a spring-pressured progress fill that recoils elastically when released early.",
      "dependencies": [
        "framer-motion",
        "lucide-react",
        "clsx",
        "tailwind-merge"
      ],
      "files": [
        {
          "path": "components/ui/hold-to-confirm-button.tsx",
          "content": "\"use client\";\n\nimport React, { useEffect, useRef, useState } from \"react\";\nimport {\n  motion,\n  useMotionValue,\n  useSpring,\n  useTransform,\n  useReducedMotion,\n} from \"framer-motion\";\nimport { ShieldAlert, Check, RotateCcw } from \"lucide-react\";\nimport { cn } from \"@/lib/utils\";\n\nexport interface HoldToConfirmButtonProps {\n  /** Default button label before confirmation. Default: \"Hold to Purge Cache\" */\n  label?: string;\n  /** Label displayed once hold threshold is completed. Default: \"Cache Purged\" */\n  confirmedLabel?: string;\n  /** Hold duration in milliseconds required to trigger confirmation. Default: 1400 */\n  holdDuration?: number;\n  /** Visual variant. Default: \"default\" */\n  variant?: \"default\" | \"danger\";\n  /** Disable button interactions. Default: false */\n  disabled?: boolean;\n  /** Spring stiffness coefficient for fill bar snap-back. Default: 280 */\n  stiffness?: number;\n  /** Spring damping coefficient for fill bar snap-back. Default: 24 */\n  damping?: number;\n  /** Callback fired when hold completes 100% */\n  onConfirm?: () => void;\n  className?: string;\n}\n\nexport function HoldToConfirmButton({\n  label = \"Hold to Purge Cache\",\n  confirmedLabel = \"Cache Purged\",\n  holdDuration = 1400,\n  variant = \"default\",\n  disabled = false,\n  stiffness = 280,\n  damping = 24,\n  onConfirm,\n  className,\n}: HoldToConfirmButtonProps) {\n  const shouldReduceMotion = useReducedMotion() ?? false;\n  const [isHolding, setIsHolding] = useState(false);\n  const [isConfirmed, setIsConfirmed] = useState(false);\n\n  const progress = useMotionValue(0);\n  const springProgress = useSpring(progress, {\n    stiffness,\n    damping,\n    mass: 0.4,\n  });\n\n  const fillWidth = useTransform(\n    springProgress,\n    (v) => `${Math.max(0, Math.min(100, v))}%`\n  );\n\n  const rafRef = useRef<number | null>(null);\n  const startTimeRef = useRef<number>(0);\n\n  const stopHolding = () => {\n    if (rafRef.current !== null) {\n      cancelAnimationFrame(rafRef.current);\n      rafRef.current = null;\n    }\n    setIsHolding(false);\n    if (!isConfirmed) {\n      progress.set(0);\n    }\n  };\n\n  const startHolding = () => {\n    if (disabled) return;\n    if (isConfirmed) {\n      setIsConfirmed(false);\n      progress.set(0);\n      return;\n    }\n\n    setIsHolding(true);\n    startTimeRef.current = performance.now();\n\n    const tick = (now: number) => {\n      const elapsed = now - startTimeRef.current;\n      const pct = Math.min(100, (elapsed / holdDuration) * 100);\n      progress.set(pct);\n\n      if (pct >= 100) {\n        setIsHolding(false);\n        setIsConfirmed(true);\n        onConfirm?.();\n        rafRef.current = null;\n      } else {\n        rafRef.current = requestAnimationFrame(tick);\n      }\n    };\n\n    rafRef.current = requestAnimationFrame(tick);\n  };\n\n  useEffect(() => {\n    return () => {\n      if (rafRef.current !== null) {\n        cancelAnimationFrame(rafRef.current);\n      }\n    };\n  }, []);\n\n  const handleKeyDown = (e: React.KeyboardEvent<HTMLButtonElement>) => {\n    if (disabled) return;\n    if ((e.key === \" \" || e.key === \"Enter\") && !e.repeat && !isHolding) {\n      e.preventDefault();\n      startHolding();\n    }\n  };\n\n  const handleKeyUp = (e: React.KeyboardEvent<HTMLButtonElement>) => {\n    if (e.key === \" \" || e.key === \"Enter\") {\n      e.preventDefault();\n      stopHolding();\n    }\n  };\n\n  return (\n    <div className=\"inline-flex flex-col items-center gap-2\">\n      <motion.button\n        type=\"button\"\n        disabled={disabled}\n        aria-live=\"polite\"\n        onPointerDown={startHolding}\n        onPointerUp={stopHolding}\n        onPointerLeave={stopHolding}\n        onPointerCancel={stopHolding}\n        onKeyDown={handleKeyDown}\n        onKeyUp={handleKeyUp}\n        animate={{\n          scale: isHolding && !shouldReduceMotion && !disabled ? 0.96 : 1,\n        }}\n        transition={{ type: \"spring\", stiffness: 400, damping: 22 }}\n        className={cn(\n          \"group relative inline-flex h-12 min-w-[220px] select-none touch-none items-center justify-center overflow-hidden rounded-2xl border px-6 text-xs font-semibold tracking-tight transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-black dark:focus-visible:ring-white disabled:cursor-not-allowed disabled:opacity-45\",\n          isConfirmed\n            ? variant === \"danger\"\n              ? \"border-red-600 bg-red-600 text-white dark:border-red-500 dark:bg-red-500 dark:text-white\"\n              : \"border-black bg-black text-white dark:border-white dark:bg-white dark:text-black\"\n            : variant === \"danger\"\n              ? \"border-red-300 bg-red-50/60 text-red-700 hover:border-red-500 dark:border-red-900/60 dark:bg-red-950/30 dark:text-red-300 dark:hover:border-red-700\"\n              : \"border-neutral-300 bg-white text-black hover:border-black dark:border-[#262626] dark:bg-[#0A0A0A] dark:text-white dark:hover:border-white\",\n          className\n        )}\n      >\n        {/* Spring-pressured progress fill overlay */}\n        {!isConfirmed && (\n          <motion.span\n            aria-hidden=\"true\"\n            style={{ width: fillWidth }}\n            className={cn(\n              \"pointer-events-none absolute inset-y-0 left-0\",\n              variant === \"danger\"\n                ? \"bg-red-500/20 dark:bg-red-500/25\"\n                : \"bg-black/10 dark:bg-white/15\"\n            )}\n          />\n        )}\n\n        <span className=\"relative z-10 flex items-center gap-2\">\n          {isConfirmed ? (\n            <>\n              <Check className=\"h-4 w-4\" />\n              <span>{confirmedLabel}</span>\n              <RotateCcw className=\"ml-1 h-3 w-3 opacity-60\" />\n            </>\n          ) : (\n            <>\n              <ShieldAlert\n                className={cn(\n                  \"h-4 w-4 transition-transform\",\n                  isHolding && !shouldReduceMotion && \"scale-110\"\n                )}\n              />\n              <span>{isHolding ? \"Keep Holding...\" : label}</span>\n            </>\n          )}\n        </span>\n      </motion.button>\n\n      <span className=\"text-[11px] text-neutral-400 dark:text-neutral-500\">\n        {disabled\n          ? \"Action disabled\"\n          : isConfirmed\n            ? \"Click to reset state\"\n            : `Press & hold for ${(holdDuration / 1000).toFixed(1)}s (or Spacebar)`}\n      </span>\n    </div>\n  );\n}\n\nexport default HoldToConfirmButton;\n",
          "type": "registry:ui",
          "target": "components/ui/hold-to-confirm-button.tsx"
        },
        {
          "path": "lib/utils.ts",
          "content": "import { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...inputs: ClassValue[]) {\n  return twMerge(clsx(inputs));\n}\n\nexport async function copyToClipboard(text: string): Promise<boolean> {\n  if (typeof window === \"undefined\") return false;\n\n  try {\n    if (navigator.clipboard && window.isSecureContext) {\n      await navigator.clipboard.writeText(text);\n      return true;\n    }\n\n    const textArea = document.createElement(\"textarea\");\n    textArea.value = text;\n    textArea.style.position = \"fixed\";\n    textArea.style.left = \"-999999px\";\n    textArea.style.top = \"-999999px\";\n    document.body.appendChild(textArea);\n    textArea.focus();\n    textArea.select();\n    const succeeded = document.execCommand(\"copy\");\n    textArea.remove();\n    return succeeded;\n  } catch {\n    return false;\n  }\n}\n",
          "type": "registry:lib",
          "target": "lib/utils.ts"
        }
      ]
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "holographic-flip-card",
      "type": "registry:ui",
      "title": "Holographic Flip Card",
      "author": "Rishabh Bose <https://theb0se.vercel.app/>",
      "description": "Dual-sided 3D interactive card combining spring-damped perspective tilt, specular foil glare tracking, and a 180-degree Y-axis kinetic flip.",
      "dependencies": [
        "framer-motion",
        "lucide-react",
        "clsx",
        "tailwind-merge"
      ],
      "files": [
        {
          "path": "components/ui/holographic-flip-card.tsx",
          "content": "\"use client\";\n\nimport React, { useRef, useState } from \"react\";\nimport {\n  motion,\n  useMotionTemplate,\n  useMotionValue,\n  useSpring,\n  useReducedMotion,\n} from \"framer-motion\";\nimport { RotateCw, Sparkles, Terminal } from \"lucide-react\";\nimport { cn } from \"@/lib/utils\";\n\nexport interface HolographicFlipCardProps {\n  /** Custom front face content */\n  front?: React.ReactNode;\n  /** Custom back face content */\n  back?: React.ReactNode;\n  /** Peak 3D perspective tilt angle in degrees on pointer hover. Default: 12 */\n  maxTilt?: number;\n  /** Hooke's Law spring stiffness coefficient for 3D rotation. Default: 220 */\n  stiffness?: number;\n  /** Spring damping coefficient for 3D rotation. Default: 22 */\n  damping?: number;\n  className?: string;\n}\n\nexport function HolographicFlipCard({\n  front,\n  back,\n  maxTilt = 12,\n  stiffness = 220,\n  damping = 22,\n  className,\n}: HolographicFlipCardProps) {\n  const cardRef = useRef<HTMLDivElement | null>(null);\n  const shouldReduceMotion = useReducedMotion() ?? false;\n  const [isFlipped, setIsFlipped] = useState(false);\n  const [isHovered, setIsHovered] = useState(false);\n\n  const tiltX = useMotionValue(0);\n  const tiltY = useMotionValue(0);\n  const glareX = useMotionValue(50);\n  const glareY = useMotionValue(50);\n\n  const springRotateX = useSpring(tiltX, { stiffness, damping });\n  const springRotateY = useSpring(tiltY, { stiffness, damping });\n  const springGlareX = useSpring(glareX, { stiffness: 280, damping: 28 });\n  const springGlareY = useSpring(glareY, { stiffness: 280, damping: 28 });\n\n  const glareBackground = useMotionTemplate`radial-gradient(260px circle at ${springGlareX}% ${springGlareY}%, rgba(255, 255, 255, 0.22), rgba(160, 160, 160, 0.08) 45%, transparent 80%)`;\n\n  const toggleFlip = () => {\n    const nextFlipped = !isFlipped;\n    setIsFlipped(nextFlipped);\n    tiltY.set(nextFlipped ? 180 : 0);\n    tiltX.set(0);\n  };\n\n  const handleMouseMove = (e: React.MouseEvent<HTMLDivElement>) => {\n    const el = cardRef.current;\n    if (!el || shouldReduceMotion) return;\n    const rect = el.getBoundingClientRect();\n    const x = e.clientX - rect.left;\n    const y = e.clientY - rect.top;\n\n    const pctX = (x / rect.width - 0.5) * 2;\n    const pctY = (y / rect.height - 0.5) * 2;\n\n    const baseFlipAngle = isFlipped ? 180 : 0;\n    tiltX.set(-pctY * maxTilt);\n    tiltY.set(baseFlipAngle + pctX * maxTilt);\n\n    glareX.set((x / rect.width) * 100);\n    glareY.set((y / rect.height) * 100);\n  };\n\n  const handleMouseLeave = () => {\n    setIsHovered(false);\n    tiltX.set(0);\n    tiltY.set(isFlipped ? 180 : 0);\n  };\n\n  const handleKeyDown = (e: React.KeyboardEvent<HTMLDivElement>) => {\n    if (e.key === \"Enter\" || e.key === \" \") {\n      e.preventDefault();\n      toggleFlip();\n    }\n  };\n\n  return (\n    <div\n      style={{ perspective: \"1200px\" }}\n      className={cn(\"w-full max-w-sm select-none\", className)}\n    >\n      <motion.div\n        ref={cardRef}\n        role=\"button\"\n        tabIndex={0}\n        aria-pressed={isFlipped}\n        aria-label={\n          isFlipped\n            ? \"Holographic card showing back face. Press Enter or Space to flip to front.\"\n            : \"Holographic card showing front face. Press Enter or Space to flip to back.\"\n        }\n        onClick={toggleFlip}\n        onKeyDown={handleKeyDown}\n        onMouseMove={handleMouseMove}\n        onMouseEnter={() => setIsHovered(true)}\n        onMouseLeave={handleMouseLeave}\n        style={{\n          rotateX: shouldReduceMotion ? 0 : springRotateX,\n          rotateY: shouldReduceMotion ? (isFlipped ? 180 : 0) : springRotateY,\n          transformStyle: \"preserve-3d\",\n        }}\n        className=\"group relative min-h-[210px] w-full cursor-pointer rounded-2xl focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-black dark:focus-visible:ring-white\"\n      >\n        {/* Front Face */}\n        <div\n          style={{ backfaceVisibility: \"hidden\" }}\n          className=\"relative flex min-h-[210px] flex-col justify-between overflow-hidden rounded-2xl border border-neutral-200 bg-white p-6 shadow-sm transition-colors group-hover:border-neutral-400 dark:border-[#222222] dark:bg-[#0A0A0A] dark:group-hover:border-[#383838]\"\n        >\n          <motion.div\n            aria-hidden=\"true\"\n            style={{\n              background: glareBackground,\n              opacity: isHovered && !isFlipped ? 1 : 0,\n            }}\n            className=\"pointer-events-none absolute inset-0 transition-opacity duration-300\"\n          />\n\n          {front || (\n            <>\n              <div className=\"relative z-10 flex items-center justify-between\">\n                <span className=\"inline-flex items-center gap-1.5 rounded-full border border-neutral-200 bg-neutral-50 px-2.5 py-1 text-[10px] font-semibold uppercase tracking-wider text-black dark:border-[#262626] dark:bg-[#141414] dark:text-white\">\n                  <Sparkles className=\"h-3 w-3\" />\n                  3D Specular Surface\n                </span>\n                <RotateCw className=\"h-4 w-4 text-neutral-400 transition-transform group-hover:rotate-45 group-hover:text-black dark:group-hover:text-white\" />\n              </div>\n\n              <div className=\"relative z-10 mt-6\">\n                <div className=\"text-base font-semibold text-black dark:text-white\">\n                  Holographic Flip Card\n                </div>\n                <p className=\"mt-1 text-xs leading-relaxed text-neutral-500 dark:text-neutral-400\">\n                  Hover for coupled 3D perspective tilt &amp; foil sheen. Click or\n                  press Enter to flip 180° around the Y-axis.\n                </p>\n              </div>\n            </>\n          )}\n        </div>\n\n        {/* Back Face */}\n        <div\n          style={{\n            backfaceVisibility: \"hidden\",\n            transform: \"rotateY(180deg)\",\n          }}\n          className=\"absolute inset-0 flex min-h-[210px] flex-col justify-between overflow-hidden rounded-2xl border border-neutral-800 bg-neutral-950 p-6 text-white shadow-sm dark:border-neutral-200 dark:bg-white dark:text-black\"\n        >\n          {back || (\n            <>\n              <div className=\"flex items-center justify-between\">\n                <span className=\"inline-flex items-center gap-1.5 font-mono text-[11px] font-semibold text-neutral-300 dark:text-neutral-600\">\n                  <Terminal className=\"h-3.5 w-3.5\" />\n                  SPRING_TELEMETRY\n                </span>\n                <RotateCw className=\"h-4 w-4 text-neutral-400\" />\n              </div>\n\n              <div className=\"my-auto space-y-2 font-mono text-xs\">\n                <div className=\"flex justify-between border-b border-white/10 pb-1.5 dark:border-black/10\">\n                  <span className=\"text-neutral-400 dark:text-neutral-500\">\n                    stiffness:\n                  </span>\n                  <span className=\"font-semibold\">{stiffness} N/m</span>\n                </div>\n                <div className=\"flex justify-between border-b border-white/10 pb-1.5 dark:border-black/10\">\n                  <span className=\"text-neutral-400 dark:text-neutral-500\">\n                    damping:\n                  </span>\n                  <span className=\"font-semibold\">{damping} Ns/m</span>\n                </div>\n                <div className=\"flex justify-between\">\n                  <span className=\"text-neutral-400 dark:text-neutral-500\">\n                    maxTilt:\n                  </span>\n                  <span className=\"font-semibold\">±{maxTilt}°</span>\n                </div>\n              </div>\n\n              <div className=\"text-[11px] text-neutral-400 dark:text-neutral-500\">\n                Click or press Space to return to front\n              </div>\n            </>\n          )}\n        </div>\n      </motion.div>\n    </div>\n  );\n}\n\nexport default HolographicFlipCard;\n",
          "type": "registry:ui",
          "target": "components/ui/holographic-flip-card.tsx"
        },
        {
          "path": "lib/utils.ts",
          "content": "import { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...inputs: ClassValue[]) {\n  return twMerge(clsx(inputs));\n}\n\nexport async function copyToClipboard(text: string): Promise<boolean> {\n  if (typeof window === \"undefined\") return false;\n\n  try {\n    if (navigator.clipboard && window.isSecureContext) {\n      await navigator.clipboard.writeText(text);\n      return true;\n    }\n\n    const textArea = document.createElement(\"textarea\");\n    textArea.value = text;\n    textArea.style.position = \"fixed\";\n    textArea.style.left = \"-999999px\";\n    textArea.style.top = \"-999999px\";\n    document.body.appendChild(textArea);\n    textArea.focus();\n    textArea.select();\n    const succeeded = document.execCommand(\"copy\");\n    textArea.remove();\n    return succeeded;\n  } catch {\n    return false;\n  }\n}\n",
          "type": "registry:lib",
          "target": "lib/utils.ts"
        }
      ]
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "horizon-light",
      "type": "registry:ui",
      "title": "Horizon Light",
      "author": "Rishabh Bose <https://theb0se.vercel.app/>",
      "description": "WebGL planetary horizon limb shader with a razor-sharp incandescent core, volumetric FBM atmospheric corona, interactive solar apex tracking, and 8-bit dithered bloom.",
      "dependencies": [
        "clsx",
        "tailwind-merge"
      ],
      "files": [
        {
          "path": "components/ui/horizon-light.tsx",
          "content": "\"use client\";\n\nimport React, { useEffect, useRef, useState } from \"react\";\nimport { cn } from \"@/lib/utils\";\n\nconst VERTEX_SHADER = `\n  attribute vec2 a_position;\n  varying vec2 v_uv;\n  void main() {\n    v_uv = a_position * 0.5 + 0.5;\n    gl_Position = vec4(a_position, 0.0, 1.0);\n  }\n`;\n\n/**\n * Fragment Shader: Planetary Horizon Light & Volumetric Ember Corona\n *\n * Renders a physical curved planetary horizon limb with:\n * - Razor-sharp incandescent core along the curved horizon arc\n * - Volumetric atmospheric scatter rising above the horizon\n * - Subtle radial sunbeams / god-rays emanating from the horizon apex (interactive with pointer X/Y)\n * - Deep Warm Graphite eclipse occlusion (or warm architectural bone in light mode) below the horizon curve\n * - High-frequency optical dither to eliminate 8-bit gradient banding\n */\nconst FRAGMENT_SHADER = `\n  precision highp float;\n\n  varying vec2 v_uv;\n  uniform float u_time;\n  uniform vec2 u_resolution;\n  uniform vec2 u_mouse;\n  uniform float u_lightMode;\n  uniform float u_apexY;\n  uniform float u_intensity;\n  uniform vec3 u_primaryColor;\n  uniform vec3 u_secondaryColor;\n  uniform vec3 u_deepColor;\n  uniform vec3 u_coreColor;\n\n  float hash(vec2 p) {\n    p = fract(p * vec2(123.34, 456.21));\n    p += dot(p, p + 45.32);\n    return fract(p.x * p.y);\n  }\n\n  float noise(vec2 p) {\n    vec2 i = floor(p);\n    vec2 f = fract(p);\n    // Quintic C2 interpolation for ultra-soft, crease-free volumetric transitions\n    vec2 u = f * f * f * (f * (f * 6.0 - 15.0) + 10.0);\n    float a = hash(i);\n    float b = hash(i + vec2(1.0, 0.0));\n    float c = hash(i + vec2(0.0, 1.0));\n    float d = hash(i + vec2(1.0, 1.0));\n    return mix(mix(a, b, u.x), mix(c, d, u.x), u.y);\n  }\n\n  float softFbm(vec2 p) {\n    float v = 0.0;\n    float a = 0.55;\n    mat2 rot = mat2(0.8, 0.6, -0.6, 0.8);\n    // 2 low-frequency octaves for wide, pillowy atmospheric light shafts\n    for (int i = 0; i < 2; i++) {\n      v += a * noise(p);\n      p = rot * p * 1.65 + vec2(1.7, 9.2);\n      a *= 0.45;\n    }\n    return v;\n  }\n\n  void main() {\n    vec2 uv = v_uv;\n    float aspect = u_resolution.x / max(u_resolution.y, 1.0);\n\n    // Normalized centered coordinates: x in [-aspect*0.5, aspect*0.5], y in [0, 1] (0 = bottom, 1 = top)\n    vec2 p = vec2((uv.x - 0.5) * aspect, uv.y);\n\n    // Interactive pointer offset shifts the solar apex gently along the horizon\n    float mouseShiftX = (u_mouse.x - 0.5) * 0.28 * aspect;\n    float mouseLiftY = (u_mouse.y - 0.5) * 0.03;\n\n    // Giant planetary circle centered far below the frame so its top arc forms the horizon line\n    float radius = max(aspect * 1.45, 2.1);\n    float apexY = u_apexY + mouseLiftY;\n    vec2 planetCenter = vec2(0.0, apexY - radius);\n\n    // Signed distance from planetary surface:\n    // dist > 0.0 => sky/atmosphere above the horizon\n    // dist == 0.0 => exact curved horizon rim\n    // dist < 0.0 => planetary surface below the horizon\n    vec2 toFrag = p - planetCenter;\n    float dist = length(toFrag) - radius;\n\n    // Horizontal distance from the solar apex (shifted slightly by pointer)\n    float horizDist = (p.x - mouseShiftX * 0.35) / max(aspect * 0.55, 0.8);\n    float centerFalloff = exp(-horizDist * horizDist * 1.85);\n    float wideFalloff = exp(-horizDist * horizDist * 0.65);\n\n    // Soft, wide-angle volumetric rays anchored deep below the horizon so atan() never pinches\n    vec2 rayOrigin = vec2(mouseShiftX * 0.3, apexY - 0.65);\n    vec2 rayDir = normalize(p - rayOrigin);\n    float angle = atan(rayDir.x, max(rayDir.y, 0.15));\n\n    // Combine gentle cosine lobes with low-frequency quintic noise for diffused, cloud-soft beams\n    float primaryWave = sin(angle * 2.4 + u_time * 0.08) * 0.5 + 0.5;\n    float secondaryWave = cos(angle * 4.1 - u_time * 0.05) * 0.5 + 0.5;\n    float softNoise = softFbm(vec2(angle * 2.2 + u_time * 0.04, max(dist, 0.0) * 1.1 - u_time * 0.07));\n    float rawRays = mix(primaryWave * 0.55 + secondaryWave * 0.45, softNoise, 0.5);\n    float raySmooth = smoothstep(0.15, 0.85, rawRays);\n\n    // Fade ray modulation smoothly away from the horizon limb so the core stays seamless\n    float rayAltitudeFade = smoothstep(0.0, 0.16, max(dist, 0.0)) * smoothstep(0.65, 0.08, max(dist, 0.0));\n    float rayMod = mix(1.0, mix(0.86, 1.16, raySmooth), rayAltitudeFade);\n\n    // 1. Ultra-crisp horizon limb line (the glowing arc itself)\n    float rimCore = exp(-abs(dist) * 140.0) * (0.35 + 0.95 * centerFalloff) * u_intensity;\n    float rimTight = exp(-abs(dist) * 38.0) * (0.25 + 0.85 * centerFalloff) * u_intensity;\n\n    // 2. Upper atmospheric scatter (rising above the horizon: dist > 0)\n    float aboveMask = smoothstep(-0.02, 0.015, dist);\n    float posDist = max(dist, 0.0);\n    float innerCorona = exp(-posDist * 11.5) * centerFalloff * aboveMask * u_intensity;\n    float midAtmosphere = exp(-posDist * 4.2) * wideFalloff * rayMod * aboveMask * u_intensity;\n    float outerBloom = exp(-posDist * 1.85) * wideFalloff * rayMod * aboveMask * u_intensity;\n\n    // 3. Sub-horizon inner planetary rim glow (subtle reflection below the arc: dist < 0)\n    float belowMask = 1.0 - smoothstep(-0.005, 0.01, dist);\n    float negDist = max(-dist, 0.0);\n    float subHorizonGlow = exp(-negDist * 16.0) * (0.2 + 0.65 * centerFalloff) * belowMask * u_intensity;\n\n    vec3 darkBg = vec3(0.047, 0.047, 0.043);      // #0c0c0b\n    vec3 lightBg = vec3(0.957, 0.945, 0.918);     // #f4f1ea\n\n    // Dark Mode composition: Eclipse planet with luminous corona\n    vec3 darkCol = darkBg;\n    darkCol += u_deepColor * outerBloom * 0.75;\n    darkCol += u_primaryColor * midAtmosphere * 0.72;\n    darkCol += u_secondaryColor * innerCorona * 0.68;\n    darkCol += mix(u_primaryColor, u_secondaryColor, 0.5) * rimTight * 0.85;\n    darkCol += u_coreColor * rimCore * 0.95;\n    darkCol += mix(u_deepColor, u_primaryColor, 0.35) * subHorizonGlow * 0.45;\n\n    // Light Mode composition: Warm architectural bone with crisp horizon illumination\n    vec3 lightCol = lightBg;\n    lightCol = mix(lightCol, vec3(1.0, 0.86, 0.76), outerBloom * 0.55);\n    lightCol = mix(lightCol, u_secondaryColor, midAtmosphere * 0.38);\n    lightCol = mix(lightCol, u_primaryColor, innerCorona * 0.42);\n    lightCol = mix(lightCol, u_primaryColor, rimTight * 0.58);\n    lightCol += vec3(1.0, 0.96, 0.90) * rimCore * 0.42;\n    lightCol = mix(lightCol, vec3(0.92, 0.89, 0.84), belowMask * (1.0 - subHorizonGlow * 0.6) * 0.35);\n\n    vec3 col = mix(darkCol, lightCol, u_lightMode);\n\n    // Subtle edge vignette so the top corners stay clean for navbar & typography\n    float topFade = smoothstep(0.98, 0.62, uv.y);\n    col = mix(mix(darkBg, lightBg, u_lightMode), col, topFade);\n\n    // High-frequency filmic grain dither to prevent 8-bit gradient banding\n    float grain = (hash(gl_FragCoord.xy + fract(u_time) * 100.0) - 0.5) / 255.0;\n    col += grain * 1.6;\n\n    gl_FragColor = vec4(clamp(col, 0.0, 1.0), 1.0);\n  }\n`;\n\nfunction hexToRgbNormalized(hex: string): [number, number, number] {\n  const clean = hex.replace(\"#\", \"\").trim();\n  const full =\n    clean.length === 3\n      ? clean\n          .split(\"\")\n          .map((c) => c + c)\n          .join(\"\")\n      : clean.padEnd(6, \"0\");\n  const num = parseInt(full.slice(0, 6), 16);\n  if (Number.isNaN(num)) return [1.0, 0.302, 0.11];\n  return [\n    ((num >> 16) & 255) / 255,\n    ((num >> 8) & 255) / 255,\n    (num & 255) / 255,\n  ];\n}\n\nexport interface HorizonLightPreset {\n  id: string;\n  label: string;\n  primaryColor: string;\n  secondaryColor: string;\n  deepColor: string;\n  coreColor: string;\n}\n\nexport const HORIZON_LIGHT_PRESETS: HorizonLightPreset[] = [\n  {\n    id: \"ember\",\n    label: \"Vermilion Eclipse\",\n    primaryColor: \"#FF4D1C\",\n    secondaryColor: \"#FF8A3D\",\n    deepColor: \"#6E1404\",\n    coreColor: \"#FFF3E0\",\n  },\n  {\n    id: \"cobalt\",\n    label: \"Orbital Cobalt\",\n    primaryColor: \"#2563EB\",\n    secondaryColor: \"#38BDF8\",\n    deepColor: \"#0B1D51\",\n    coreColor: \"#F0F9FF\",\n  },\n  {\n    id: \"emerald\",\n    label: \"Solaris Borealis\",\n    primaryColor: \"#10B981\",\n    secondaryColor: \"#6EE7B7\",\n    deepColor: \"#064E3B\",\n    coreColor: \"#ECFDF5\",\n  },\n  {\n    id: \"supernova\",\n    label: \"Violet Supernova\",\n    primaryColor: \"#9333EA\",\n    secondaryColor: \"#F472B6\",\n    deepColor: \"#3B0764\",\n    coreColor: \"#FAF5FF\",\n  },\n];\n\nexport interface HorizonLightProps {\n  /** Primary atmospheric scatter color (default: \"#FF4D1C\" International Vermilion) */\n  primaryColor?: string;\n  /** Inner corona glow color (default: \"#FF8A3D\" Solar Amber) */\n  secondaryColor?: string;\n  /** Outer deep atmospheric bloom color (default: \"#6E1404\" Deep Crimson Ember) */\n  deepColor?: string;\n  /** Razor-sharp planetary limb core color (default: \"#FFF3E0\" Incandescent Core) */\n  coreColor?: string;\n  /** Vertical position of the planetary horizon apex (0.2 to 0.75, default: 0.43) */\n  horizonHeight?: number;\n  /** Overall corona and limb intensity multiplier (0.4 to 1.8, default: 1.0) */\n  intensity?: number;\n  /** Speed multiplier for volumetric FBM god-rays (default: 1.0) */\n  speed?: number;\n  /** Whether pointer X/Y gently shifts the solar apex along the curved limb */\n  interactive?: boolean;\n  /** Shader surface mode: \"dark\" (Warm Graphite eclipse), \"light\" (Architectural Bone), or \"auto\" */\n  themeMode?: \"dark\" | \"light\" | \"auto\";\n  /** Optional custom foreground content */\n  children?: React.ReactNode;\n  /** Additional container class names */\n  className?: string;\n}\n\nexport function HorizonLight({\n  primaryColor = \"#FF4D1C\",\n  secondaryColor = \"#FF8A3D\",\n  deepColor = \"#6E1404\",\n  coreColor = \"#FFF3E0\",\n  horizonHeight = 0.43,\n  intensity = 1.0,\n  speed = 1.0,\n  interactive = true,\n  themeMode = \"dark\",\n  children,\n  className,\n}: HorizonLightProps) {\n  const containerRef = useRef<HTMLDivElement>(null);\n  const canvasRef = useRef<HTMLCanvasElement>(null);\n\n  // Interactive HUD state for standalone demo preview\n  const [activePresetId, setActivePresetId] = useState<string>(\"ember\");\n  const [localLightMode, setLocalLightMode] = useState<boolean>(\n    themeMode === \"light\"\n  );\n  const [localApexY, setLocalApexY] = useState<number>(horizonHeight);\n\n  useEffect(() => {\n    setLocalApexY(horizonHeight);\n  }, [horizonHeight]);\n\n  useEffect(() => {\n    if (themeMode !== \"auto\") {\n      setLocalLightMode(themeMode === \"light\");\n    }\n  }, [themeMode]);\n\n  const activePreset = HORIZON_LIGHT_PRESETS.find(\n    (p) => p.id === activePresetId\n  );\n\n  const effectivePrimary =\n    activePresetId === \"ember\"\n      ? primaryColor\n      : (activePreset?.primaryColor ?? primaryColor);\n  const effectiveSecondary =\n    activePresetId === \"ember\"\n      ? secondaryColor\n      : (activePreset?.secondaryColor ?? secondaryColor);\n  const effectiveDeep =\n    activePresetId === \"ember\"\n      ? deepColor\n      : (activePreset?.deepColor ?? deepColor);\n  const effectiveCore =\n    activePresetId === \"ember\"\n      ? coreColor\n      : (activePreset?.coreColor ?? coreColor);\n\n  // Keep latest uniform values in a ref so the WebGL loop updates smoothly without recreating the context\n  const uniformsRef = useRef({\n    primary: hexToRgbNormalized(effectivePrimary),\n    secondary: hexToRgbNormalized(effectiveSecondary),\n    deep: hexToRgbNormalized(effectiveDeep),\n    core: hexToRgbNormalized(effectiveCore),\n    apexY: localApexY,\n    intensity,\n    speed,\n    interactive,\n    lightModeTarget: localLightMode ? 1.0 : 0.0,\n  });\n\n  useEffect(() => {\n    uniformsRef.current = {\n      primary: hexToRgbNormalized(effectivePrimary),\n      secondary: hexToRgbNormalized(effectiveSecondary),\n      deep: hexToRgbNormalized(effectiveDeep),\n      core: hexToRgbNormalized(effectiveCore),\n      apexY: localApexY,\n      intensity,\n      speed,\n      interactive,\n      lightModeTarget: localLightMode ? 1.0 : 0.0,\n    };\n  }, [\n    effectivePrimary,\n    effectiveSecondary,\n    effectiveDeep,\n    effectiveCore,\n    localApexY,\n    intensity,\n    speed,\n    interactive,\n    localLightMode,\n  ]);\n\n  // Sync with document theme only when themeMode === \"auto\"\n  useEffect(() => {\n    if (themeMode !== \"auto\") return;\n    const checkTheme = () => {\n      const html = document.documentElement;\n      const isLight =\n        html.classList.contains(\"light\") || !html.classList.contains(\"dark\");\n      setLocalLightMode(isLight);\n    };\n    checkTheme();\n    const observer = new MutationObserver(checkTheme);\n    observer.observe(document.documentElement, {\n      attributes: true,\n      attributeFilter: [\"class\"],\n    });\n    return () => observer.disconnect();\n  }, [themeMode]);\n\n  useEffect(() => {\n    const canvas = canvasRef.current;\n    const container = containerRef.current;\n    if (!canvas || !container) return;\n\n    const gl = canvas.getContext(\"webgl\", {\n      alpha: false,\n      antialias: false,\n      powerPreference: \"high-performance\",\n    });\n\n    if (!gl) return;\n\n    const compileShader = (type: number, source: string) => {\n      const shader = gl.createShader(type);\n      if (!shader) return null;\n      gl.shaderSource(shader, source);\n      gl.compileShader(shader);\n      if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {\n        gl.deleteShader(shader);\n        return null;\n      }\n      return shader;\n    };\n\n    const vs = compileShader(gl.VERTEX_SHADER, VERTEX_SHADER);\n    const fs = compileShader(gl.FRAGMENT_SHADER, FRAGMENT_SHADER);\n    if (!vs || !fs) return;\n\n    const program = gl.createProgram();\n    if (!program) return;\n    gl.attachShader(program, vs);\n    gl.attachShader(program, fs);\n    gl.linkProgram(program);\n    if (!gl.getProgramParameter(program, gl.LINK_STATUS)) return;\n    gl.useProgram(program);\n\n    // Fullscreen quad\n    const buffer = gl.createBuffer();\n    gl.bindBuffer(gl.ARRAY_BUFFER, buffer);\n    gl.bufferData(\n      gl.ARRAY_BUFFER,\n      new Float32Array([-1, -1, 1, -1, -1, 1, -1, 1, 1, -1, 1, 1]),\n      gl.STATIC_DRAW\n    );\n\n    const posLoc = gl.getAttribLocation(program, \"a_position\");\n    gl.enableVertexAttribArray(posLoc);\n    gl.vertexAttribPointer(posLoc, 2, gl.FLOAT, false, 0, 0);\n\n    const uTime = gl.getUniformLocation(program, \"u_time\");\n    const uRes = gl.getUniformLocation(program, \"u_resolution\");\n    const uMouse = gl.getUniformLocation(program, \"u_mouse\");\n    const uLightMode = gl.getUniformLocation(program, \"u_lightMode\");\n    const uApexY = gl.getUniformLocation(program, \"u_apexY\");\n    const uIntensity = gl.getUniformLocation(program, \"u_intensity\");\n    const uPrimary = gl.getUniformLocation(program, \"u_primaryColor\");\n    const uSecondary = gl.getUniformLocation(program, \"u_secondaryColor\");\n    const uDeep = gl.getUniformLocation(program, \"u_deepColor\");\n    const uCore = gl.getUniformLocation(program, \"u_coreColor\");\n\n    let width = 0;\n    let height = 0;\n\n    const handleResize = () => {\n      if (!canvas || !container) return;\n      // Render at max 1.5x DPR for locked 60fps performance even on 4K displays\n      const dpr = Math.min(window.devicePixelRatio || 1, 1.5);\n      const rect = container.getBoundingClientRect();\n      width = Math.max(1, Math.floor(rect.width * dpr));\n      height = Math.max(1, Math.floor(rect.height * dpr));\n      if (canvas.width !== width || canvas.height !== height) {\n        canvas.width = width;\n        canvas.height = height;\n        gl.viewport(0, 0, width, height);\n      }\n    };\n\n    handleResize();\n    const resizeObserver = new ResizeObserver(handleResize);\n    resizeObserver.observe(container);\n    window.addEventListener(\"resize\", handleResize, { passive: true });\n\n    // Smooth damped pointer tracking\n    const targetMouse = { x: 0.5, y: 0.5 };\n    const currentMouse = { x: 0.5, y: 0.5 };\n\n    const handlePointerMove = (e: PointerEvent) => {\n      if (!uniformsRef.current.interactive || !container) return;\n      const rect = container.getBoundingClientRect();\n      if (rect.width <= 0 || rect.height <= 0) return;\n      const nx = (e.clientX - rect.left) / rect.width;\n      const ny = 1.0 - (e.clientY - rect.top) / rect.height;\n      if (nx >= 0 && nx <= 1 && ny >= 0 && ny <= 1) {\n        targetMouse.x = nx;\n        targetMouse.y = ny;\n      }\n    };\n\n    window.addEventListener(\"pointermove\", handlePointerMove, {\n      passive: true,\n    });\n\n    const reducedMotion = window.matchMedia(\n      \"(prefers-reduced-motion: reduce)\"\n    ).matches;\n\n    let rafId = 0;\n    let currentLightMode = uniformsRef.current.lightModeTarget;\n    let currentApex = uniformsRef.current.apexY;\n    const startTime = performance.now();\n\n    const render = (now: number) => {\n      const cfg = uniformsRef.current;\n      const elapsed = reducedMotion\n        ? 0.0\n        : ((now - startTime) * 0.001) * cfg.speed;\n\n      // Damped spring interpolation for pointer & parameters\n      currentMouse.x += (targetMouse.x - currentMouse.x) * 0.04;\n      currentMouse.y += (targetMouse.y - currentMouse.y) * 0.04;\n      currentLightMode += (cfg.lightModeTarget - currentLightMode) * 0.08;\n      currentApex += (cfg.apexY - currentApex) * 0.08;\n\n      gl.uniform1f(uTime, elapsed);\n      gl.uniform2f(uRes, width, height);\n      gl.uniform2f(uMouse, currentMouse.x, currentMouse.y);\n      gl.uniform1f(uLightMode, currentLightMode);\n      gl.uniform1f(uApexY, currentApex);\n      gl.uniform1f(uIntensity, cfg.intensity);\n      gl.uniform3fv(uPrimary, cfg.primary);\n      gl.uniform3fv(uSecondary, cfg.secondary);\n      gl.uniform3fv(uDeep, cfg.deep);\n      gl.uniform3fv(uCore, cfg.core);\n\n      gl.drawArrays(gl.TRIANGLES, 0, 6);\n\n      if (!reducedMotion) {\n        rafId = requestAnimationFrame(render);\n      }\n    };\n\n    rafId = requestAnimationFrame(render);\n\n    return () => {\n      cancelAnimationFrame(rafId);\n      resizeObserver.disconnect();\n      window.removeEventListener(\"resize\", handleResize);\n      window.removeEventListener(\"pointermove\", handlePointerMove);\n      gl.deleteBuffer(buffer);\n      gl.deleteProgram(program);\n      gl.deleteShader(vs);\n      gl.deleteShader(fs);\n    };\n  }, []);\n\n  return (\n    <div\n      ref={containerRef}\n      data-fullscreen-scroll\n      className={cn(\n        \"relative w-full min-h-[540px] overflow-hidden rounded-2xl select-none flex flex-col justify-between\",\n        localLightMode ? \"bg-[#f4f1ea] text-zinc-900\" : \"bg-[#0c0c0b] text-white\",\n        className\n      )}\n    >\n      {/* WebGL Planetary Horizon Shader */}\n      <canvas\n        ref={canvasRef}\n        aria-hidden=\"true\"\n        className=\"pointer-events-none absolute inset-0 h-full w-full block\"\n      />\n\n      {/* Content Layer */}\n      {children ? (\n        <div className=\"relative z-10 flex-1 flex flex-col\">{children}</div>\n      ) : (\n        <div className=\"relative z-10 flex-1 flex flex-col justify-between p-6 sm:p-10\">\n          {/* Top Telemetry Bar */}\n          <div className=\"flex flex-wrap items-center justify-between gap-3\">\n            <div\n              className={cn(\n                \"inline-flex items-center gap-2 rounded-full px-3 py-1 text-[11px] font-mono uppercase tracking-widest border backdrop-blur-md\",\n                localLightMode\n                  ? \"bg-white/60 border-zinc-900/10 text-zinc-700\"\n                  : \"bg-white/[0.04] border-white/10 text-zinc-300\"\n              )}\n            >\n              <span\n                className=\"h-1.5 w-1.5 rounded-full animate-pulse\"\n                style={{ backgroundColor: effectivePrimary }}\n              />\n              GLSL Planetary Limb SDF · 4-Octave FBM\n            </div>\n\n            {/* Mode & Preset Controls */}\n            <div className=\"flex flex-wrap items-center gap-1.5\">\n              {HORIZON_LIGHT_PRESETS.map((preset) => {\n                const isSelected = activePresetId === preset.id;\n                return (\n                  <button\n                    key={preset.id}\n                    type=\"button\"\n                    onClick={() => setActivePresetId(preset.id)}\n                    className={cn(\n                      \"inline-flex items-center gap-1.5 rounded-full px-2.5 py-1 text-xs font-medium transition-all border backdrop-blur-md\",\n                      isSelected\n                        ? localLightMode\n                          ? \"bg-zinc-900 text-white border-zinc-900 shadow-sm\"\n                          : \"bg-white text-zinc-950 border-white shadow-sm\"\n                        : localLightMode\n                          ? \"bg-white/60 text-zinc-700 border-zinc-900/10 hover:bg-white/90\"\n                          : \"bg-black/40 text-zinc-300 border-white/10 hover:bg-white/10\"\n                    )}\n                  >\n                    <span\n                      className=\"h-2 w-2 rounded-full\"\n                      style={{ backgroundColor: preset.primaryColor }}\n                    />\n                    {preset.label.split(\" \")[1]}\n                  </button>\n                );\n              })}\n\n              <button\n                type=\"button\"\n                onClick={() => setLocalLightMode((prev) => !prev)}\n                className={cn(\n                  \"ml-1 rounded-full px-2.5 py-1 text-xs font-mono border backdrop-blur-md transition-colors\",\n                  localLightMode\n                    ? \"bg-zinc-900/10 border-zinc-900/15 text-zinc-800 hover:bg-zinc-900/15\"\n                    : \"bg-white/10 border-white/15 text-zinc-200 hover:bg-white/15\"\n                )}\n              >\n                {localLightMode ? \"Light Surface\" : \"Eclipse Dark\"}\n              </button>\n            </div>\n          </div>\n\n          {/* Center Hero Copy */}\n          <div className=\"my-auto py-12 text-center max-w-2xl mx-auto\">\n            <p\n              className={cn(\n                \"text-xs font-mono uppercase tracking-[0.25em] mb-3\",\n                localLightMode ? \"text-zinc-600\" : \"text-zinc-400\"\n              )}\n            >\n              Atmospheric Scatter &amp; Solar Corona\n            </p>\n            <h2\n              className={cn(\n                \"text-3xl sm:text-5xl font-semibold tracking-tight leading-[1.08]\",\n                localLightMode ? \"text-zinc-950\" : \"text-white\"\n              )}\n            >\n              Planetary horizon light with volumetric god-rays.\n            </h2>\n            <p\n              className={cn(\n                \"mt-4 text-sm sm:text-base max-w-xl mx-auto leading-relaxed\",\n                localLightMode ? \"text-zinc-700\" : \"text-zinc-300/85\"\n              )}\n            >\n              Move your pointer across the horizon arc to shift the solar apex\n              in real time. Rendered via a signed-distance planetary sphere and\n              8-bit dithered atmospheric bloom.\n            </p>\n          </div>\n\n          {/* Bottom Horizon Elevation Scrubber */}\n          <div className=\"flex flex-wrap items-center justify-between gap-4 pt-2\">\n            <div\n              className={cn(\n                \"text-[11px] font-mono\",\n                localLightMode ? \"text-zinc-600\" : \"text-zinc-400\"\n              )}\n            >\n              APEX ELEVATION:{\" \"}\n              <span className=\"font-semibold\">\n                {Math.round(localApexY * 100)}%\n              </span>\n            </div>\n\n            <div\n              className={cn(\n                \"flex items-center gap-3 rounded-full px-3.5 py-1.5 border backdrop-blur-md\",\n                localLightMode\n                  ? \"bg-white/65 border-zinc-900/10\"\n                  : \"bg-black/45 border-white/10\"\n              )}\n            >\n              <span\n                className={cn(\n                  \"text-[11px] font-mono\",\n                  localLightMode ? \"text-zinc-600\" : \"text-zinc-400\"\n                )}\n              >\n                Horizon Arc\n              </span>\n              <input\n                type=\"range\"\n                min={0.25}\n                max={0.68}\n                step={0.01}\n                value={localApexY}\n                onChange={(e) => setLocalApexY(parseFloat(e.target.value))}\n                aria-label=\"Horizon Apex Height\"\n                className=\"w-28 accent-orange-500 cursor-pointer\"\n              />\n            </div>\n          </div>\n        </div>\n      )}\n    </div>\n  );\n}\n\nexport default HorizonLight;\n",
          "type": "registry:ui",
          "target": "components/ui/horizon-light.tsx"
        },
        {
          "path": "lib/utils.ts",
          "content": "import { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...inputs: ClassValue[]) {\n  return twMerge(clsx(inputs));\n}\n\nexport async function copyToClipboard(text: string): Promise<boolean> {\n  if (typeof window === \"undefined\") return false;\n\n  try {\n    if (navigator.clipboard && window.isSecureContext) {\n      await navigator.clipboard.writeText(text);\n      return true;\n    }\n\n    const textArea = document.createElement(\"textarea\");\n    textArea.value = text;\n    textArea.style.position = \"fixed\";\n    textArea.style.left = \"-999999px\";\n    textArea.style.top = \"-999999px\";\n    document.body.appendChild(textArea);\n    textArea.focus();\n    textArea.select();\n    const succeeded = document.execCommand(\"copy\");\n    textArea.remove();\n    return succeeded;\n  } catch {\n    return false;\n  }\n}\n",
          "type": "registry:lib",
          "target": "lib/utils.ts"
        }
      ]
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "hover-reveal-feature-grid",
      "type": "registry:ui",
      "title": "Hover Reveal Feature Grid",
      "author": "Rishabh Bose <https://theb0se.vercel.app/>",
      "description": "Linear-inspired bento feature grid where hovering any tile casts an interactive radial spotlight mask across card borders, smoothly reveals secondary deep feature specifications, and highlights contextual interactive badges.",
      "dependencies": [
        "framer-motion",
        "lucide-react",
        "clsx",
        "tailwind-merge"
      ],
      "files": [
        {
          "path": "components/ui/hover-reveal-feature-grid.tsx",
          "content": "\"use client\";\n\nimport React, { useState, useRef, useCallback } from \"react\";\nimport { motion, AnimatePresence } from \"framer-motion\";\nimport {\n  Layers,\n  Sparkles,\n  Zap,\n  Shield,\n  Cpu,\n  ArrowUpRight,\n  Sliders,\n  CheckCircle2,\n  Workflow,\n  Radio,\n  Eye,\n} from \"lucide-react\";\nimport { cn } from \"@/lib/utils\";\n\nexport type SpotlightColor = \"indigo\" | \"emerald\" | \"violet\" | \"amber\";\n\nexport interface BentoFeatureItem {\n  id: string;\n  tag: string;\n  title: string;\n  summary: string;\n  revealedDetails: string;\n  badge: string;\n  metric: string;\n  colSpan?: string;\n}\n\nexport interface HoverRevealFeatureGridProps {\n  spotlightColor?: SpotlightColor;\n  spotlightRadius?: number;\n  className?: string;\n}\n\nconst SPOTLIGHT_THEMES: Record<\n  SpotlightColor,\n  {\n    name: string;\n    radial: string;\n    borderGlow: string;\n    badgeBorder: string;\n    badgeBg: string;\n    badgeText: string;\n    accent: string;\n  }\n> = {\n  indigo: {\n    name: \"Linear Indigo\",\n    radial: \"rgba(99, 102, 241, 0.22)\",\n    borderGlow: \"rgba(129, 140, 248, 0.5)\",\n    badgeBorder: \"border-indigo-500/40\",\n    badgeBg: \"bg-indigo-950/60\",\n    badgeText: \"text-indigo-300\",\n    accent: \"text-indigo-400\",\n  },\n  emerald: {\n    name: \"Matrix Emerald\",\n    radial: \"rgba(16, 185, 129, 0.22)\",\n    borderGlow: \"rgba(52, 211, 153, 0.5)\",\n    badgeBorder: \"border-emerald-500/40\",\n    badgeBg: \"bg-emerald-950/60\",\n    badgeText: \"text-emerald-300\",\n    accent: \"text-emerald-400\",\n  },\n  violet: {\n    name: \"Cyber Violet\",\n    radial: \"rgba(168, 85, 247, 0.22)\",\n    borderGlow: \"rgba(192, 132, 252, 0.5)\",\n    badgeBorder: \"border-purple-500/40\",\n    badgeBg: \"bg-purple-950/60\",\n    badgeText: \"text-purple-300\",\n    accent: \"text-purple-400\",\n  },\n  amber: {\n    name: \"Sunset Amber\",\n    radial: \"rgba(245, 158, 11, 0.22)\",\n    borderGlow: \"rgba(251, 191, 36, 0.5)\",\n    badgeBorder: \"border-amber-500/40\",\n    badgeBg: \"bg-amber-950/60\",\n    badgeText: \"text-amber-300\",\n    accent: \"text-amber-400\",\n  },\n};\n\nconst DEFAULT_FEATURES: BentoFeatureItem[] = [\n  {\n    id: \"hero-sync\",\n    tag: \"CORE PROTOCOL\",\n    title: \"Real-time Bi-directional Graph Sync\",\n    summary: \"Instantaneous CRDT delta updates replicated across client memory states.\",\n    revealedDetails:\n      \"State vector clocks with sub-10ms conflict resolution, zero server round-trip latency for local changes, and optimistic offline caching.\",\n    badge: \"99.999% Uptime\",\n    metric: \"< 8ms Latency\",\n    colSpan: \"md:col-span-2\",\n  },\n  {\n    id: \"engine-isolate\",\n    tag: \"INFRASTRUCTURE\",\n    title: \"Microsecond Sandboxing\",\n    summary: \"Stateless execution isolates boots in 200 microseconds.\",\n    revealedDetails:\n      \"V8 memory pools pre-warmed on global edge nodes with isolated heap ceilings.\",\n    badge: \"0 Cold Start\",\n    metric: \"0.2ms Init\",\n    colSpan: \"md:col-span-1\",\n  },\n  {\n    id: \"keyboard-first\",\n    tag: \"ERGONOMICS\",\n    title: \"Command-Driven Workflows\",\n    summary: \"Operate the entire system without lifting fingers from the keyboard.\",\n    revealedDetails:\n      \"Fuzzy command matching, macro record/playback, and custom vim keybindings baked into every screen.\",\n    badge: \"100% Keyboard\",\n    metric: \"120+ Hotkeys\",\n    colSpan: \"md:col-span-1\",\n  },\n  {\n    id: \"telemetry-mesh\",\n    tag: \"OBSERVABILITY\",\n    title: \"High-Frequency Telemetry Mesh\",\n    summary: \"Sub-millisecond tracing across microservices with eBPF hooks.\",\n    revealedDetails:\n      \"Continuous runtime profiling with flamegraphs, distributed span correlation, and automated anomaly detection.\",\n    badge: \"Auto Diagnostics\",\n    metric: \"10M Events/s\",\n    colSpan: \"md:col-span-2\",\n  },\n];\n\nexport function HoverRevealFeatureGrid({\n  spotlightColor = \"indigo\",\n  spotlightRadius = 350,\n  className,\n}: HoverRevealFeatureGridProps) {\n  const containerRef = useRef<HTMLDivElement>(null);\n  const [activeTheme, setActiveTheme] = useState<SpotlightColor>(spotlightColor);\n  const [radius, setRadius] = useState<number>(spotlightRadius);\n  const [mousePos, setMousePos] = useState<{ x: number; y: number } | null>(null);\n  const [hoveredCardId, setHoveredCardId] = useState<string | null>(null);\n  const [alwaysReveal, setAlwaysReveal] = useState<boolean>(false);\n\n  const theme = SPOTLIGHT_THEMES[activeTheme];\n\n  const handleMouseMove = useCallback((e: React.MouseEvent<HTMLDivElement>) => {\n    if (!containerRef.current) return;\n    const rect = containerRef.current.getBoundingClientRect();\n    setMousePos({\n      x: e.clientX - rect.left,\n      y: e.clientY - rect.top,\n    });\n  }, []);\n\n  const handleMouseLeave = useCallback(() => {\n    setMousePos(null);\n  }, []);\n\n  return (\n    <div\n      data-fullscreen-scroll\n      ref={containerRef}\n      onMouseMove={handleMouseMove}\n      onMouseLeave={handleMouseLeave}\n      className={cn(\n        \"relative w-full min-h-[520px] overflow-hidden rounded-2xl border border-neutral-800 bg-[#07080D] p-6 text-white shadow-2xl flex flex-col justify-between selection:bg-neutral-800\",\n        className\n      )}\n    >\n      {/* Background radial spotlight beam tracking cursor */}\n      {mousePos && (\n        <div\n          className=\"pointer-events-none absolute -translate-x-1/2 -translate-y-1/2 rounded-full blur-2xl transition-opacity duration-300\"\n          style={{\n            left: `${mousePos.x}px`,\n            top: `${mousePos.y}px`,\n            width: `${radius * 2}px`,\n            height: `${radius * 2}px`,\n            background: `radial-gradient(circle, ${theme.radial} 0%, transparent 70%)`,\n          }}\n        />\n      )}\n\n      {/* Header Bar */}\n      <div className=\"relative z-10 flex flex-wrap items-center justify-between gap-4 border-b border-neutral-800/80 pb-4\">\n        <div className=\"flex items-center gap-2.5\">\n          <div className=\"flex h-8 w-8 items-center justify-center rounded-lg border border-neutral-700 bg-neutral-900 font-mono text-xs font-bold text-neutral-200\">\n            <Layers className=\"h-4 w-4\" />\n          </div>\n          <div>\n            <div className=\"flex items-center gap-2\">\n              <h3 className=\"text-sm font-semibold tracking-tight text-white\">\n                Linear Bento Feature Grid\n              </h3>\n              <span\n                className={cn(\n                  \"text-[10px] uppercase font-mono px-2 py-0.5 rounded-full border\",\n                  theme.badgeBorder,\n                  theme.badgeBg,\n                  theme.badgeText\n                )}\n              >\n                {theme.name}\n              </span>\n            </div>\n            <p className=\"text-xs text-neutral-400 font-mono\">\n              Hover tiles to project spotlight mask & reveal secondary specs\n            </p>\n          </div>\n        </div>\n\n        {/* Live Controls */}\n        <div className=\"flex flex-wrap items-center gap-2\">\n          {/* Spotlight color selector */}\n          <div className=\"flex items-center rounded-lg border border-neutral-800 bg-neutral-900/90 p-1\">\n            {([\"indigo\", \"emerald\", \"violet\", \"amber\"] as const).map((c) => (\n              <button\n                key={c}\n                onClick={() => setActiveTheme(c)}\n                className={cn(\n                  \"px-2.5 py-1 text-[11px] font-mono rounded capitalize transition-all\",\n                  activeTheme === c\n                    ? \"bg-neutral-800 text-white font-bold shadow-sm\"\n                    : \"text-neutral-400 hover:text-neutral-200\"\n                )}\n              >\n                {c}\n              </button>\n            ))}\n          </div>\n\n          {/* Always Reveal Toggle */}\n          <button\n            onClick={() => setAlwaysReveal(!alwaysReveal)}\n            className={cn(\n              \"flex items-center gap-1.5 px-2.5 py-1 text-xs font-mono rounded-lg border transition-all\",\n              alwaysReveal\n                ? \"border-neutral-700 bg-neutral-800 text-white font-medium\"\n                : \"border-neutral-800 bg-neutral-900 text-neutral-400 hover:text-neutral-200\"\n            )}\n          >\n            <Eye className=\"h-3.5 w-3.5\" />\n            <span>{alwaysReveal ? \"Always Reveal: ON\" : \"Hover Reveal\"}</span>\n          </button>\n        </div>\n      </div>\n\n      {/* Main Bento Grid */}\n      <div className=\"relative z-10 my-6 grid grid-cols-1 md:grid-cols-3 gap-4\">\n        {DEFAULT_FEATURES.map((item, idx) => {\n          const isHovered = hoveredCardId === item.id || alwaysReveal;\n\n          return (\n            <motion.div\n              key={item.id}\n              tabIndex={0}\n              role=\"button\"\n              onMouseEnter={() => setHoveredCardId(item.id)}\n              onMouseLeave={() => setHoveredCardId(null)}\n              onFocus={() => setHoveredCardId(item.id)}\n              onBlur={() => setHoveredCardId(null)}\n              className={cn(\n                \"group relative flex flex-col justify-between overflow-hidden rounded-xl border p-5 backdrop-blur-md transition-all duration-300 cursor-pointer outline-none\",\n                item.colSpan,\n                isHovered\n                  ? \"border-neutral-600 bg-neutral-900/80 shadow-lg ring-1 ring-white/10\"\n                  : \"border-neutral-800/80 bg-neutral-950/60 hover:border-neutral-700\"\n              )}\n            >\n              {/* Card top banner */}\n              <div>\n                <div className=\"flex items-center justify-between gap-2\">\n                  <span className=\"font-mono text-[10px] font-semibold uppercase tracking-wider text-neutral-400 flex items-center gap-1.5\">\n                    {idx === 0 ? (\n                      <Sparkles className=\"h-3 w-3 text-white\" />\n                    ) : idx === 1 ? (\n                      <Cpu className=\"h-3 w-3\" />\n                    ) : idx === 2 ? (\n                      <Zap className=\"h-3 w-3\" />\n                    ) : (\n                      <Radio className=\"h-3 w-3\" />\n                    )}\n                    {item.tag}\n                  </span>\n\n                  <span\n                    className={cn(\n                      \"inline-flex items-center gap-1 rounded-full border px-2 py-0.5 font-mono text-[10px] font-bold transition-all\",\n                      isHovered\n                        ? cn(theme.badgeBorder, theme.badgeBg, theme.badgeText)\n                        : \"border-neutral-800 bg-neutral-900 text-neutral-400\"\n                    )}\n                  >\n                    {item.metric}\n                    <ArrowUpRight className=\"h-2.5 w-2.5\" />\n                  </span>\n                </div>\n\n                <h4 className=\"mt-3 text-base font-semibold text-white tracking-tight group-hover:text-white transition-colors\">\n                  {item.title}\n                </h4>\n\n                <p className=\"mt-1.5 text-xs leading-relaxed text-neutral-400\">\n                  {item.summary}\n                </p>\n              </div>\n\n              {/* Progressive Revealed Details (Spring Animated) */}\n              <div className=\"mt-4 border-t border-neutral-800/80 pt-3\">\n                <AnimatePresence>\n                  {isHovered ? (\n                    <motion.div\n                      initial={{ opacity: 0, height: 0, y: 6 }}\n                      animate={{ opacity: 1, height: \"auto\", y: 0 }}\n                      exit={{ opacity: 0, height: 0, y: 6 }}\n                      transition={{ duration: 0.25, ease: \"easeOut\" }}\n                      className=\"overflow-hidden\"\n                    >\n                      <div className=\"rounded-lg border border-neutral-800 bg-neutral-950/90 p-3 font-mono text-[11px] leading-relaxed text-neutral-300\">\n                        <div className=\"flex items-center gap-1.5 text-white font-semibold mb-1\">\n                          <CheckCircle2 className=\"h-3 w-3 text-emerald-400\" />\n                          <span>ARCHITECTURE SPECIFICATION</span>\n                        </div>\n                        {item.revealedDetails}\n                      </div>\n                    </motion.div>\n                  ) : (\n                    <div className=\"flex items-center justify-between text-[11px] font-mono text-neutral-500\">\n                      <span>Hover or focus to inspect spec</span>\n                      <span className=\"text-neutral-600\">&rarr;</span>\n                    </div>\n                  )}\n                </AnimatePresence>\n\n                {/* Bottom badge */}\n                <div className=\"mt-3 flex items-center justify-between\">\n                  <span\n                    className={cn(\n                      \"inline-flex items-center gap-1 text-[10px] font-mono uppercase tracking-wider px-2 py-0.5 rounded\",\n                      isHovered\n                        ? \"bg-white/10 text-white font-medium\"\n                        : \"text-neutral-500\"\n                    )}\n                  >\n                    {item.badge}\n                  </span>\n                  <span className=\"text-[10px] font-mono text-neutral-500\">\n                    STATUS: READY\n                  </span>\n                </div>\n              </div>\n            </motion.div>\n          );\n        })}\n      </div>\n\n      {/* Footer controls: Spotlight Radius Slider & Telemetry */}\n      <div className=\"relative z-10 flex flex-wrap items-center justify-between gap-4 border-t border-neutral-800/80 pt-3 text-xs\">\n        <div className=\"flex items-center gap-3\">\n          <span className=\"font-mono text-[11px] text-neutral-400 flex items-center gap-1\">\n            <Sliders className=\"h-3 w-3\" />\n            <span>SPOTLIGHT CONE</span>\n          </span>\n          <input\n            type=\"range\"\n            min=\"150\"\n            max=\"600\"\n            step=\"25\"\n            value={radius}\n            onChange={(e) => setRadius(parseInt(e.target.value))}\n            className=\"accent-neutral-300 h-1.5 w-32 cursor-pointer rounded-lg bg-neutral-800\"\n          />\n          <span className=\"font-mono text-[11px] text-white font-bold\">{radius}px</span>\n        </div>\n\n        <div className=\"flex items-center gap-4 font-mono text-[11px] text-neutral-400\">\n          <span>\n            HOVERED:{\" \"}\n            <span className=\"text-white font-bold\">\n              {hoveredCardId ? hoveredCardId.toUpperCase() : \"NONE\"}\n            </span>\n          </span>\n          <span>TILES: 4 BENTO CELLS</span>\n        </div>\n      </div>\n    </div>\n  );\n}\n\nexport default HoverRevealFeatureGrid;\n",
          "type": "registry:ui",
          "target": "components/ui/hover-reveal-feature-grid.tsx"
        },
        {
          "path": "lib/utils.ts",
          "content": "import { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...inputs: ClassValue[]) {\n  return twMerge(clsx(inputs));\n}\n\nexport async function copyToClipboard(text: string): Promise<boolean> {\n  if (typeof window === \"undefined\") return false;\n\n  try {\n    if (navigator.clipboard && window.isSecureContext) {\n      await navigator.clipboard.writeText(text);\n      return true;\n    }\n\n    const textArea = document.createElement(\"textarea\");\n    textArea.value = text;\n    textArea.style.position = \"fixed\";\n    textArea.style.left = \"-999999px\";\n    textArea.style.top = \"-999999px\";\n    document.body.appendChild(textArea);\n    textArea.focus();\n    textArea.select();\n    const succeeded = document.execCommand(\"copy\");\n    textArea.remove();\n    return succeeded;\n  } catch {\n    return false;\n  }\n}\n",
          "type": "registry:lib",
          "target": "lib/utils.ts"
        }
      ]
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "interactive-grid-beam",
      "type": "registry:ui",
      "title": "Interactive Grid Beam",
      "author": "Rishabh Bose <https://theb0se.vercel.app/>",
      "description": "Architectural matrix background surface with spring-smoothed radial cursor illumination and click-triggered orthogonal grid light beams.",
      "dependencies": [
        "framer-motion",
        "clsx",
        "tailwind-merge"
      ],
      "files": [
        {
          "path": "components/ui/interactive-grid-beam.tsx",
          "content": "\"use client\";\n\nimport React, { useRef, useState } from \"react\";\nimport {\n  motion,\n  useMotionTemplate,\n  useMotionValue,\n  useSpring,\n  useReducedMotion,\n} from \"framer-motion\";\nimport { cn } from \"@/lib/utils\";\n\nexport interface InteractiveGridBeamProps {\n  /** Grid cell size in pixels. Default: 32 */\n  gridSize?: number;\n  /** Radius of the cursor-tracked grid illumination mask in pixels. Default: 220 */\n  glowRadius?: number;\n  /** Spring stiffness coefficient for cursor spotlight tracking. Default: 280 */\n  stiffness?: number;\n  /** Spring damping coefficient for cursor spotlight tracking. Default: 26 */\n  damping?: number;\n  /** Foreground content rendered above the interactive grid matrix */\n  children?: React.ReactNode;\n  className?: string;\n}\n\ninterface PulseTrace {\n  id: number;\n  x: number;\n  y: number;\n}\n\nexport function InteractiveGridBeam({\n  gridSize = 32,\n  glowRadius = 220,\n  stiffness = 280,\n  damping = 26,\n  children,\n  className,\n}: InteractiveGridBeamProps) {\n  const containerRef = useRef<HTMLDivElement | null>(null);\n  const shouldReduceMotion = useReducedMotion() ?? false;\n  const [isHovered, setIsHovered] = useState(false);\n  const [pulses, setPulses] = useState<PulseTrace[]>([]);\n\n  const mouseX = useMotionValue(-1000);\n  const mouseY = useMotionValue(-1000);\n\n  const smoothX = useSpring(mouseX, { stiffness, damping, mass: 0.3 });\n  const smoothY = useSpring(mouseY, { stiffness, damping, mass: 0.3 });\n\n  const activeX = shouldReduceMotion ? mouseX : smoothX;\n  const activeY = shouldReduceMotion ? mouseY : smoothY;\n\n  const maskImage = useMotionTemplate`radial-gradient(${glowRadius}px circle at ${activeX}px ${activeY}px, rgba(0,0,0,1) 0%, rgba(0,0,0,0.35) 55%, transparent 100%)`;\n\n  const handleMouseMove = (e: React.MouseEvent<HTMLDivElement>) => {\n    const el = containerRef.current;\n    if (!el) return;\n    const rect = el.getBoundingClientRect();\n    mouseX.set(e.clientX - rect.left);\n    mouseY.set(e.clientY - rect.top);\n  };\n\n  const handleClick = (e: React.MouseEvent<HTMLDivElement>) => {\n    if (shouldReduceMotion) return;\n    const el = containerRef.current;\n    if (!el) return;\n    const rect = el.getBoundingClientRect();\n    const rawX = e.clientX - rect.left;\n    const rawY = e.clientY - rect.top;\n\n    // Snap beam origin to nearest grid intersection\n    const snappedX = Math.round(rawX / gridSize) * gridSize;\n    const snappedY = Math.round(rawY / gridSize) * gridSize;\n    const id = Date.now() + Math.random();\n\n    setPulses((prev) => [...prev.slice(-3), { id, x: snappedX, y: snappedY }]);\n  };\n\n  const gridBackgroundStyle: React.CSSProperties = {\n    backgroundSize: `${gridSize}px ${gridSize}px`,\n    backgroundImage:\n      \"linear-gradient(to right, currentColor 1px, transparent 1px), linear-gradient(to bottom, currentColor 1px, transparent 1px)\",\n  };\n\n  return (\n    <div\n      ref={containerRef}\n      onMouseMove={handleMouseMove}\n      onMouseEnter={() => setIsHovered(true)}\n      onMouseLeave={() => setIsHovered(false)}\n      onClick={handleClick}\n      className={cn(\n        \"group relative flex min-h-[240px] w-full cursor-crosshair items-center justify-center overflow-hidden rounded-2xl border border-neutral-200 bg-white p-8 dark:border-[#222222] dark:bg-[#0A0A0A]\",\n        className\n      )}\n    >\n      {/* Base ambient low-contrast architectural grid */}\n      <div\n        aria-hidden=\"true\"\n        style={gridBackgroundStyle}\n        className=\"pointer-events-none absolute inset-0 text-neutral-200/55 dark:text-[#1A1A1A]\"\n      />\n\n      {/* Cursor-masked high-contrast kinetic grid overlay */}\n      <motion.div\n        aria-hidden=\"true\"\n        style={{\n          ...gridBackgroundStyle,\n          WebkitMaskImage: maskImage,\n          maskImage,\n          opacity: isHovered ? 1 : 0,\n        }}\n        className=\"pointer-events-none absolute inset-0 text-black/45 transition-opacity duration-300 dark:text-white/45\"\n      />\n\n      {/* Interactive orthogonal light beams emitted on click */}\n      {!shouldReduceMotion &&\n        pulses.map((pulse) => (\n          <React.Fragment key={pulse.id}>\n            {/* Horizontal propagating beam */}\n            <motion.div\n              aria-hidden=\"true\"\n              initial={{ scaleX: 0, opacity: 0.9 }}\n              animate={{ scaleX: 1.6, opacity: 0 }}\n              transition={{ duration: 0.75, ease: \"easeOut\" }}\n              style={{ top: pulse.y, left: 0, right: 0 }}\n              className=\"pointer-events-none absolute h-[1.5px] origin-center bg-gradient-to-r from-transparent via-black to-transparent dark:via-white\"\n            />\n            {/* Vertical propagating beam */}\n            <motion.div\n              aria-hidden=\"true\"\n              initial={{ scaleY: 0, opacity: 0.9 }}\n              animate={{ scaleY: 1.6, opacity: 0 }}\n              transition={{ duration: 0.75, ease: \"easeOut\" }}\n              style={{ left: pulse.x, top: 0, bottom: 0 }}\n              className=\"pointer-events-none absolute w-[1.5px] origin-center bg-gradient-to-b from-transparent via-black to-transparent dark:via-white\"\n            />\n            {/* Intersection node pulse */}\n            <motion.div\n              aria-hidden=\"true\"\n              initial={{ scale: 0.4, opacity: 1 }}\n              animate={{ scale: 2.8, opacity: 0 }}\n              transition={{ duration: 0.65, ease: \"easeOut\" }}\n              style={{ left: pulse.x - 4, top: pulse.y - 4 }}\n              className=\"pointer-events-none absolute h-2 w-2 rounded-full bg-black dark:bg-white\"\n            />\n          </React.Fragment>\n        ))}\n\n      {/* Foreground Content */}\n      <div className=\"relative z-10 text-center\">\n        {children || (\n          <div className=\"mx-auto max-w-xs rounded-2xl border border-neutral-200/90 bg-white/90 px-5 py-4 shadow-sm backdrop-blur-md dark:border-[#262626] dark:bg-[#111111]/90\">\n            <div className=\"text-xs font-semibold uppercase tracking-widest text-neutral-400\">\n              Interactive Grid Matrix\n            </div>\n            <div className=\"mt-1 text-sm font-semibold text-black dark:text-white\">\n              Move cursor or click any intersection\n            </div>\n            <p className=\"mt-1 text-[11px] text-neutral-500\">\n              Snaps orthogonal light beams to {gridSize}px coordinates.\n            </p>\n          </div>\n        )}\n      </div>\n    </div>\n  );\n}\n\nexport default InteractiveGridBeam;\n",
          "type": "registry:ui",
          "target": "components/ui/interactive-grid-beam.tsx"
        },
        {
          "path": "lib/utils.ts",
          "content": "import { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...inputs: ClassValue[]) {\n  return twMerge(clsx(inputs));\n}\n\nexport async function copyToClipboard(text: string): Promise<boolean> {\n  if (typeof window === \"undefined\") return false;\n\n  try {\n    if (navigator.clipboard && window.isSecureContext) {\n      await navigator.clipboard.writeText(text);\n      return true;\n    }\n\n    const textArea = document.createElement(\"textarea\");\n    textArea.value = text;\n    textArea.style.position = \"fixed\";\n    textArea.style.left = \"-999999px\";\n    textArea.style.top = \"-999999px\";\n    document.body.appendChild(textArea);\n    textArea.focus();\n    textArea.select();\n    const succeeded = document.execCommand(\"copy\");\n    textArea.remove();\n    return succeeded;\n  } catch {\n    return false;\n  }\n}\n",
          "type": "registry:lib",
          "target": "lib/utils.ts"
        }
      ]
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "isometric-city",
      "type": "registry:ui",
      "title": "Isometric City",
      "author": "Rishabh Bose <https://theb0se.vercel.app/>",
      "description": "Procedural 3D-projected isometric night cityscape rendered on HTML5 Canvas 2D with depth-sorted skyscrapers, flickering office windows, rooftop aviation beacons, and avenue light-streak traffic.",
      "dependencies": [
        "lucide-react",
        "clsx",
        "tailwind-merge"
      ],
      "files": [
        {
          "path": "components/ui/isometric-city.tsx",
          "content": "\"use client\";\n\nimport React, { useEffect, useRef, useState } from \"react\";\nimport { Building2, Car, Sparkles, RefreshCw } from \"lucide-react\";\nimport { cn } from \"@/lib/utils\";\n\nexport interface IsometricCityProps {\n  /** Number of city blocks along each isometric axis (4 to 10) */\n  gridSize?: number;\n  /** Probability [0.3 - 1.0] that a grid cell contains a skyscraper */\n  buildingDensity?: number;\n  /** Speed multiplier for avenue light-streak traffic */\n  trafficSpeed?: number;\n  /** Architectural lighting color palette */\n  colorPalette?: \"cyberpunk\" | \"midnight\" | \"amber\";\n  /** Whether office windows subtly toggle on and off over time */\n  windowFlicker?: boolean;\n  /** Optional foreground content */\n  children?: React.ReactNode;\n  /** Additional container classes */\n  className?: string;\n}\n\ninterface PaletteConfig {\n  bgTop: string;\n  bgBottom: string;\n  smogGlow: string;\n  gridLine: string;\n  streetGlow: string;\n  roofFace: string;\n  leftFace: string;\n  rightFace: string;\n  edgeStroke: string;\n  neonAccent: string;\n  windowLitA: string;\n  windowLitB: string;\n  beaconColor: string;\n  headlight: string;\n  taillight: string;\n}\n\nconst PALETTES: Record<\"cyberpunk\" | \"midnight\" | \"amber\", PaletteConfig> = {\n  midnight: {\n    bgTop: \"#020617\",\n    bgBottom: \"#091936\",\n    smogGlow: \"rgba(56, 189, 248, 0.16)\",\n    gridLine: \"rgba(56, 189, 248, 0.18)\",\n    streetGlow: \"rgba(56, 189, 248, 0.12)\",\n    roofFace: \"#1E293B\",\n    leftFace: \"#0F172A\",\n    rightFace: \"#080D1A\",\n    edgeStroke: \"rgba(148, 163, 184, 0.25)\",\n    neonAccent: \"#38BDF8\",\n    windowLitA: \"#38BDF8\",\n    windowLitB: \"#E0F2FE\",\n    beaconColor: \"#F43F5E\",\n    headlight: \"#F8FAFC\",\n    taillight: \"#FB7185\",\n  },\n  cyberpunk: {\n    bgTop: \"#060212\",\n    bgBottom: \"#1B0933\",\n    smogGlow: \"rgba(236, 72, 153, 0.20)\",\n    gridLine: \"rgba(236, 72, 153, 0.22)\",\n    streetGlow: \"rgba(34, 211, 238, 0.14)\",\n    roofFace: \"#271340\",\n    leftFace: \"#170A29\",\n    rightFace: \"#0D041A\",\n    edgeStroke: \"rgba(244, 114, 182, 0.32)\",\n    neonAccent: \"#22D3EE\",\n    windowLitA: \"#22D3EE\",\n    windowLitB: \"#F472B6\",\n    beaconColor: \"#22D3EE\",\n    headlight: \"#22D3EE\",\n    taillight: \"#F43F5E\",\n  },\n  amber: {\n    bgTop: \"#080502\",\n    bgBottom: \"#1F1408\",\n    smogGlow: \"rgba(245, 158, 11, 0.16)\",\n    gridLine: \"rgba(245, 158, 11, 0.18)\",\n    streetGlow: \"rgba(251, 191, 36, 0.12)\",\n    roofFace: \"#2B2118\",\n    leftFace: \"#1C150E\",\n    rightFace: \"#110C08\",\n    edgeStroke: \"rgba(251, 191, 36, 0.26)\",\n    neonAccent: \"#F59E0B\",\n    windowLitA: \"#FBBF24\",\n    windowLitB: \"#FEF3C7\",\n    beaconColor: \"#EF4444\",\n    headlight: \"#FDE68A\",\n    taillight: \"#EA580C\",\n  },\n};\n\ninterface BuildingBlock {\n  gx: number;\n  gy: number;\n  height: number;\n  floors: number;\n  style: \"stepped\" | \"helipad\" | \"spire\" | \"modern\";\n  upperTierHeight: number;\n  hasBeacon: boolean;\n  hasNeonTrim: boolean;\n  beaconPhase: number;\n  windowsLeft: boolean[][];\n  windowsRight: boolean[][];\n}\n\ninterface TrafficStreak {\n  axis: \"x\" | \"y\";\n  laneIndex: number;\n  pos: number;\n  speed: number;\n  dir: 1 | -1;\n  length: number;\n}\n\nexport function IsometricCity({\n  gridSize: propGridSize = 7,\n  buildingDensity: propDensity = 0.78,\n  trafficSpeed: propTrafficSpeed = 1.0,\n  colorPalette: propPalette = \"midnight\",\n  windowFlicker: propFlicker = true,\n  children,\n  className,\n}: IsometricCityProps) {\n  const containerRef = useRef<HTMLDivElement>(null);\n  const canvasRef = useRef<HTMLCanvasElement>(null);\n  const pointerRef = useRef<{ x: number; y: number }>({ x: 0, y: 0 });\n\n  const [palette, setPalette] = useState<\"cyberpunk\" | \"midnight\" | \"amber\">(\n    propPalette\n  );\n  const [trafficSpeed, setTrafficSpeed] = useState(propTrafficSpeed);\n  const [windowFlicker, setWindowFlicker] = useState(propFlicker);\n  const [seed, setSeed] = useState(1);\n  const [buildingCount, setBuildingCount] = useState(0);\n\n  useEffect(() => {\n    setPalette(propPalette);\n  }, [propPalette]);\n\n  useEffect(() => {\n    setTrafficSpeed(propTrafficSpeed);\n  }, [propTrafficSpeed]);\n\n  useEffect(() => {\n    setWindowFlicker(propFlicker);\n  }, [propFlicker]);\n\n  useEffect(() => {\n    const container = containerRef.current;\n    const canvas = canvasRef.current;\n    if (!container || !canvas) return;\n\n    const ctx = canvas.getContext(\"2d\");\n    if (!ctx) return;\n\n    let animationFrameId = 0;\n    let width = 0;\n    let height = 0;\n\n    const N = Math.max(4, Math.min(10, propGridSize));\n\n    // Generate procedural city blocks sorted back-to-front by (gx + gy)\n    const buildings: BuildingBlock[] = [];\n    for (let gx = 0; gx < N; gx++) {\n      for (let gy = 0; gy < N; gy++) {\n        if (Math.random() > propDensity) continue;\n\n        const distFromCenter =\n          Math.hypot(gx - (N - 1) / 2, gy - (N - 1) / 2) / (N * 0.7);\n        const centerBoost = Math.max(0.28, 1 - distFromCenter * 0.72);\n        const floors = Math.max(\n          3,\n          Math.floor((4 + Math.random() * 14) * centerBoost)\n        );\n        const bHeight = floors * 10;\n\n        const cols = 4;\n        const windowsLeft: boolean[][] = [];\n        const windowsRight: boolean[][] = [];\n        for (let f = 0; f < floors; f++) {\n          windowsLeft.push(\n            Array.from({ length: cols }, () => Math.random() < 0.64)\n          );\n          windowsRight.push(\n            Array.from({ length: cols }, () => Math.random() < 0.58)\n          );\n        }\n\n        const roll = Math.random();\n        const style: BuildingBlock[\"style\"] =\n          floors >= 11 && roll < 0.38\n            ? \"stepped\"\n            : floors >= 10 && roll < 0.68\n            ? \"spire\"\n            : floors >= 8 && roll < 0.88\n            ? \"helipad\"\n            : \"modern\";\n\n        buildings.push({\n          gx,\n          gy,\n          height: bHeight,\n          floors,\n          style,\n          upperTierHeight:\n            style === \"stepped\" ? Math.floor(2 + Math.random() * 3) * 10 : 0,\n          hasBeacon: floors >= 8,\n          hasNeonTrim: floors >= 9 && Math.random() < 0.55,\n          beaconPhase: Math.random() * Math.PI * 2,\n          windowsLeft,\n          windowsRight,\n        });\n      }\n    }\n\n    buildings.sort((a, b) => a.gx + a.gy - (b.gx + b.gy));\n    setBuildingCount(buildings.length);\n\n    // Avenue vehicle light-streaks\n    const streaks: TrafficStreak[] = Array.from({ length: N * 4 }, (_, i) => ({\n      axis: i % 2 === 0 ? \"x\" : \"y\",\n      laneIndex: Math.floor(Math.random() * (N + 1)),\n      pos: Math.random() * N,\n      speed: 0.012 + Math.random() * 0.018,\n      dir: Math.random() > 0.5 ? 1 : -1,\n      length: 0.38 + Math.random() * 0.45,\n    }));\n\n    const updateSize = () => {\n      const rect = container.getBoundingClientRect();\n      const dpr = Math.min(window.devicePixelRatio || 1, 2);\n      width = Math.max(1, Math.floor(rect.width));\n      height = Math.max(1, Math.floor(rect.height));\n      canvas.width = width * dpr;\n      canvas.height = height * dpr;\n      ctx.setTransform(dpr, 0, 0, dpr, 0, 0);\n    };\n\n    updateSize();\n    const observer = new ResizeObserver(updateSize);\n    observer.observe(container);\n\n    let time = 0;\n\n    const render = () => {\n      time += 0.03;\n      const theme = PALETTES[palette];\n\n      // 1. Nocturnal Sky & Atmospheric Smog Horizon Glow\n      const bgGrad = ctx.createLinearGradient(0, 0, 0, height);\n      bgGrad.addColorStop(0, theme.bgTop);\n      bgGrad.addColorStop(1, theme.bgBottom);\n      ctx.fillStyle = bgGrad;\n      ctx.fillRect(0, 0, width, height);\n\n      const smog = ctx.createRadialGradient(\n        width * 0.5,\n        height * 0.54,\n        20,\n        width * 0.5,\n        height * 0.54,\n        Math.max(width, height) * 0.55\n      );\n      smog.addColorStop(0, theme.smogGlow);\n      smog.addColorStop(1, \"transparent\");\n      ctx.fillStyle = smog;\n      ctx.fillRect(0, 0, width, height);\n\n      // Isometric projection with subtle mouse-driven camera parallax\n      const tileW = Math.min(width / (N * 1.32), 70);\n      const tileH = tileW * 0.52;\n      const originX = width / 2 + pointerRef.current.x * 16;\n      const originY = height * 0.35 + pointerRef.current.y * 10;\n\n      const isoProject = (gx: number, gy: number, z = 0) => ({\n        x: originX + (gx - gy) * (tileW * 0.5),\n        y: originY + (gx + gy) * (tileH * 0.5) - z,\n      });\n\n      const drawIsoPrism = (\n        x0: number,\n        y0: number,\n        x1: number,\n        y1: number,\n        zBase: number,\n        zTop: number,\n        highlightNeon = false\n      ) => {\n        const tBack = isoProject(x0, y0, zTop);\n        const tRight = isoProject(x1, y0, zTop);\n        const tFront = isoProject(x1, y1, zTop);\n        const tLeft = isoProject(x0, y1, zTop);\n\n        const bRight = isoProject(x1, y0, zBase);\n        const bFront = isoProject(x1, y1, zBase);\n        const bLeft = isoProject(x0, y1, zBase);\n\n        // Left Face\n        ctx.beginPath();\n        ctx.moveTo(tLeft.x, tLeft.y);\n        ctx.lineTo(tFront.x, tFront.y);\n        ctx.lineTo(bFront.x, bFront.y);\n        ctx.lineTo(bLeft.x, bLeft.y);\n        ctx.closePath();\n        ctx.fillStyle = theme.leftFace;\n        ctx.fill();\n        ctx.strokeStyle = theme.edgeStroke;\n        ctx.lineWidth = 0.85;\n        ctx.stroke();\n\n        // Right Face\n        ctx.beginPath();\n        ctx.moveTo(tFront.x, tFront.y);\n        ctx.lineTo(tRight.x, tRight.y);\n        ctx.lineTo(bRight.x, bRight.y);\n        ctx.lineTo(bFront.x, bFront.y);\n        ctx.closePath();\n        ctx.fillStyle = theme.rightFace;\n        ctx.fill();\n        ctx.stroke();\n\n        // Roof Face\n        ctx.beginPath();\n        ctx.moveTo(tBack.x, tBack.y);\n        ctx.lineTo(tRight.x, tRight.y);\n        ctx.lineTo(tFront.x, tFront.y);\n        ctx.lineTo(tLeft.x, tLeft.y);\n        ctx.closePath();\n        ctx.fillStyle = theme.roofFace;\n        ctx.fill();\n        ctx.stroke();\n\n        // Neon architectural roof cornice trim\n        if (highlightNeon) {\n          ctx.save();\n          ctx.beginPath();\n          ctx.moveTo(tLeft.x, tLeft.y);\n          ctx.lineTo(tFront.x, tFront.y);\n          ctx.lineTo(tRight.x, tRight.y);\n          ctx.strokeStyle = theme.neonAccent;\n          ctx.shadowColor = theme.neonAccent;\n          ctx.shadowBlur = 8;\n          ctx.lineWidth = 1.5;\n          ctx.stroke();\n          ctx.restore();\n        }\n      };\n\n      // 2. Ground Avenue Grid & Wet-Street Intersection Glow Pools\n      ctx.strokeStyle = theme.gridLine;\n      ctx.lineWidth = 1.1;\n      for (let i = 0; i <= N; i++) {\n        const startX = isoProject(i, 0, 0);\n        const endX = isoProject(i, N, 0);\n        ctx.beginPath();\n        ctx.moveTo(startX.x, startX.y);\n        ctx.lineTo(endX.x, endX.y);\n        ctx.stroke();\n\n        const startY = isoProject(0, i, 0);\n        const endY = isoProject(N, i, 0);\n        ctx.beginPath();\n        ctx.moveTo(startY.x, startY.y);\n        ctx.lineTo(endY.x, endY.y);\n        ctx.stroke();\n      }\n\n      // Intersection streetlamp reflection pools\n      for (let gx = 0; gx <= N; gx++) {\n        for (let gy = 0; gy <= N; gy++) {\n          const pt = isoProject(gx, gy, 0);\n          const pool = ctx.createRadialGradient(pt.x, pt.y, 1, pt.x, pt.y, 12);\n          pool.addColorStop(0, theme.streetGlow);\n          pool.addColorStop(1, \"transparent\");\n          ctx.fillStyle = pool;\n          ctx.beginPath();\n          ctx.arc(pt.x, pt.y, 12, 0, Math.PI * 2);\n          ctx.fill();\n        }\n      }\n\n      // 3. Bidirectional Avenue Vehicle Light Streaks (Headlights + Taillights)\n      for (let i = 0; i < streaks.length; i++) {\n        const st = streaks[i];\n        st.pos += st.speed * trafficSpeed * st.dir;\n        if (st.pos > N) st.pos = 0;\n        if (st.pos < 0) st.pos = N;\n\n        const tailPos = Math.max(0, Math.min(N, st.pos - st.length * st.dir));\n        const laneOffset = st.dir === 1 ? 0.04 : -0.04;\n        const pHead =\n          st.axis === \"x\"\n            ? isoProject(st.pos, st.laneIndex + laneOffset, 1)\n            : isoProject(st.laneIndex + laneOffset, st.pos, 1);\n        const pTail =\n          st.axis === \"x\"\n            ? isoProject(tailPos, st.laneIndex + laneOffset, 1)\n            : isoProject(st.laneIndex + laneOffset, tailPos, 1);\n\n        const grad = ctx.createLinearGradient(\n          pTail.x,\n          pTail.y,\n          pHead.x,\n          pHead.y\n        );\n        const streakColor = st.dir === 1 ? theme.headlight : theme.taillight;\n        grad.addColorStop(0, \"transparent\");\n        grad.addColorStop(1, streakColor);\n\n        ctx.save();\n        ctx.strokeStyle = grad;\n        ctx.lineWidth = 2.4;\n        ctx.shadowColor = streakColor;\n        ctx.shadowBlur = 9;\n        ctx.beginPath();\n        ctx.moveTo(pTail.x, pTail.y);\n        ctx.lineTo(pHead.x, pHead.y);\n        ctx.stroke();\n        ctx.restore();\n      }\n\n      // 4. Depth-Sorted 3D Isometric Skyscrapers with Architectural Setbacks & Details\n      const pad = 0.14;\n      const bw = 1 - pad * 2;\n\n      for (let i = 0; i < buildings.length; i++) {\n        const b = buildings[i];\n\n        if (windowFlicker && Math.random() < 0.016) {\n          const f = Math.floor(Math.random() * b.floors);\n          const c = Math.floor(Math.random() * 4);\n          if (Math.random() < 0.5) {\n            b.windowsLeft[f][c] = !b.windowsLeft[f][c];\n          } else {\n            b.windowsRight[f][c] = !b.windowsRight[f][c];\n          }\n        }\n\n        const x0 = b.gx + pad;\n        const y0 = b.gy + pad;\n        const x1 = x0 + bw;\n        const y1 = y0 + bw;\n        const h = b.height;\n\n        // Main tower shaft\n        drawIsoPrism(x0, y0, x1, y1, 0, h, b.hasNeonTrim);\n\n        // Draw perspective-projected office windows on main shaft\n        for (let f = 0; f < b.floors; f++) {\n          const zTop = (f + 0.72) * 10;\n          const zBot = (f + 0.24) * 10;\n\n          for (let col = 0; col < 4; col++) {\n            const u0 = (col + 0.22) / 4.4;\n            const u1 = (col + 0.76) / 4.4;\n\n            if (b.windowsLeft[f][col]) {\n              const wl0 = isoProject(x0 + bw * u0, y1, zTop);\n              const wl1 = isoProject(x0 + bw * u1, y1, zTop);\n              const wl2 = isoProject(x0 + bw * u1, y1, zBot);\n              const wl3 = isoProject(x0 + bw * u0, y1, zBot);\n\n              ctx.fillStyle =\n                (f + col) % 3 === 0 ? theme.windowLitB : theme.windowLitA;\n              ctx.globalAlpha = 0.82;\n              ctx.beginPath();\n              ctx.moveTo(wl0.x, wl0.y);\n              ctx.lineTo(wl1.x, wl1.y);\n              ctx.lineTo(wl2.x, wl2.y);\n              ctx.lineTo(wl3.x, wl3.y);\n              ctx.closePath();\n              ctx.fill();\n              ctx.globalAlpha = 1;\n            }\n\n            if (b.windowsRight[f][col]) {\n              const wr0 = isoProject(x1, y0 + bw * u0, zTop);\n              const wr1 = isoProject(x1, y0 + bw * u1, zTop);\n              const wr2 = isoProject(x1, y0 + bw * u1, zBot);\n              const wr3 = isoProject(x1, y0 + bw * u0, zBot);\n\n              ctx.fillStyle =\n                (f + col) % 2 === 0 ? theme.windowLitA : theme.windowLitB;\n              ctx.globalAlpha = 0.58;\n              ctx.beginPath();\n              ctx.moveTo(wr0.x, wr0.y);\n              ctx.lineTo(wr1.x, wr1.y);\n              ctx.lineTo(wr2.x, wr2.y);\n              ctx.lineTo(wr3.x, wr3.y);\n              ctx.closePath();\n              ctx.fill();\n              ctx.globalAlpha = 1;\n            }\n          }\n        }\n\n        // Architectural Upper Setback Tier (Stepped Skyscraper)\n        let topZ = h;\n        if (b.style === \"stepped\" && b.upperTierHeight > 0) {\n          const inset = bw * 0.22;\n          topZ = h + b.upperTierHeight;\n          drawIsoPrism(\n            x0 + inset,\n            y0 + inset,\n            x1 - inset,\n            y1 - inset,\n            h,\n            topZ,\n            true\n          );\n        }\n\n        // Glowing Rooftop Helipad Ring\n        if (b.style === \"helipad\") {\n          const roofCenter = isoProject(x0 + bw * 0.5, y0 + bw * 0.5, topZ + 0.5);\n          ctx.save();\n          ctx.translate(roofCenter.x, roofCenter.y);\n          ctx.scale(1, 0.52);\n          ctx.beginPath();\n          ctx.arc(0, 0, tileW * 0.16, 0, Math.PI * 2);\n          ctx.strokeStyle = theme.neonAccent;\n          ctx.lineWidth = 1.3;\n          ctx.stroke();\n          ctx.restore();\n        }\n\n        // Rooftop Spire & Blinking Aviation Warning Beacon\n        if (b.hasBeacon) {\n          const roofCenter = isoProject(x0 + bw * 0.5, y0 + bw * 0.5, topZ);\n          const hasTallSpire = b.style === \"spire\" || b.style === \"stepped\";\n          const spireTop = isoProject(\n            x0 + bw * 0.5,\n            y0 + bw * 0.5,\n            topZ + (hasTallSpire ? 22 : 5)\n          );\n\n          if (hasTallSpire) {\n            ctx.beginPath();\n            ctx.moveTo(roofCenter.x, roofCenter.y);\n            ctx.lineTo(spireTop.x, spireTop.y);\n            ctx.strokeStyle = \"rgba(226, 232, 240, 0.65)\";\n            ctx.lineWidth = 1.3;\n            ctx.stroke();\n          }\n\n          const pulse =\n            0.35 +\n            0.65 *\n              Math.pow(Math.sin(time * 2.4 + b.beaconPhase) * 0.5 + 0.5, 2);\n          ctx.save();\n          ctx.beginPath();\n          ctx.arc(spireTop.x, spireTop.y, 2.4, 0, Math.PI * 2);\n          ctx.fillStyle = theme.beaconColor;\n          ctx.globalAlpha = pulse;\n          ctx.shadowColor = theme.beaconColor;\n          ctx.shadowBlur = 12;\n          ctx.fill();\n          ctx.restore();\n        }\n      }\n\n      animationFrameId = requestAnimationFrame(render);\n    };\n\n    animationFrameId = requestAnimationFrame(render);\n\n    return () => {\n      cancelAnimationFrame(animationFrameId);\n      observer.disconnect();\n    };\n  }, [propGridSize, propDensity, palette, trafficSpeed, windowFlicker, seed]);\n\n  return (\n    <div\n      ref={containerRef}\n      data-fullscreen-scroll\n      onMouseMove={(e) => {\n        const rect = e.currentTarget.getBoundingClientRect();\n        pointerRef.current = {\n          x: (e.clientX - rect.left) / Math.max(1, rect.width) - 0.5,\n          y: (e.clientY - rect.top) / Math.max(1, rect.height) - 0.5,\n        };\n      }}\n      onMouseLeave={() => {\n        pointerRef.current = { x: 0, y: 0 };\n      }}\n      className={cn(\n        \"relative w-full min-h-[520px] overflow-hidden rounded-2xl border border-sky-500/20 bg-[#020617] text-slate-100 shadow-2xl\",\n        className\n      )}\n    >\n      <canvas\n        ref={canvasRef}\n        aria-hidden=\"true\"\n        className=\"pointer-events-none absolute inset-0 h-full w-full\"\n      />\n\n      {children && (\n        <div className=\"relative z-10 flex min-h-[520px] w-full flex-col\">\n          {children}\n        </div>\n      )}\n    </div>\n  );\n}\n\nexport default IsometricCity;\n",
          "type": "registry:ui",
          "target": "components/ui/isometric-city.tsx"
        },
        {
          "path": "lib/utils.ts",
          "content": "import { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...inputs: ClassValue[]) {\n  return twMerge(clsx(inputs));\n}\n\nexport async function copyToClipboard(text: string): Promise<boolean> {\n  if (typeof window === \"undefined\") return false;\n\n  try {\n    if (navigator.clipboard && window.isSecureContext) {\n      await navigator.clipboard.writeText(text);\n      return true;\n    }\n\n    const textArea = document.createElement(\"textarea\");\n    textArea.value = text;\n    textArea.style.position = \"fixed\";\n    textArea.style.left = \"-999999px\";\n    textArea.style.top = \"-999999px\";\n    document.body.appendChild(textArea);\n    textArea.focus();\n    textArea.select();\n    const succeeded = document.execCommand(\"copy\");\n    textArea.remove();\n    return succeeded;\n  } catch {\n    return false;\n  }\n}\n",
          "type": "registry:lib",
          "target": "lib/utils.ts"
        }
      ]
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "keycap-chips",
      "type": "registry:ui",
      "title": "Keycap Chips",
      "author": "Rishabh Bose <https://theb0se.vercel.app/>",
      "description": "Raycast-inspired 3D tactile physical keyboard keycaps with realistic chamfer bevels, inset mechanical shadows, physical depression animations, and interactive keyboard listener.",
      "dependencies": [
        "framer-motion",
        "lucide-react",
        "clsx",
        "tailwind-merge"
      ],
      "files": [
        {
          "path": "components/ui/keycap-chips.tsx",
          "content": "\"use client\";\n\nimport React, { useState, useEffect, useCallback } from \"react\";\nimport { motion, AnimatePresence } from \"framer-motion\";\nimport {\n  Keyboard,\n  Command,\n  CornerDownLeft,\n  Search,\n  Sparkles,\n  Terminal,\n  Volume2,\n  VolumeX,\n  Plus,\n  Trash2,\n  CheckCircle2,\n} from \"lucide-react\";\nimport { cn } from \"@/lib/utils\";\n\nexport type KeycapVariant = \"obsidian\" | \"classic\" | \"cyber\" | \"porcelain\";\nexport type KeycapSize = \"sm\" | \"md\" | \"lg\";\n\nexport interface ShortcutItem {\n  id: string;\n  name: string;\n  category: string;\n  keys: string[];\n}\n\nexport interface KeycapChipsProps {\n  shortcuts?: ShortcutItem[];\n  keys?: string[];\n  size?: KeycapSize;\n  variant?: KeycapVariant;\n  enableGlobalListener?: boolean;\n  inline?: boolean;\n  onShortcutPress?: (key: string) => void;\n  className?: string;\n}\n\nconst DEFAULT_SHORTCUTS: ShortcutItem[] = [\n  {\n    id: \"cmd-k\",\n    name: \"Open Command Palette\",\n    category: \"Navigation\",\n    keys: [\"⌘\", \"K\"],\n  },\n  {\n    id: \"quick-open\",\n    name: \"Quick File Search\",\n    category: \"Workbench\",\n    keys: [\"⌘\", \"P\"],\n  },\n  {\n    id: \"commit\",\n    name: \"Commit & Instant Push\",\n    category: \"Source Control\",\n    keys: [\"⌘\", \"⇧\", \"↵\"],\n  },\n  {\n    id: \"terminal-toggle\",\n    name: \"Toggle Embedded Terminal\",\n    category: \"Developer Tools\",\n    keys: [\"⌃\", \"`\"],\n  },\n  {\n    id: \"zen-mode\",\n    name: \"Toggle Zen Fullscreen\",\n    category: \"Display\",\n    keys: [\"⌥\", \"⌘\", \"F\"],\n  },\n];\n\nconst VARIANT_STYLES: Record<\n  KeycapVariant,\n  {\n    keycap: string;\n    keycapPressed: string;\n    text: string;\n    border: string;\n    badge: string;\n  }\n> = {\n  obsidian: {\n    keycap:\n      \"bg-neutral-800 text-neutral-100 border border-neutral-700/80 shadow-[0_3px_0_0_#171717,0_6px_8px_rgba(0,0,0,0.5)]\",\n    keycapPressed:\n      \"bg-neutral-750 text-white translate-y-[3px] shadow-[0_0px_0_0_#171717,0_2px_4px_rgba(0,0,0,0.4)] ring-1 ring-cyan-500/60\",\n    text: \"text-neutral-200\",\n    border: \"border-neutral-800\",\n    badge: \"border-neutral-700 bg-neutral-900 text-neutral-300\",\n  },\n  classic: {\n    keycap:\n      \"bg-[#D6D3D1] text-neutral-900 border border-[#E7E5E4] shadow-[0_3px_0_0_#A8A29E,0_6px_8px_rgba(0,0,0,0.3)]\",\n    keycapPressed:\n      \"bg-[#E7E5E4] text-black translate-y-[3px] shadow-[0_0px_0_0_#A8A29E,0_2px_4px_rgba(0,0,0,0.3)] ring-1 ring-amber-500/60\",\n    text: \"text-neutral-100\",\n    border: \"border-neutral-700\",\n    badge: \"border-stone-700 bg-stone-900 text-stone-200\",\n  },\n  cyber: {\n    keycap:\n      \"bg-neutral-900 text-amber-400 border border-amber-500/60 shadow-[0_3px_0_0_#78350F,0_0_12px_rgba(245,158,11,0.2)]\",\n    keycapPressed:\n      \"bg-amber-950 text-amber-300 translate-y-[3px] shadow-[0_0px_0_0_#78350F,0_0_16px_rgba(245,158,11,0.5)] ring-1 ring-amber-400\",\n    text: \"text-amber-400\",\n    border: \"border-amber-900/50\",\n    badge: \"border-amber-800/60 bg-amber-950/40 text-amber-400\",\n  },\n  porcelain: {\n    keycap:\n      \"bg-neutral-100 text-neutral-900 border border-white shadow-[0_3px_0_0_#CBD5E1,0_6px_10px_rgba(0,0,0,0.2)]\",\n    keycapPressed:\n      \"bg-white text-black translate-y-[3px] shadow-[0_0px_0_0_#CBD5E1,0_2px_4px_rgba(0,0,0,0.2)] ring-1 ring-indigo-500/60\",\n    text: \"text-neutral-200\",\n    border: \"border-neutral-700\",\n    badge: \"border-slate-700 bg-slate-900 text-slate-200\",\n  },\n};\n\nconst SIZE_STYLES: Record<\n  KeycapSize,\n  {\n    container: string;\n    keycap: string;\n    font: string;\n  }\n> = {\n  sm: {\n    container: \"gap-1\",\n    keycap: \"min-w-[22px] h-[22px] px-1.5 rounded text-[10px]\",\n    font: \"text-[10px]\",\n  },\n  md: {\n    container: \"gap-1.5\",\n    keycap: \"min-w-[28px] h-[28px] px-2 rounded-md text-xs\",\n    font: \"text-xs\",\n  },\n  lg: {\n    container: \"gap-2\",\n    keycap: \"min-w-[38px] h-[36px] px-3 rounded-lg text-sm font-semibold\",\n    font: \"text-sm\",\n  },\n};\n\nexport function KeycapChips({\n  shortcuts = DEFAULT_SHORTCUTS,\n  keys,\n  size = \"md\",\n  variant = \"obsidian\",\n  enableGlobalListener = true,\n  inline = false,\n  onShortcutPress,\n  className,\n}: KeycapChipsProps) {\n  const [activeSize, setActiveSize] = useState<KeycapSize>(size);\n  const [activeVariant, setActiveVariant] = useState<KeycapVariant>(variant);\n  const [activePressedKey, setActivePressedKey] = useState<string | null>(null);\n  const [lastExecuted, setLastExecuted] = useState<string | null>(null);\n  const [soundEnabled, setSoundEnabled] = useState<boolean>(true);\n  const [customCombo, setCustomCombo] = useState<string[]>([]);\n  const [isRecording, setIsRecording] = useState<boolean>(false);\n\n  const vStyle = VARIANT_STYLES[activeVariant];\n  const sStyle = SIZE_STYLES[activeSize];\n\n  // Key press sound simulation via Web Audio API synth click\n  const playClickSound = useCallback(() => {\n    if (!soundEnabled) return;\n    try {\n      const audioCtx = new (window.AudioContext || (window as unknown as { webkitAudioContext: typeof AudioContext }).webkitAudioContext)();\n      const osc = audioCtx.createOscillator();\n      const gain = audioCtx.createGain();\n      osc.type = \"sine\";\n      osc.frequency.setValueAtTime(800, audioCtx.currentTime);\n      osc.frequency.exponentialRampToValueAtTime(150, audioCtx.currentTime + 0.04);\n      gain.gain.setValueAtTime(0.12, audioCtx.currentTime);\n      gain.gain.exponentialRampToValueAtTime(0.001, audioCtx.currentTime + 0.04);\n      osc.connect(gain);\n      gain.connect(audioCtx.destination);\n      osc.start();\n      osc.stop(audioCtx.currentTime + 0.04);\n    } catch {\n      // AudioContext unavailable or blocked\n    }\n  }, [soundEnabled]);\n\n  // Global keyboard listener to depress keycaps physically\n  useEffect(() => {\n    if (!enableGlobalListener) return;\n\n    const handleKeyDown = (e: KeyboardEvent) => {\n      // Ignore if typing inside input\n      if (\n        e.target instanceof HTMLInputElement ||\n        e.target instanceof HTMLTextAreaElement\n      ) {\n        return;\n      }\n\n      let keyLabel = e.key;\n      if (e.metaKey || e.key === \"Meta\") keyLabel = \"⌘\";\n      else if (e.altKey || e.key === \"Alt\") keyLabel = \"⌥\";\n      else if (e.shiftKey && e.key !== \"Shift\") keyLabel = \"⇧\";\n      else if (e.ctrlKey || e.key === \"Control\") keyLabel = \"⌃\";\n      else if (e.key === \"Enter\") keyLabel = \"↵\";\n      else if (e.key === \"Escape\") keyLabel = \"Esc\";\n      else if (e.key === \" \") keyLabel = \"Space\";\n      else keyLabel = e.key.toUpperCase();\n\n      setActivePressedKey(keyLabel);\n      playClickSound();\n\n      if (isRecording) {\n        setCustomCombo((prev) => {\n          if (!prev.includes(keyLabel) && prev.length < 4) {\n            return [...prev, keyLabel];\n          }\n          return prev;\n        });\n      }\n    };\n\n    const handleKeyUp = () => {\n      setActivePressedKey(null);\n    };\n\n    window.addEventListener(\"keydown\", handleKeyDown);\n    window.addEventListener(\"keyup\", handleKeyUp);\n    return () => {\n      window.removeEventListener(\"keydown\", handleKeyDown);\n      window.removeEventListener(\"keyup\", handleKeyUp);\n    };\n  }, [enableGlobalListener, isRecording, playClickSound]);\n\n  const triggerShortcut = (item: ShortcutItem) => {\n    playClickSound();\n    setLastExecuted(item.name);\n    setTimeout(() => setLastExecuted(null), 2500);\n  };\n\n  if (inline) {\n    const displayKeys =\n      keys || (shortcuts.length > 0 ? shortcuts[0].keys : [\"⌘\", \"K\"]);\n    return (\n      <div className={cn(\"inline-flex items-center\", sStyle.container, className)}>\n        {displayKeys.map((k, idx) => (\n          <kbd\n            key={idx}\n            className={cn(\n              \"inline-flex items-center justify-center font-mono font-bold select-none cursor-pointer transition-all duration-100\",\n              sStyle.keycap,\n              activePressedKey === k ? vStyle.keycapPressed : vStyle.keycap\n            )}\n            onClick={() => {\n              playClickSound();\n              onShortcutPress?.(k);\n            }}\n          >\n            {k}\n          </kbd>\n        ))}\n      </div>\n    );\n  }\n\n  return (\n    <div\n      data-fullscreen-scroll\n      className={cn(\n        \"relative w-full min-h-[520px] overflow-hidden rounded-2xl border border-neutral-800 bg-[#090A0F] p-6 text-white shadow-2xl flex flex-col justify-between selection:bg-neutral-700\",\n        className\n      )}\n    >\n      {/* Subtle grid pattern */}\n      <div\n        className=\"pointer-events-none absolute inset-0 opacity-15\"\n        style={{\n          backgroundImage:\n            \"linear-gradient(#262626 1px, transparent 1px), linear-gradient(to right, #262626 1px, transparent 1px)\",\n          backgroundSize: \"28px 28px\",\n        }}\n      />\n\n      {/* Header bar */}\n      <div className=\"relative z-10 flex flex-wrap items-center justify-between gap-4 border-b border-neutral-800/80 pb-4\">\n        <div className=\"flex items-center gap-2.5\">\n          <div className=\"flex h-8 w-8 items-center justify-center rounded-lg border border-neutral-700 bg-neutral-900 font-mono text-xs font-bold text-neutral-200\">\n            <Command className=\"h-4 w-4\" />\n          </div>\n          <div>\n            <h3 className=\"text-sm font-semibold tracking-tight text-white flex items-center gap-2\">\n              Tactile Keycap Chips\n              <span\n                className={cn(\n                  \"text-[10px] uppercase font-mono px-2 py-0.5 rounded-full border\",\n                  vStyle.badge\n                )}\n              >\n                {activeVariant}\n              </span>\n            </h3>\n            <p className=\"text-xs text-neutral-400 font-mono\">\n              Raycast-grade 3D mechanical bevels with keypress haptics\n            </p>\n          </div>\n        </div>\n\n        {/* Live Controls */}\n        <div className=\"flex flex-wrap items-center gap-2\">\n          {/* Variant picker */}\n          <div className=\"flex items-center rounded-lg border border-neutral-800 bg-neutral-900/90 p-1\">\n            {([\"obsidian\", \"classic\", \"cyber\", \"porcelain\"] as const).map((v) => (\n              <button\n                key={v}\n                onClick={() => setActiveVariant(v)}\n                className={cn(\n                  \"px-2.5 py-1 text-[11px] font-mono rounded capitalize transition-all\",\n                  activeVariant === v\n                    ? \"bg-neutral-800 text-white font-bold shadow-sm\"\n                    : \"text-neutral-400 hover:text-neutral-200\"\n                )}\n              >\n                {v}\n              </button>\n            ))}\n          </div>\n\n          {/* Size picker */}\n          <div className=\"flex items-center rounded-lg border border-neutral-800 bg-neutral-900/90 p-1 font-mono text-[10px]\">\n            {([\"sm\", \"md\", \"lg\"] as const).map((s) => (\n              <button\n                key={s}\n                onClick={() => setActiveSize(s)}\n                className={cn(\n                  \"px-2.5 py-1 rounded uppercase transition-all\",\n                  activeSize === s\n                    ? \"bg-neutral-800 text-white font-bold\"\n                    : \"text-neutral-400 hover:text-neutral-200\"\n                )}\n              >\n                {s}\n              </button>\n            ))}\n          </div>\n\n          {/* Sound Toggle */}\n          <button\n            onClick={() => setSoundEnabled(!soundEnabled)}\n            aria-label={soundEnabled ? \"Mute audio\" : \"Unmute audio\"}\n            className={cn(\n              \"flex items-center gap-1.5 px-2.5 py-1 text-xs font-mono rounded-lg border transition-all\",\n              soundEnabled\n                ? \"border-neutral-700 bg-neutral-800 text-white\"\n                : \"border-neutral-800 bg-neutral-900 text-neutral-500 hover:text-neutral-300\"\n            )}\n          >\n            {soundEnabled ? (\n              <Volume2 className=\"h-3.5 w-3.5 text-cyan-400\" />\n            ) : (\n              <VolumeX className=\"h-3.5 w-3.5\" />\n            )}\n            <span>{soundEnabled ? \"Audio On\" : \"Muted\"}</span>\n          </button>\n        </div>\n      </div>\n\n      {/* Main Showcase: Shortcut List */}\n      <div className=\"relative z-10 my-6 flex flex-col gap-2.5 max-w-2xl mx-auto w-full\">\n        {shortcuts.map((item) => {\n          const isRowActive = item.keys.includes(activePressedKey || \"\");\n\n          return (\n            <motion.div\n              key={item.id}\n              tabIndex={0}\n              role=\"button\"\n              onClick={() => triggerShortcut(item)}\n              onKeyDown={(e) => {\n                if (e.key === \"Enter\" || e.key === \" \") {\n                  e.preventDefault();\n                  triggerShortcut(item);\n                }\n              }}\n              whileHover={{ scale: 1.01 }}\n              whileTap={{ scale: 0.99 }}\n              className={cn(\n                \"group flex items-center justify-between rounded-xl border p-3.5 transition-all cursor-pointer backdrop-blur-sm\",\n                isRowActive\n                  ? \"border-cyan-500/50 bg-neutral-800/90 shadow-md\"\n                  : \"border-neutral-800/90 bg-neutral-950/60 hover:border-neutral-700 hover:bg-neutral-900/60\"\n              )}\n            >\n              <div className=\"flex items-center gap-3\">\n                <span className=\"font-mono text-[10px] text-neutral-500 uppercase\">\n                  {item.category}\n                </span>\n                <span className=\"text-sm font-medium text-neutral-200 group-hover:text-white transition-colors\">\n                  {item.name}\n                </span>\n              </div>\n\n              {/* Physical 3D Keycaps */}\n              <div className={cn(\"flex items-center\", sStyle.container)}>\n                {item.keys.map((k, kIdx) => {\n                  const isKeyPressed = activePressedKey === k;\n                  return (\n                    <kbd\n                      key={kIdx}\n                      className={cn(\n                        \"inline-flex items-center justify-center font-mono font-bold select-none cursor-pointer transition-all duration-100\",\n                        sStyle.keycap,\n                        isKeyPressed ? vStyle.keycapPressed : vStyle.keycap\n                      )}\n                    >\n                      {k}\n                    </kbd>\n                  );\n                })}\n              </div>\n            </motion.div>\n          );\n        })}\n      </div>\n\n      {/* Toast Notification of Triggered Shortcut */}\n      <AnimatePresence>\n        {lastExecuted && (\n          <motion.div\n            initial={{ opacity: 0, y: 10, scale: 0.95 }}\n            animate={{ opacity: 1, y: 0, scale: 1 }}\n            exit={{ opacity: 0, y: 10, scale: 0.95 }}\n            className=\"relative z-20 mx-auto -mt-2 mb-4 flex items-center gap-2 rounded-full border border-emerald-500/40 bg-emerald-950/80 px-4 py-1.5 font-mono text-xs text-emerald-300 backdrop-blur-md shadow-lg\"\n          >\n            <CheckCircle2 className=\"h-3.5 w-3.5 text-emerald-400\" />\n            <span>Action Dispatched: &ldquo;{lastExecuted}&rdquo;</span>\n          </motion.div>\n        )}\n      </AnimatePresence>\n\n      {/* Bottom Interactive Key Recorder */}\n      <div className=\"relative z-10 border-t border-neutral-800/80 pt-4 flex flex-wrap items-center justify-between gap-4 text-xs\">\n        <div className=\"flex items-center gap-3\">\n          <button\n            onClick={() => {\n              setIsRecording(!isRecording);\n              if (!isRecording) setCustomCombo([]);\n            }}\n            className={cn(\n              \"flex items-center gap-1.5 px-3 py-1.5 rounded-lg border font-mono text-xs transition-all\",\n              isRecording\n                ? \"border-rose-500/60 bg-rose-950/50 text-rose-300 animate-pulse\"\n                : \"border-neutral-700 bg-neutral-900 text-neutral-300 hover:text-white\"\n            )}\n          >\n            <Keyboard className=\"h-3.5 w-3.5\" />\n            <span>{isRecording ? \"Recording Keys...\" : \"Record Shortcut\"}</span>\n          </button>\n\n          {customCombo.length > 0 && (\n            <div className=\"flex items-center gap-1.5\">\n              <span className=\"font-mono text-neutral-500 text-[11px]\">Recorded:</span>\n              <div className=\"flex items-center gap-1\">\n                {customCombo.map((k, i) => (\n                  <kbd\n                    key={i}\n                    className={cn(\n                      \"inline-flex items-center justify-center font-mono font-bold px-2 py-0.5 rounded text-xs\",\n                      vStyle.keycap\n                    )}\n                  >\n                    {k}\n                  </kbd>\n                ))}\n              </div>\n              <button\n                onClick={() => setCustomCombo([])}\n                aria-label=\"Clear recorded shortcut\"\n                className=\"text-neutral-500 hover:text-neutral-300 p-1\"\n              >\n                <Trash2 className=\"h-3.5 w-3.5\" />\n              </button>\n            </div>\n          )}\n        </div>\n\n        <div className=\"flex items-center gap-4 font-mono text-[11px] text-neutral-400\">\n          <span>\n            LAST KEY:{\" \"}\n            <span className=\"text-white font-bold\">\n              {activePressedKey ? activePressedKey : \"NONE\"}\n            </span>\n          </span>\n          <span className=\"hidden sm:inline\">GLOBAL LISTENER: ACTIVE</span>\n        </div>\n      </div>\n    </div>\n  );\n}\n\nexport default KeycapChips;\n",
          "type": "registry:ui",
          "target": "components/ui/keycap-chips.tsx"
        },
        {
          "path": "lib/utils.ts",
          "content": "import { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...inputs: ClassValue[]) {\n  return twMerge(clsx(inputs));\n}\n\nexport async function copyToClipboard(text: string): Promise<boolean> {\n  if (typeof window === \"undefined\") return false;\n\n  try {\n    if (navigator.clipboard && window.isSecureContext) {\n      await navigator.clipboard.writeText(text);\n      return true;\n    }\n\n    const textArea = document.createElement(\"textarea\");\n    textArea.value = text;\n    textArea.style.position = \"fixed\";\n    textArea.style.left = \"-999999px\";\n    textArea.style.top = \"-999999px\";\n    document.body.appendChild(textArea);\n    textArea.focus();\n    textArea.select();\n    const succeeded = document.execCommand(\"copy\");\n    textArea.remove();\n    return succeeded;\n  } catch {\n    return false;\n  }\n}\n",
          "type": "registry:lib",
          "target": "lib/utils.ts"
        }
      ]
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "kinetic-drawer-sheet",
      "type": "registry:ui",
      "title": "Kinetic Drawer Sheet",
      "author": "Rishabh Bose <https://theb0se.vercel.app/>",
      "description": "Bottom gesture sheet featuring Peek and Full spring detents, velocity-projected flick transitions, and rubber-band over-drag.",
      "dependencies": [
        "framer-motion",
        "lucide-react",
        "clsx",
        "tailwind-merge"
      ],
      "files": [
        {
          "path": "components/ui/kinetic-drawer-sheet.tsx",
          "content": "\"use client\";\n\nimport React, { useEffect, useState } from \"react\";\nimport {\n  AnimatePresence,\n  motion,\n  useReducedMotion,\n  type PanInfo,\n} from \"framer-motion\";\nimport { PanelBottomOpen, Sparkles, X } from \"lucide-react\";\nimport { cn } from \"@/lib/utils\";\n\nexport type DrawerDetent = \"peek\" | \"full\";\n\nexport interface KineticDrawerSheetProps {\n  /** Trigger button label. Default: \"Open Gesture Drawer\" */\n  triggerLabel?: string;\n  /** Drawer heading title. Default: \"Multi-Detent Spring Sheet\" */\n  title?: string;\n  /** Spring stiffness coefficient for sheet slide and detent snapping. Default: 320 */\n  stiffness?: number;\n  /** Spring damping coefficient for sheet slide and detent snapping. Default: 28 */\n  damping?: number;\n  className?: string;\n}\n\nexport function KineticDrawerSheet({\n  triggerLabel = \"Open Gesture Drawer\",\n  title = \"Multi-Detent Spring Sheet\",\n  stiffness = 320,\n  damping = 28,\n  className,\n}: KineticDrawerSheetProps) {\n  const shouldReduceMotion = useReducedMotion() ?? false;\n  const [isOpen, setIsOpen] = useState(false);\n  const [detent, setDetent] = useState<DrawerDetent>(\"peek\");\n\n  useEffect(() => {\n    if (!isOpen) return;\n    const onKeyDown = (e: KeyboardEvent) => {\n      if (e.key === \"Escape\") {\n        setIsOpen(false);\n      }\n    };\n    window.addEventListener(\"keydown\", onKeyDown);\n    return () => window.removeEventListener(\"keydown\", onKeyDown);\n  }, [isOpen]);\n\n  const handleDragEnd = (\n    _e: MouseEvent | TouchEvent | PointerEvent,\n    info: PanInfo\n  ) => {\n    if (info.offset.y > 75 || info.velocity.y > 400) {\n      if (detent === \"full\") {\n        setDetent(\"peek\");\n      } else {\n        setIsOpen(false);\n      }\n    } else if (info.offset.y < -50 || info.velocity.y < -350) {\n      setDetent(\"full\");\n    }\n  };\n\n  return (\n    <div className={cn(\"inline-block\", className)}>\n      <button\n        type=\"button\"\n        aria-haspopup=\"dialog\"\n        aria-expanded={isOpen}\n        onClick={() => {\n          setDetent(\"peek\");\n          setIsOpen(true);\n        }}\n        className=\"inline-flex h-11 items-center gap-2 rounded-2xl border border-neutral-200 bg-white px-5 text-xs font-semibold text-black shadow-sm transition-colors hover:border-black focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-black dark:border-[#222222] dark:bg-[#0A0A0A] dark:text-white dark:hover:border-white dark:focus-visible:ring-white\"\n      >\n        <PanelBottomOpen className=\"h-4 w-4\" />\n        <span>{triggerLabel}</span>\n      </button>\n\n      <AnimatePresence>\n        {isOpen && (\n          <div className=\"fixed inset-0 z-50 flex items-end justify-center p-4 sm:p-6\">\n            {/* Backdrop */}\n            <motion.div\n              initial={{ opacity: 0 }}\n              animate={{ opacity: 1 }}\n              exit={{ opacity: 0 }}\n              transition={{ duration: 0.18 }}\n              onClick={() => setIsOpen(false)}\n              aria-hidden=\"true\"\n              className=\"fixed inset-0 bg-black/50 backdrop-blur-sm\"\n            />\n\n            {/* Bottom Detent Sheet */}\n            <motion.div\n              layout\n              role=\"dialog\"\n              aria-modal=\"true\"\n              aria-label={title}\n              initial={{ y: \"100%\", opacity: 0.5 }}\n              animate={{ y: 0, opacity: 1 }}\n              exit={{ y: \"100%\", opacity: 0 }}\n              transition={\n                shouldReduceMotion\n                  ? { duration: 0.01 }\n                  : { type: \"spring\", stiffness, damping }\n              }\n              drag={shouldReduceMotion ? false : \"y\"}\n              dragConstraints={{ top: 0, bottom: 0 }}\n              dragElastic={0.32}\n              onDragEnd={handleDragEnd}\n              className=\"relative z-10 w-full max-w-md overflow-hidden rounded-3xl border border-neutral-200 bg-white p-6 text-left shadow-2xl dark:border-[#262626] dark:bg-[#0D0D0D]\"\n            >\n              {/* Grab Bar */}\n              <div\n                aria-hidden=\"true\"\n                className=\"mx-auto mb-4 h-1.5 w-12 cursor-grab rounded-full bg-neutral-200 active:cursor-grabbing dark:bg-[#262626]\"\n              />\n\n              <div className=\"flex items-center justify-between gap-3\">\n                <div className=\"flex items-center gap-2.5\">\n                  <div className=\"flex h-9 w-9 items-center justify-center rounded-xl border border-neutral-200 bg-neutral-50 text-black dark:border-[#262626] dark:bg-[#141414] dark:text-white\">\n                    <Sparkles className=\"h-4 w-4\" />\n                  </div>\n                  <div>\n                    <h3 className=\"text-sm font-semibold text-black dark:text-white\">\n                      {title}\n                    </h3>\n                    <p className=\"font-mono text-[10px] uppercase text-neutral-400\">\n                      DETENT: {detent.toUpperCase()} • DRAG UP/DOWN\n                    </p>\n                  </div>\n                </div>\n\n                <button\n                  type=\"button\"\n                  aria-label=\"Close drawer\"\n                  onClick={() => setIsOpen(false)}\n                  className=\"flex h-8 w-8 items-center justify-center rounded-full border border-neutral-200 text-neutral-500 transition-colors hover:border-black hover:text-black dark:border-[#262626] dark:hover:border-white dark:hover:text-white\"\n                >\n                  <X className=\"h-4 w-4\" />\n                </button>\n              </div>\n\n              <p className=\"mt-4 text-xs leading-relaxed text-neutral-600 dark:text-neutral-300\">\n                Flick upward or press the detent toggle below to expand full\n                diagnostics. Flick downward or press Escape to dismiss.\n              </p>\n\n              {detent === \"full\" && (\n                <motion.div\n                  initial={{ opacity: 0, y: 8 }}\n                  animate={{ opacity: 1, y: 0 }}\n                  className=\"mt-4 rounded-2xl border border-neutral-200 bg-neutral-50 p-4 font-mono text-xs dark:border-[#1F1F1F] dark:bg-[#141414]\"\n                >\n                  <div className=\"flex justify-between py-1\">\n                    <span className=\"text-neutral-400\">Spring Solver:</span>\n                    <span className=\"font-semibold text-black dark:text-white\">\n                      k={stiffness}, c={damping}\n                    </span>\n                  </div>\n                  <div className=\"flex justify-between py-1\">\n                    <span className=\"text-neutral-400\">Drag Elasticity:</span>\n                    <span className=\"font-semibold text-black dark:text-white\">\n                      0.32 (Rubber-Band)\n                    </span>\n                  </div>\n                </motion.div>\n              )}\n\n              <div className=\"mt-5 flex items-center justify-between gap-2\">\n                <button\n                  type=\"button\"\n                  onClick={() =>\n                    setDetent((d) => (d === \"peek\" ? \"full\" : \"peek\"))\n                  }\n                  className=\"rounded-xl border border-neutral-200 px-3.5 py-2 text-xs font-semibold text-black transition-colors hover:border-black dark:border-[#262626] dark:text-white dark:hover:border-white\"\n                >\n                  {detent === \"peek\" ? \"Expand Full Detent\" : \"Snap to Peek\"}\n                </button>\n                <button\n                  type=\"button\"\n                  onClick={() => setIsOpen(false)}\n                  className=\"rounded-xl bg-black px-4 py-2 text-xs font-semibold text-white dark:bg-white dark:text-black\"\n                >\n                  Done\n                </button>\n              </div>\n            </motion.div>\n          </div>\n        )}\n      </AnimatePresence>\n    </div>\n  );\n}\n\nexport default KineticDrawerSheet;\n",
          "type": "registry:ui",
          "target": "components/ui/kinetic-drawer-sheet.tsx"
        },
        {
          "path": "lib/utils.ts",
          "content": "import { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...inputs: ClassValue[]) {\n  return twMerge(clsx(inputs));\n}\n\nexport async function copyToClipboard(text: string): Promise<boolean> {\n  if (typeof window === \"undefined\") return false;\n\n  try {\n    if (navigator.clipboard && window.isSecureContext) {\n      await navigator.clipboard.writeText(text);\n      return true;\n    }\n\n    const textArea = document.createElement(\"textarea\");\n    textArea.value = text;\n    textArea.style.position = \"fixed\";\n    textArea.style.left = \"-999999px\";\n    textArea.style.top = \"-999999px\";\n    document.body.appendChild(textArea);\n    textArea.focus();\n    textArea.select();\n    const succeeded = document.execCommand(\"copy\");\n    textArea.remove();\n    return succeeded;\n  } catch {\n    return false;\n  }\n}\n",
          "type": "registry:lib",
          "target": "lib/utils.ts"
        }
      ]
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "kinetic-rolling-counter",
      "type": "registry:ui",
      "title": "Kinetic Rolling Counter",
      "author": "Rishabh Bose <https://theb0se.vercel.app/>",
      "description": "Mechanical odometer numeric ticker where each digit column spins independently along a vertical 0-9 reel using Hooke's Law springs.",
      "dependencies": [
        "framer-motion",
        "lucide-react",
        "clsx",
        "tailwind-merge"
      ],
      "files": [
        {
          "path": "components/ui/kinetic-rolling-counter.tsx",
          "content": "\"use client\";\n\nimport React, { useState } from \"react\";\nimport { motion, useReducedMotion } from \"framer-motion\";\nimport { Minus, Plus } from \"lucide-react\";\nimport { cn } from \"@/lib/utils\";\n\nexport interface KineticRollingCounterProps {\n  /** Initial integer value. Default: 1248 */\n  defaultValue?: number;\n  /** Increment step size. Default: 17 */\n  step?: number;\n  /** Hooke's Law spring stiffness coefficient for digit reel rotation. Default: 340 */\n  stiffness?: number;\n  /** Spring damping coefficient for digit reel rotation. Default: 26 */\n  damping?: number;\n  className?: string;\n}\n\nconst DIGITS = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];\n\ninterface DigitReelColumnProps {\n  digit: number;\n  stiffness: number;\n  damping: number;\n  shouldReduceMotion: boolean;\n}\n\nfunction DigitReelColumn({\n  digit,\n  stiffness,\n  damping,\n  shouldReduceMotion,\n}: DigitReelColumnProps) {\n  return (\n    <div\n      aria-hidden=\"true\"\n      className=\"relative h-9 w-6 overflow-hidden rounded-lg border border-neutral-200 bg-neutral-50 font-mono text-lg font-bold tabular-nums text-black dark:border-[#262626] dark:bg-[#141414] dark:text-white\"\n    >\n      <motion.div\n        animate={{ y: `-${digit * 10}%` }}\n        transition={\n          shouldReduceMotion\n            ? { duration: 0 }\n            : { type: \"spring\", stiffness, damping }\n        }\n        className=\"flex flex-col items-center\"\n      >\n        {DIGITS.map((n) => (\n          <span\n            key={n}\n            className=\"flex h-9 w-6 items-center justify-center leading-none\"\n          >\n            {n}\n          </span>\n        ))}\n      </motion.div>\n    </div>\n  );\n}\n\nexport function KineticRollingCounter({\n  defaultValue = 1248,\n  step = 17,\n  stiffness = 340,\n  damping = 26,\n  className,\n}: KineticRollingCounterProps) {\n  const shouldReduceMotion = useReducedMotion() ?? false;\n  const [count, setCount] = useState<number>(Math.max(0, defaultValue));\n\n  const formatted = String(Math.max(0, count)).padStart(4, \"0\");\n  const digitArray = formatted.split(\"\").map((ch) => Number(ch) || 0);\n\n  return (\n    <div\n      className={cn(\n        \"inline-flex items-center gap-3 rounded-2xl border border-neutral-200 bg-white px-4 py-3 shadow-sm dark:border-[#222222] dark:bg-[#0A0A0A]\",\n        className\n      )}\n    >\n      <button\n        type=\"button\"\n        aria-label={`Decrease counter by ${step}`}\n        onClick={() => setCount((c) => Math.max(0, c - step))}\n        className=\"flex h-8 w-8 items-center justify-center rounded-xl border border-neutral-200 text-neutral-600 transition-colors hover:border-black hover:text-black focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-black dark:border-[#262626] dark:text-neutral-300 dark:hover:border-white dark:hover:text-white dark:focus-visible:ring-white\"\n      >\n        <Minus className=\"h-3.5 w-3.5\" />\n      </button>\n\n      {/* Screen-reader live region */}\n      <span className=\"sr-only\" role=\"status\" aria-live=\"polite\">\n        Current value: {count}\n      </span>\n\n      {/* Mechanical Odometer Digit Reels */}\n      <div className=\"flex items-center gap-1\">\n        {digitArray.map((d, idx) => (\n          <DigitReelColumn\n            key={idx}\n            digit={d}\n            stiffness={stiffness}\n            damping={damping}\n            shouldReduceMotion={shouldReduceMotion}\n          />\n        ))}\n      </div>\n\n      <button\n        type=\"button\"\n        aria-label={`Increase counter by ${step}`}\n        onClick={() => setCount((c) => c + step)}\n        className=\"flex h-8 w-8 items-center justify-center rounded-xl border border-black bg-black text-white transition-opacity hover:opacity-90 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-black dark:border-white dark:bg-white dark:text-black dark:focus-visible:ring-white\"\n      >\n        <Plus className=\"h-3.5 w-3.5\" />\n      </button>\n    </div>\n  );\n}\n\nexport default KineticRollingCounter;\n",
          "type": "registry:ui",
          "target": "components/ui/kinetic-rolling-counter.tsx"
        },
        {
          "path": "lib/utils.ts",
          "content": "import { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...inputs: ClassValue[]) {\n  return twMerge(clsx(inputs));\n}\n\nexport async function copyToClipboard(text: string): Promise<boolean> {\n  if (typeof window === \"undefined\") return false;\n\n  try {\n    if (navigator.clipboard && window.isSecureContext) {\n      await navigator.clipboard.writeText(text);\n      return true;\n    }\n\n    const textArea = document.createElement(\"textarea\");\n    textArea.value = text;\n    textArea.style.position = \"fixed\";\n    textArea.style.left = \"-999999px\";\n    textArea.style.top = \"-999999px\";\n    document.body.appendChild(textArea);\n    textArea.focus();\n    textArea.select();\n    const succeeded = document.execCommand(\"copy\");\n    textArea.remove();\n    return succeeded;\n  } catch {\n    return false;\n  }\n}\n",
          "type": "registry:lib",
          "target": "lib/utils.ts"
        }
      ]
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "kinetic-slider",
      "type": "registry:ui",
      "title": "Kinetic Slider",
      "author": "Rishabh Bose <https://theb0se.vercel.app/>",
      "description": "Elastic range slider featuring velocity-reactive tooltip inertia, logarithmic rubber-band boundary over-drag, and full keyboard accessibility.",
      "dependencies": [
        "framer-motion",
        "clsx",
        "tailwind-merge"
      ],
      "files": [
        {
          "path": "components/ui/kinetic-slider.tsx",
          "content": "\"use client\";\n\nimport React, { useRef, useState, useEffect } from \"react\";\nimport {\n  motion,\n  useMotionValue,\n  useSpring,\n  useVelocity,\n  useTransform,\n  useReducedMotion,\n} from \"framer-motion\";\nimport { cn } from \"@/lib/utils\";\n\nexport interface KineticSliderProps {\n  /** Field label displayed above the slider track. Default: \"Spring Tension\" */\n  label?: string;\n  /** Controlled numeric value */\n  value?: number;\n  /** Uncontrolled initial numeric value. Default: 64 */\n  defaultValue?: number;\n  /** Minimum value. Default: 0 */\n  min?: number;\n  /** Maximum value. Default: 100 */\n  max?: number;\n  /** Increment step size. Default: 1 */\n  step?: number;\n  /** Unit suffix appended to displayed value (e.g. \"%\", \"Hz\", \"ms\"). Default: \"%\" */\n  unit?: string;\n  /** Hooke's Law spring stiffness coefficient. Default: 340 */\n  stiffness?: number;\n  /** Spring damping coefficient. Default: 24 */\n  damping?: number;\n  /** Callback fired when value changes */\n  onChange?: (value: number) => void;\n  className?: string;\n}\n\nexport function KineticSlider({\n  label = \"Spring Tension\",\n  value: controlledValue,\n  defaultValue = 64,\n  min = 0,\n  max = 100,\n  step = 1,\n  unit = \"%\",\n  stiffness = 340,\n  damping = 24,\n  onChange,\n  className,\n}: KineticSliderProps) {\n  const shouldReduceMotion = useReducedMotion() ?? false;\n  const trackRef = useRef<HTMLDivElement | null>(null);\n\n  const [internalValue, setInternalValue] = useState<number>(() =>\n    Math.min(max, Math.max(min, defaultValue))\n  );\n  const [isDragging, setIsDragging] = useState(false);\n  const [isHovered, setIsHovered] = useState(false);\n  const [isFocused, setIsFocused] = useState(false);\n\n  const currentValue =\n    controlledValue !== undefined ? controlledValue : internalValue;\n  const range = Math.max(1, max - min);\n  const normalizedPct = ((currentValue - min) / range) * 100;\n\n  const pctMotion = useMotionValue(normalizedPct);\n  const springPct = useSpring(pctMotion, {\n    stiffness,\n    damping,\n    mass: 0.4,\n  });\n\n  // Rubber-band overdrag horizontal stretch in pixels\n  const overdragX = useMotionValue(0);\n  const springOverdragX = useSpring(overdragX, {\n    stiffness: 420,\n    damping: 26,\n  });\n\n  // Velocity-reactive tooltip tilt\n  const pctVelocity = useVelocity(springPct);\n  const rawTilt = useTransform(pctVelocity, [-250, 0, 250], [-14, 0, 14]);\n  const tooltipRotate = useSpring(rawTilt, {\n    stiffness: 320,\n    damping: 20,\n  });\n\n  const fillWidth = useTransform(springPct, (v) => `${Math.max(0, Math.min(100, v))}%`);\n\n  useEffect(() => {\n    pctMotion.set(((currentValue - min) / range) * 100);\n  }, [currentValue, min, range, pctMotion]);\n\n  const commitValue = (nextRaw: number) => {\n    const stepped = Math.round((nextRaw - min) / step) * step + min;\n    const clamped = Math.min(max, Math.max(min, Number(stepped.toFixed(4))));\n    if (controlledValue === undefined) {\n      setInternalValue(clamped);\n    }\n    onChange?.(clamped);\n  };\n\n  const updateFromClientX = (clientX: number) => {\n    const track = trackRef.current;\n    if (!track) return;\n    const rect = track.getBoundingClientRect();\n    const rawRatio = (clientX - rect.left) / rect.width;\n\n    if (rawRatio < 0) {\n      const excessPx = clientX - rect.left;\n      const rubber = -Math.log1p(Math.abs(excessPx)) * 3.2;\n      overdragX.set(shouldReduceMotion ? 0 : rubber);\n      commitValue(min);\n    } else if (rawRatio > 1) {\n      const excessPx = clientX - rect.right;\n      const rubber = Math.log1p(Math.abs(excessPx)) * 3.2;\n      overdragX.set(shouldReduceMotion ? 0 : rubber);\n      commitValue(max);\n    } else {\n      overdragX.set(0);\n      commitValue(min + rawRatio * range);\n    }\n  };\n\n  const handlePointerDown = (e: React.PointerEvent<HTMLDivElement>) => {\n    e.currentTarget.setPointerCapture(e.pointerId);\n    setIsDragging(true);\n    updateFromClientX(e.clientX);\n  };\n\n  const handlePointerMove = (e: React.PointerEvent<HTMLDivElement>) => {\n    if (!isDragging) return;\n    updateFromClientX(e.clientX);\n  };\n\n  const handlePointerUp = (e: React.PointerEvent<HTMLDivElement>) => {\n    if (e.currentTarget.hasPointerCapture(e.pointerId)) {\n      e.currentTarget.releasePointerCapture(e.pointerId);\n    }\n    setIsDragging(false);\n    overdragX.set(0);\n  };\n\n  const handleKeyDown = (e: React.KeyboardEvent<HTMLDivElement>) => {\n    const largeStep = step * 10;\n    if (e.key === \"ArrowRight\" || e.key === \"ArrowUp\") {\n      e.preventDefault();\n      commitValue(currentValue + step);\n    } else if (e.key === \"ArrowLeft\" || e.key === \"ArrowDown\") {\n      e.preventDefault();\n      commitValue(currentValue - step);\n    } else if (e.key === \"PageUp\") {\n      e.preventDefault();\n      commitValue(currentValue + largeStep);\n    } else if (e.key === \"PageDown\") {\n      e.preventDefault();\n      commitValue(currentValue - largeStep);\n    } else if (e.key === \"Home\") {\n      e.preventDefault();\n      commitValue(min);\n    } else if (e.key === \"End\") {\n      e.preventDefault();\n      commitValue(max);\n    }\n  };\n\n  const showBubble = isDragging || isHovered || isFocused;\n\n  return (\n    <motion.div\n      style={{ x: shouldReduceMotion ? 0 : springOverdragX }}\n      className={cn(\n        \"w-full max-w-sm select-none rounded-2xl border border-neutral-200 bg-white p-5 dark:border-[#222222] dark:bg-[#0A0A0A]\",\n        className\n      )}\n    >\n      <div className=\"mb-4 flex items-center justify-between text-xs\">\n        <span className=\"font-semibold tracking-tight text-black dark:text-white\">\n          {label}\n        </span>\n        <span className=\"font-mono text-xs font-medium tabular-nums text-neutral-500 dark:text-neutral-400\">\n          {currentValue}\n          {unit}\n        </span>\n      </div>\n\n      {/* Interactive Slider Track */}\n      <div\n        ref={trackRef}\n        role=\"slider\"\n        tabIndex={0}\n        aria-label={label}\n        aria-valuemin={min}\n        aria-valuemax={max}\n        aria-valuenow={currentValue}\n        aria-valuetext={`${currentValue}${unit}`}\n        onPointerDown={handlePointerDown}\n        onPointerMove={handlePointerMove}\n        onPointerUp={handlePointerUp}\n        onPointerCancel={handlePointerUp}\n        onMouseEnter={() => setIsHovered(true)}\n        onMouseLeave={() => setIsHovered(false)}\n        onFocus={() => setIsFocused(true)}\n        onBlur={() => setIsFocused(false)}\n        onKeyDown={handleKeyDown}\n        className=\"group relative flex h-9 cursor-ew-resize touch-none items-center rounded-xl focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-black dark:focus-visible:ring-white\"\n      >\n        {/* Background Rail */}\n        <motion.div\n          animate={{\n            height: isDragging ? 10 : isHovered ? 8 : 6,\n          }}\n          transition={{ type: \"spring\", stiffness: 360, damping: 26 }}\n          className=\"relative w-full overflow-hidden rounded-full bg-neutral-200 dark:bg-[#1E1E1E]\"\n        >\n          {/* Active Fill Bar */}\n          <motion.div\n            style={{\n              width: shouldReduceMotion ? `${normalizedPct}%` : fillWidth,\n            }}\n            className=\"h-full rounded-full bg-black dark:bg-white\"\n          />\n        </motion.div>\n\n        {/* Thumb + Velocity-Reactive Floating Pill */}\n        <motion.div\n          style={{\n            left: shouldReduceMotion ? `${normalizedPct}%` : fillWidth,\n          }}\n          className=\"pointer-events-none absolute top-1/2 -translate-x-1/2 -translate-y-1/2\"\n        >\n          {/* Floating Velocity Pill */}\n          <motion.div\n            initial={false}\n            animate={{\n              opacity: showBubble ? 1 : 0,\n              y: showBubble ? -30 : -18,\n              scale: showBubble ? 1 : 0.85,\n            }}\n            style={{\n              rotate: shouldReduceMotion ? 0 : tooltipRotate,\n            }}\n            transition={{ type: \"spring\", stiffness: 380, damping: 22 }}\n            aria-hidden=\"true\"\n            className=\"absolute left-1/2 -translate-x-1/2 whitespace-nowrap rounded-md bg-black px-2 py-0.5 font-mono text-[10px] font-semibold tabular-nums text-white shadow-sm dark:bg-white dark:text-black\"\n          >\n            {currentValue}\n            {unit}\n          </motion.div>\n\n          {/* Tactile Thumb */}\n          <motion.div\n            animate={{\n              scaleX: isDragging && !shouldReduceMotion ? 1.18 : 1,\n              scaleY: isDragging && !shouldReduceMotion ? 0.9 : 1,\n              scale: isHovered || isFocused ? 1.08 : 1,\n            }}\n            transition={{ type: \"spring\", stiffness: 400, damping: 22 }}\n            className=\"h-5 w-5 rounded-full border-2 border-black bg-white shadow-sm dark:border-white dark:bg-[#0A0A0A]\"\n          />\n        </motion.div>\n      </div>\n\n      <div className=\"mt-2 flex justify-between font-mono text-[10px] text-neutral-400\">\n        <span>\n          {min}\n          {unit}\n        </span>\n        <span>\n          {max}\n          {unit}\n        </span>\n      </div>\n    </motion.div>\n  );\n}\n\nexport default KineticSlider;\n",
          "type": "registry:ui",
          "target": "components/ui/kinetic-slider.tsx"
        },
        {
          "path": "lib/utils.ts",
          "content": "import { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...inputs: ClassValue[]) {\n  return twMerge(clsx(inputs));\n}\n\nexport async function copyToClipboard(text: string): Promise<boolean> {\n  if (typeof window === \"undefined\") return false;\n\n  try {\n    if (navigator.clipboard && window.isSecureContext) {\n      await navigator.clipboard.writeText(text);\n      return true;\n    }\n\n    const textArea = document.createElement(\"textarea\");\n    textArea.value = text;\n    textArea.style.position = \"fixed\";\n    textArea.style.left = \"-999999px\";\n    textArea.style.top = \"-999999px\";\n    document.body.appendChild(textArea);\n    textArea.focus();\n    textArea.select();\n    const succeeded = document.execCommand(\"copy\");\n    textArea.remove();\n    return succeeded;\n  } catch {\n    return false;\n  }\n}\n",
          "type": "registry:lib",
          "target": "lib/utils.ts"
        }
      ]
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "kinetic-step-indicator",
      "type": "registry:ui",
      "title": "Kinetic Step Indicator",
      "author": "Rishabh Bose <https://theb0se.vercel.app/>",
      "description": "Multi-step workflow progress bar with spring-filled liquid connector tubes, elastic checkmark badges, and direct step jumping.",
      "dependencies": [
        "framer-motion",
        "lucide-react",
        "clsx",
        "tailwind-merge"
      ],
      "files": [
        {
          "path": "components/ui/kinetic-step-indicator.tsx",
          "content": "\"use client\";\n\nimport React, { useState } from \"react\";\nimport { motion, useReducedMotion } from \"framer-motion\";\nimport { Check } from \"lucide-react\";\nimport { cn } from \"@/lib/utils\";\n\nexport interface StepSpec {\n  id: string;\n  label: string;\n  caption: string;\n}\n\nexport interface KineticStepIndicatorProps {\n  /** Array of workflow steps. */\n  steps?: StepSpec[];\n  /** Initial active 0-based step index. Default: 1 */\n  defaultStep?: number;\n  /** Spring stiffness coefficient for connector liquid fill. Default: 320 */\n  stiffness?: number;\n  /** Spring damping coefficient for connector liquid fill. Default: 25 */\n  damping?: number;\n  className?: string;\n}\n\nconst DEFAULT_STEPS: StepSpec[] = [\n  { id: \"scaffold\", label: \"Scaffold\", caption: \"Two-file .tsx + .meta.ts\" },\n  { id: \"physics\", label: \"Spring Solver\", caption: \"Hooke's Law tuning\" },\n  { id: \"registry\", label: \"Sync CLI\", caption: \"Shadcn v2 JSON\" },\n  { id: \"ship\", label: \"Verify\", caption: \"100/100 SEO audit\" },\n];\n\nexport function KineticStepIndicator({\n  steps = DEFAULT_STEPS,\n  defaultStep = 1,\n  stiffness = 320,\n  damping = 25,\n  className,\n}: KineticStepIndicatorProps) {\n  const shouldReduceMotion = useReducedMotion() ?? false;\n  const [currentStep, setCurrentStep] = useState<number>(defaultStep);\n\n  return (\n    <div\n      role=\"group\"\n      aria-label=\"Workflow progress steps\"\n      className={cn(\n        \"w-full max-w-md rounded-2xl border border-neutral-200 bg-white p-5 dark:border-[#222222] dark:bg-[#0A0A0A]\",\n        className\n      )}\n    >\n      {/* Nodes & Liquid Connector Tubes */}\n      <div className=\"flex items-center justify-between\">\n        {steps.map((step, idx) => {\n          const isCompleted = idx < currentStep;\n          const isCurrent = idx === currentStep;\n\n          return (\n            <React.Fragment key={step.id}>\n              <motion.button\n                type=\"button\"\n                aria-current={isCurrent ? \"step\" : undefined}\n                aria-label={`Step ${idx + 1}: ${step.label} — ${step.caption}`}\n                onClick={() => setCurrentStep(idx)}\n                animate={{\n                  scale: isCurrent && !shouldReduceMotion ? 1.12 : 1,\n                }}\n                transition={{ type: \"spring\", stiffness, damping }}\n                className={cn(\n                  \"relative z-10 flex h-9 w-9 shrink-0 items-center justify-center rounded-full border font-mono text-xs font-bold transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-black dark:focus-visible:ring-white\",\n                  isCompleted || isCurrent\n                    ? \"border-black bg-black text-white dark:border-white dark:bg-white dark:text-black\"\n                    : \"border-neutral-200 bg-neutral-50 text-neutral-400 hover:border-neutral-400 dark:border-[#262626] dark:bg-[#141414]\"\n                )}\n              >\n                {isCompleted ? <Check className=\"h-4 w-4\" /> : idx + 1}\n              </motion.button>\n\n              {idx < steps.length - 1 && (\n                <div className=\"relative mx-2 h-1 flex-1 overflow-hidden rounded-full bg-neutral-200 dark:bg-[#1F1F1F]\">\n                  <motion.div\n                    initial={false}\n                    animate={{\n                      scaleX: idx < currentStep ? 1 : 0,\n                    }}\n                    transition={\n                      shouldReduceMotion\n                        ? { duration: 0 }\n                        : { type: \"spring\", stiffness, damping }\n                    }\n                    className=\"h-full w-full origin-left bg-black dark:bg-white\"\n                  />\n                </div>\n              )}\n            </React.Fragment>\n          );\n        })}\n      </div>\n\n      {/* Active Step Telemetry Readout */}\n      <div className=\"mt-4 flex items-center justify-between border-t border-neutral-100 pt-3 text-xs dark:border-[#1B1B1B]\">\n        <div>\n          <span className=\"font-semibold text-black dark:text-white\">\n            {steps[currentStep]?.label}\n          </span>\n          <span className=\"ml-2 text-neutral-500 dark:text-neutral-400\">\n            {steps[currentStep]?.caption}\n          </span>\n        </div>\n\n        <div className=\"flex items-center gap-1.5\">\n          <button\n            type=\"button\"\n            disabled={currentStep === 0}\n            onClick={() => setCurrentStep((s) => Math.max(0, s - 1))}\n            className=\"rounded-lg border border-neutral-200 px-2 py-1 text-[11px] font-semibold text-black disabled:opacity-30 dark:border-[#262626] dark:text-white\"\n          >\n            Prev\n          </button>\n          <button\n            type=\"button\"\n            disabled={currentStep === steps.length - 1}\n            onClick={() =>\n              setCurrentStep((s) => Math.min(steps.length - 1, s + 1))\n            }\n            className=\"rounded-lg bg-black px-2.5 py-1 text-[11px] font-semibold text-white disabled:opacity-30 dark:bg-white dark:text-black\"\n          >\n            Next\n          </button>\n        </div>\n      </div>\n    </div>\n  );\n}\n\nexport default KineticStepIndicator;\n",
          "type": "registry:ui",
          "target": "components/ui/kinetic-step-indicator.tsx"
        },
        {
          "path": "lib/utils.ts",
          "content": "import { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...inputs: ClassValue[]) {\n  return twMerge(clsx(inputs));\n}\n\nexport async function copyToClipboard(text: string): Promise<boolean> {\n  if (typeof window === \"undefined\") return false;\n\n  try {\n    if (navigator.clipboard && window.isSecureContext) {\n      await navigator.clipboard.writeText(text);\n      return true;\n    }\n\n    const textArea = document.createElement(\"textarea\");\n    textArea.value = text;\n    textArea.style.position = \"fixed\";\n    textArea.style.left = \"-999999px\";\n    textArea.style.top = \"-999999px\";\n    document.body.appendChild(textArea);\n    textArea.focus();\n    textArea.select();\n    const succeeded = document.execCommand(\"copy\");\n    textArea.remove();\n    return succeeded;\n  } catch {\n    return false;\n  }\n}\n",
          "type": "registry:lib",
          "target": "lib/utils.ts"
        }
      ]
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "kinetic-swipe-button",
      "type": "registry:ui",
      "title": "Kinetic Swipe Button",
      "author": "Rishabh Bose <https://theb0se.vercel.app/>",
      "description": "Slide-to-execute actuator switch with a spring-tethered thumb that locks upon crossing the completion threshold or recoils elastically.",
      "dependencies": [
        "framer-motion",
        "lucide-react",
        "clsx",
        "tailwind-merge"
      ],
      "files": [
        {
          "path": "components/ui/kinetic-swipe-button.tsx",
          "content": "\"use client\";\n\nimport React, { useRef, useState } from \"react\";\nimport {\n  motion,\n  useMotionValue,\n  useSpring,\n  useTransform,\n  useReducedMotion,\n} from \"framer-motion\";\nimport { ArrowRight, Check, RotateCcw } from \"lucide-react\";\nimport { cn } from \"@/lib/utils\";\n\nexport interface KineticSwipeButtonProps {\n  /** Track instruction text before completion. Default: \"Slide to Deploy Production\" */\n  label?: string;\n  /** Text displayed when locked at the right end. Default: \"Deployment Triggered\" */\n  completedLabel?: string;\n  /** Completion threshold ratio (0.5 to 0.95). Default: 0.78 */\n  threshold?: number;\n  /** Spring stiffness coefficient for thumb snap-back. Default: 360 */\n  stiffness?: number;\n  /** Spring damping coefficient for thumb snap-back. Default: 26 */\n  damping?: number;\n  /** Callback fired when swipe crosses completion threshold */\n  onComplete?: () => void;\n  className?: string;\n}\n\nexport function KineticSwipeButton({\n  label = \"Slide to Deploy Production\",\n  completedLabel = \"Deployment Triggered\",\n  threshold = 0.78,\n  stiffness = 360,\n  damping = 26,\n  onComplete,\n  className,\n}: KineticSwipeButtonProps) {\n  const shouldReduceMotion = useReducedMotion() ?? false;\n  const trackRef = useRef<HTMLDivElement | null>(null);\n  const [isDragging, setIsDragging] = useState(false);\n  const [isCompleted, setIsCompleted] = useState(false);\n  const startXRef = useRef<number>(0);\n\n  const dragX = useMotionValue(0);\n  const springX = useSpring(dragX, { stiffness, damping, mass: 0.4 });\n  const textOpacity = useTransform(springX, [0, 140], [1, 0]);\n\n  const getMaxTravel = () => {\n    const track = trackRef.current;\n    if (!track) return 220;\n    return Math.max(0, track.clientWidth - 52);\n  };\n\n  const handlePointerDown = (e: React.PointerEvent<HTMLButtonElement>) => {\n    if (isCompleted) return;\n    e.currentTarget.setPointerCapture(e.pointerId);\n    setIsDragging(true);\n    startXRef.current = e.clientX - dragX.get();\n  };\n\n  const handlePointerMove = (e: React.PointerEvent<HTMLButtonElement>) => {\n    if (!isDragging || isCompleted) return;\n    const maxTravel = getMaxTravel();\n    const nextX = Math.max(0, Math.min(maxTravel, e.clientX - startXRef.current));\n    dragX.set(nextX);\n  };\n\n  const handlePointerUp = (e: React.PointerEvent<HTMLButtonElement>) => {\n    if (!isDragging) return;\n    if (e.currentTarget.hasPointerCapture(e.pointerId)) {\n      e.currentTarget.releasePointerCapture(e.pointerId);\n    }\n    setIsDragging(false);\n\n    const maxTravel = getMaxTravel();\n    if (dragX.get() >= maxTravel * threshold) {\n      dragX.set(maxTravel);\n      setIsCompleted(true);\n      onComplete?.();\n    } else {\n      dragX.set(0);\n    }\n  };\n\n  const resetSwipe = () => {\n    setIsCompleted(false);\n    dragX.set(0);\n  };\n\n  return (\n    <div\n      ref={trackRef}\n      className={cn(\n        \"relative flex h-14 w-full max-w-xs select-none items-center overflow-hidden rounded-2xl border border-neutral-200 bg-neutral-100 p-1.5 dark:border-[#222222] dark:bg-[#0D0D0D]\",\n        className\n      )}\n    >\n      {/* Center Track Label */}\n      {!isCompleted ? (\n        <motion.span\n          style={{ opacity: shouldReduceMotion ? 1 : textOpacity }}\n          className=\"pointer-events-none mx-auto pl-8 text-xs font-semibold tracking-tight text-neutral-500 dark:text-neutral-400\"\n        >\n          {label}\n        </motion.span>\n      ) : (\n        <button\n          type=\"button\"\n          onClick={resetSwipe}\n          className=\"mx-auto inline-flex items-center gap-1.5 text-xs font-semibold text-black dark:text-white\"\n        >\n          <Check className=\"h-4 w-4\" />\n          <span>{completedLabel}</span>\n          <RotateCcw className=\"ml-1 h-3 w-3 text-neutral-400\" />\n        </button>\n      )}\n\n      {/* Draggable Magnetic Actuator Thumb */}\n      {!isCompleted && (\n        <motion.button\n          type=\"button\"\n          aria-label={label}\n          onPointerDown={handlePointerDown}\n          onPointerMove={handlePointerMove}\n          onPointerUp={handlePointerUp}\n          onPointerCancel={handlePointerUp}\n          onKeyDown={(e) => {\n            if (e.key === \"Enter\" || e.key === \" \") {\n              e.preventDefault();\n              dragX.set(getMaxTravel());\n              setIsCompleted(true);\n              onComplete?.();\n            }\n          }}\n          style={{ x: shouldReduceMotion ? 0 : springX }}\n          className=\"absolute left-1.5 flex h-11 w-11 cursor-grab touch-none items-center justify-center rounded-xl bg-black text-white shadow-sm active:cursor-grabbing focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-black dark:bg-white dark:text-black dark:focus-visible:ring-white\"\n        >\n          <ArrowRight className=\"h-4 w-4\" />\n        </motion.button>\n      )}\n    </div>\n  );\n}\n\nexport default KineticSwipeButton;\n",
          "type": "registry:ui",
          "target": "components/ui/kinetic-swipe-button.tsx"
        },
        {
          "path": "lib/utils.ts",
          "content": "import { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...inputs: ClassValue[]) {\n  return twMerge(clsx(inputs));\n}\n\nexport async function copyToClipboard(text: string): Promise<boolean> {\n  if (typeof window === \"undefined\") return false;\n\n  try {\n    if (navigator.clipboard && window.isSecureContext) {\n      await navigator.clipboard.writeText(text);\n      return true;\n    }\n\n    const textArea = document.createElement(\"textarea\");\n    textArea.value = text;\n    textArea.style.position = \"fixed\";\n    textArea.style.left = \"-999999px\";\n    textArea.style.top = \"-999999px\";\n    document.body.appendChild(textArea);\n    textArea.focus();\n    textArea.select();\n    const succeeded = document.execCommand(\"copy\");\n    textArea.remove();\n    return succeeded;\n  } catch {\n    return false;\n  }\n}\n",
          "type": "registry:lib",
          "target": "lib/utils.ts"
        }
      ]
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "lava-lamp",
      "type": "registry:ui",
      "title": "Lava Lamp",
      "author": "Rishabh Bose <https://theb0se.vercel.app/>",
      "description": "True WebGL signed distance field (SDF) metaball lava lamp shader using polynomial smooth-minimum (smin) surface tension blending, 3D specular/Fresnel subsurface rim lighting, and pointer thermal attraction.",
      "dependencies": [
        "lucide-react",
        "clsx",
        "tailwind-merge"
      ],
      "files": [
        {
          "path": "components/ui/lava-lamp.tsx",
          "content": "\"use client\";\n\nimport React, { useEffect, useRef, useState } from \"react\";\nimport { Flame, Sparkles, Droplet } from \"lucide-react\";\nimport { cn } from \"@/lib/utils\";\n\nexport interface LavaLampProps {\n  /** Number of buoyant metaball wax blobs (3 to 12). Default: 7 */\n  blobCount?: number;\n  /** Core molten wax hex color. Default: \"#FF3B00\" */\n  primaryColor?: string;\n  /** Subsurface rim/highlight wax hex color. Default: \"#FFB800\" */\n  secondaryColor?: string;\n  /** Deep vessel background hex color. Default: \"#0F071E\" */\n  backgroundColor?: string;\n  /** Thermal buoyancy cycle speed multiplier. Default: 1.0 */\n  speed?: number;\n  /** Polynomial smooth-minimum (smin) surface tension blending factor (0.15 to 0.85). Default: 0.45 */\n  viscosity?: number;\n  /** Optional foreground content */\n  children?: React.ReactNode;\n  className?: string;\n}\n\nfunction hexToRgbNorm(hex: string): [number, number, number] {\n  const clean = hex.replace(\"#\", \"\").trim();\n  if (clean.length === 3) {\n    return [\n      (parseInt(clean[0] + clean[0], 16) || 255) / 255,\n      (parseInt(clean[1] + clean[1], 16) || 59) / 255,\n      (parseInt(clean[2] + clean[2], 16) || 0) / 255,\n    ];\n  }\n  const num = parseInt(clean, 16);\n  if (Number.isNaN(num)) return [1.0, 0.23, 0.0];\n  return [\n    ((num >> 16) & 255) / 255,\n    ((num >> 8) & 255) / 255,\n    (num & 255) / 255,\n  ];\n}\n\nconst VERTEX_SHADER = `\n  attribute vec2 a_position;\n  varying vec2 v_uv;\n  void main() {\n    v_uv = a_position * 0.5 + 0.5;\n    gl_Position = vec4(a_position, 0.0, 1.0);\n  }\n`;\n\nconst FRAGMENT_SHADER = `\n  precision highp float;\n  varying vec2 v_uv;\n  uniform vec2 u_resolution;\n  uniform float u_time;\n  uniform int u_blobCount;\n  uniform float u_viscosity;\n  uniform vec3 u_primaryColor;\n  uniform vec3 u_secondaryColor;\n  uniform vec3 u_bgColor;\n  uniform vec2 u_pointer;\n  // xy = position, z = radius, w = vertical stretch factor\n  uniform vec4 u_blobs[12];\n\n  // Polynomial smooth-minimum (Inigo Quilez smin) for liquid surface tension necking & merging\n  float smin(float a, float b, float k) {\n    float h = clamp(0.5 + 0.5 * (b - a) / max(0.0001, k), 0.0, 1.0);\n    return mix(b, a, h) - k * h * (1.0 - h);\n  }\n\n  float sceneSDF(vec2 p) {\n    float k = mix(0.07, 0.38, clamp(u_viscosity, 0.05, 0.95));\n    float d = 10.0;\n\n    for (int i = 0; i < 12; i++) {\n      if (i >= u_blobCount) break;\n      vec4 b = u_blobs[i];\n      // Thermal vertical stretching/tear-drop deformation during ascent/descent\n      vec2 delta = p - b.xy;\n      delta.y /= b.w;\n      float dist = (length(delta) - b.z) * min(1.0, b.w);\n      d = smin(d, dist, k);\n    }\n\n    // Bottom incandescent heating coil wax reservoir pool\n    float bottomMeniscus =\n      (p.y + 0.56) +\n      sin(p.x * 3.4 + u_time * 1.2) * 0.022 +\n      cos(p.x * 5.8 - u_time * 0.85) * 0.012;\n    d = smin(d, bottomMeniscus, k * 0.95);\n\n    // Top cooler wax meniscus cap\n    float topMeniscus = (0.58 - p.y) + sin(p.x * 3.1 - u_time * 0.9) * 0.016;\n    d = smin(d, topMeniscus, k * 0.55);\n\n    // Pointer thermal heat attractor blob\n    float ptrDist = length(p - u_pointer) - 0.105;\n    d = smin(d, ptrDist, k * 0.88);\n\n    return d;\n  }\n\n  void main() {\n    vec2 aspect = vec2(u_resolution.x / max(1.0, u_resolution.y), 1.0);\n    vec2 p = (v_uv - 0.5) * aspect;\n\n    float d = sceneSDF(p);\n\n    // Finite-difference 2D gradient to reconstruct smooth 3D hemisphere normal\n    float eps = 0.0028;\n    vec2 grad = vec2(\n      sceneSDF(p + vec2(eps, 0.0)) - sceneSDF(p - vec2(eps, 0.0)),\n      sceneSDF(p + vec2(0.0, eps)) - sceneSDF(p - vec2(0.0, eps))\n    ) / (2.0 * eps);\n\n    // 1. Liquid suspension fluid & incandescent bottom heating coil illumination\n    float bottomHeat = exp(-max(0.0, v_uv.y) * 2.6) * (0.85 + 0.15 * sin(u_time * 2.0));\n    float centerColumn = exp(-pow((v_uv.x - 0.5) * 1.8, 2.0));\n    vec3 col = u_bgColor;\n    col += u_primaryColor * bottomHeat * 0.34;\n    col += u_secondaryColor * pow(bottomHeat, 2.2) * centerColumn * 0.28;\n\n    // Volumetric outer glow radiating from molten wax into the surrounding liquid\n    float outerHalo = exp(-max(0.0, d) * 7.5);\n    float innerHalo = exp(-max(0.0, d) * 22.0);\n    col += u_primaryColor * outerHalo * 0.42;\n    col += u_secondaryColor * innerHalo * 0.28;\n\n    // 2. Inside the Molten Wax Metaballs: 3D Subsurface Scattering & Blinn-Phong Lighting\n    if (d < 0.0) {\n      // Optical thickness / core depth inside the wax blob\n      float coreDepth = clamp(-d * 5.2, 0.0, 1.0);\n      vec2 gClamped = clamp(grad * 0.62, -0.96, 0.96);\n      float nz = sqrt(max(0.04, 1.0 - dot(gClamped, gClamped)));\n      vec3 normal = normalize(vec3(-gClamped.x, -gClamped.y, nz));\n\n      // Dual light sources: top-left key light + incandescent bottom thermal up-light\n      vec3 keyLight = normalize(vec3(-0.38, 0.62, 0.68));\n      vec3 bottomUpLight = normalize(vec3(0.0, -0.88, 0.47));\n      vec3 viewDir = vec3(0.0, 0.0, 1.0);\n\n      float diffKey = max(0.0, dot(normal, keyLight));\n      float diffBottom = max(0.0, dot(normal, bottomUpLight)) * (1.2 - v_uv.y * 0.7);\n      float fresnel = pow(1.0 - max(0.0, normal.z), 2.6);\n\n      // Blinn-Phong glossy specular highlights\n      vec3 halfKey = normalize(keyLight + viewDir);\n      vec3 halfBot = normalize(bottomUpLight + viewDir);\n      float specKey = pow(max(0.0, dot(normal, halfKey)), 52.0);\n      float specBot = pow(max(0.0, dot(normal, halfBot)), 24.0) * (1.0 - v_uv.y);\n\n      // Internal thermal subsurface scattering:\n      // Cooler outer skin (primaryColor) -> incandescent hot core & bottom-lit wax (secondaryColor -> white-hot)\n      float thermalFactor = clamp(\n        coreDepth * 0.68 + (1.0 - v_uv.y) * 0.42 + diffBottom * 0.45,\n        0.0,\n        1.0\n      );\n      vec3 waxCol = mix(u_primaryColor * 0.88, u_secondaryColor * 1.12, thermalFactor);\n\n      // White-hot incandescent core inside thick wax regions near the heating coil\n      float hotCore = pow(coreDepth, 2.2) * (1.15 - v_uv.y * 0.65);\n      waxCol = mix(waxCol, vec3(1.0, 0.97, 0.86), clamp(hotCore * 0.58, 0.0, 0.75));\n\n      // Translucent subsurface rim scattering where light grazes the wax skin\n      waxCol = mix(waxCol, u_secondaryColor * 1.35, fresnel * 0.65);\n\n      // Add 3D diffuse + crisp glassy specular highlights\n      waxCol *= 0.82 + 0.25 * diffKey;\n      waxCol += vec3(1.0, 0.96, 0.9) * (specKey * 0.72 + specBot * 0.35);\n\n      // Smooth anti-aliased boundary transition\n      float edgeMask = smoothstep(0.0, -0.006, d);\n      col = mix(col, waxCol, edgeMask);\n    }\n\n    // 3. Cylindrical Glass Vessel Reflections & Edge Vignette\n    float xFromCenter = abs(v_uv.x - 0.5) * 2.0;\n    // Vertical glass highlight ribbons near left and right vessel curvature\n    float glassSpecLeft = exp(-pow((v_uv.x - 0.11) * 28.0, 2.0)) * 0.11;\n    float glassSpecRight = exp(-pow((v_uv.x - 0.89) * 34.0, 2.0)) * 0.08;\n    col += vec3(0.9, 0.95, 1.0) * (glassSpecLeft + glassSpecRight) * (0.4 + 0.6 * v_uv.y);\n\n    // Subtle cylindrical edge darkening\n    float cylinderVig = 1.0 - 0.35 * pow(xFromCenter, 2.6);\n    col *= cylinderVig;\n\n    gl_FragColor = vec4(clamp(col, 0.0, 1.0), 1.0);\n  }\n`;\n\nconst LAVA_PRESETS = [\n  {\n    name: \"Magma\",\n    primary: \"#FF3B00\",\n    secondary: \"#FFB800\",\n    bg: \"#0F071E\",\n    viscosity: 0.45,\n  },\n  {\n    name: \"Cyber Acid\",\n    primary: \"#10B981\",\n    secondary: \"#A3E635\",\n    bg: \"#041014\",\n    viscosity: 0.52,\n  },\n  {\n    name: \"Ultraviolet\",\n    primary: \"#EC4899\",\n    secondary: \"#38BDF8\",\n    bg: \"#090418\",\n    viscosity: 0.42,\n  },\n];\n\nexport function LavaLamp({\n  blobCount = 7,\n  primaryColor = \"#FF3B00\",\n  secondaryColor = \"#FFB800\",\n  backgroundColor = \"#0F071E\",\n  speed = 1.0,\n  viscosity = 0.45,\n  children,\n  className,\n}: LavaLampProps) {\n  const containerRef = useRef<HTMLDivElement>(null);\n  const canvasRef = useRef<HTMLCanvasElement>(null);\n  const pointerRef = useRef<{ x: number; y: number; tx: number; ty: number }>({\n    x: 0,\n    y: -0.25,\n    tx: 0,\n    ty: -0.25,\n  });\n\n  const [liveCount, setLiveCount] = useState(blobCount);\n  const [livePrimary, setLivePrimary] = useState(primaryColor);\n  const [liveSecondary, setLiveSecondary] = useState(secondaryColor);\n  const [liveBg, setLiveBg] = useState(backgroundColor);\n  const [liveSpeed, setLiveSpeed] = useState(speed);\n  const [liveViscosity, setLiveViscosity] = useState(viscosity);\n\n  useEffect(() => setLiveCount(blobCount), [blobCount]);\n  useEffect(() => setLivePrimary(primaryColor), [primaryColor]);\n  useEffect(() => setLiveSecondary(secondaryColor), [secondaryColor]);\n  useEffect(() => setLiveBg(backgroundColor), [backgroundColor]);\n  useEffect(() => setLiveSpeed(speed), [speed]);\n  useEffect(() => setLiveViscosity(viscosity), [viscosity]);\n\n  const paramsRef = useRef({\n    count: liveCount,\n    primary: livePrimary,\n    secondary: liveSecondary,\n    bg: liveBg,\n    speed: liveSpeed,\n    viscosity: liveViscosity,\n  });\n\n  useEffect(() => {\n    paramsRef.current = {\n      count: liveCount,\n      primary: livePrimary,\n      secondary: liveSecondary,\n      bg: liveBg,\n      speed: liveSpeed,\n      viscosity: liveViscosity,\n    };\n  }, [liveCount, livePrimary, liveSecondary, liveBg, liveSpeed, liveViscosity]);\n\n  useEffect(() => {\n    const container = containerRef.current;\n    const canvas = canvasRef.current;\n    if (!container || !canvas) return;\n\n    const gl = canvas.getContext(\"webgl\", {\n      alpha: false,\n      antialias: false,\n      powerPreference: \"high-performance\",\n    });\n    if (!gl) return;\n\n    const compile = (type: number, src: string) => {\n      const s = gl.createShader(type);\n      if (!s) return null;\n      gl.shaderSource(s, src);\n      gl.compileShader(s);\n      if (!gl.getShaderParameter(s, gl.COMPILE_STATUS)) {\n        gl.deleteShader(s);\n        return null;\n      }\n      return s;\n    };\n\n    const vs = compile(gl.VERTEX_SHADER, VERTEX_SHADER);\n    const fs = compile(gl.FRAGMENT_SHADER, FRAGMENT_SHADER);\n    if (!vs || !fs) return;\n\n    const program = gl.createProgram();\n    if (!program) return;\n    gl.attachShader(program, vs);\n    gl.attachShader(program, fs);\n    gl.linkProgram(program);\n    gl.useProgram(program);\n\n    const buf = gl.createBuffer();\n    gl.bindBuffer(gl.ARRAY_BUFFER, buf);\n    gl.bufferData(\n      gl.ARRAY_BUFFER,\n      new Float32Array([-1, -1, 1, -1, -1, 1, -1, 1, 1, -1, 1, 1]),\n      gl.STATIC_DRAW\n    );\n    const posLoc = gl.getAttribLocation(program, \"a_position\");\n    gl.enableVertexAttribArray(posLoc);\n    gl.vertexAttribPointer(posLoc, 2, gl.FLOAT, false, 0, 0);\n\n    const uResLoc = gl.getUniformLocation(program, \"u_resolution\");\n    const uTimeLoc = gl.getUniformLocation(program, \"u_time\");\n    const uCountLoc = gl.getUniformLocation(program, \"u_blobCount\");\n    const uViscLoc = gl.getUniformLocation(program, \"u_viscosity\");\n    const uPrimLoc = gl.getUniformLocation(program, \"u_primaryColor\");\n    const uSecLoc = gl.getUniformLocation(program, \"u_secondaryColor\");\n    const uBgLoc = gl.getUniformLocation(program, \"u_bgColor\");\n    const uPtrLoc = gl.getUniformLocation(program, \"u_pointer\");\n    const uBlobsLoc = gl.getUniformLocation(program, \"u_blobs\");\n\n    // Seed 12 thermal wax blob trajectories\n    const blobSeeds = Array.from({ length: 12 }, (_, i) => ({\n      phaseY: i * 1.15 + 0.4,\n      phaseX: i * 2.05 + 1.1,\n      freqY: 0.25 + (i % 4) * 0.08,\n      freqX: 0.19 + (i % 3) * 0.07,\n      baseRadius: 0.105 + (i % 4) * 0.025,\n      spreadX: 0.16 + (i % 5) * 0.08,\n    }));\n\n    const resize = () => {\n      const rect = container.getBoundingClientRect();\n      const dpr = Math.min(window.devicePixelRatio || 1, 1.75);\n      canvas.width = Math.max(1, Math.floor(rect.width * dpr));\n      canvas.height = Math.max(1, Math.floor(rect.height * dpr));\n      gl.viewport(0, 0, canvas.width, canvas.height);\n    };\n\n    resize();\n    const ro = new ResizeObserver(resize);\n    ro.observe(container);\n\n    let rafId = 0;\n    let time = 0;\n    const blobData = new Float32Array(48);\n\n    const render = () => {\n      const {\n        count: curCount,\n        primary: curPrimary,\n        secondary: curSecondary,\n        bg: curBg,\n        speed: curSpeed,\n        viscosity: curViscosity,\n      } = paramsRef.current;\n\n      time += 0.016 * curSpeed;\n      const aspect = canvas.width / Math.max(1, canvas.height);\n\n      // Smooth pointer thermal tracking\n      const ptr = pointerRef.current;\n      ptr.x += (ptr.tx - ptr.x) * 0.07;\n      ptr.y += (ptr.ty - ptr.y) * 0.07;\n\n      // Update thermal buoyancy wax blobs (dwell near bottom coil, stretch mid-column, cool & sink)\n      for (let i = 0; i < 12; i++) {\n        const s = blobSeeds[i];\n        const cycle = time * s.freqY + s.phaseY;\n        const sinC = Math.sin(cycle);\n        const cosC = Math.cos(cycle);\n        // Shaped thermal convection curve: lingers at bottom heater and top cooler\n        const rawY = sinC + 0.24 * Math.sin(cycle * 2.0);\n        const y = rawY * 0.39;\n        const x =\n          Math.sin(time * s.freqX + s.phaseX) *\n          s.spreadX *\n          Math.min(1.35, aspect * 0.72);\n        const r = s.baseRadius * (0.92 + 0.14 * Math.cos(cycle * 1.5 + i));\n\n        // Vertical stretch is strongest when rising/sinking rapidly through mid-vessel (|cosC| near 1),\n        // and flattens into an oblate drop at the top/bottom turnaround points\n        const verticalVelocity = Math.abs(cosC);\n        const stretch = 0.84 + verticalVelocity * 0.42;\n\n        blobData[i * 4] = x;\n        blobData[i * 4 + 1] = y;\n        blobData[i * 4 + 2] = r;\n        blobData[i * 4 + 3] = stretch;\n      }\n\n      const [pr, pg, pb] = hexToRgbNorm(curPrimary);\n      const [sr, sg, sb] = hexToRgbNorm(curSecondary);\n      const [br, bg, bb] = hexToRgbNorm(curBg);\n\n      gl.useProgram(program);\n      gl.uniform2f(uResLoc, canvas.width, canvas.height);\n      gl.uniform1f(uTimeLoc, time);\n      gl.uniform1i(uCountLoc, Math.max(3, Math.min(12, Math.round(curCount))));\n      gl.uniform1f(uViscLoc, curViscosity);\n      gl.uniform3f(uPrimLoc, pr, pg, pb);\n      gl.uniform3f(uSecLoc, sr, sg, sb);\n      gl.uniform3f(uBgLoc, br, bg, bb);\n      gl.uniform2f(uPtrLoc, ptr.x * aspect, ptr.y);\n      gl.uniform4fv(uBlobsLoc, blobData);\n\n      gl.drawArrays(gl.TRIANGLES, 0, 6);\n      rafId = requestAnimationFrame(render);\n    };\n\n    rafId = requestAnimationFrame(render);\n\n    return () => {\n      cancelAnimationFrame(rafId);\n      ro.disconnect();\n    };\n  }, []);\n\n  const handlePointerMove = (e: React.PointerEvent<HTMLDivElement>) => {\n    if (!containerRef.current) return;\n    const rect = containerRef.current.getBoundingClientRect();\n    const nx = (e.clientX - rect.left) / Math.max(1, rect.width) - 0.5;\n    const ny = 0.5 - (e.clientY - rect.top) / Math.max(1, rect.height);\n    pointerRef.current.tx = nx;\n    pointerRef.current.ty = ny;\n  };\n\n  return (\n    <div\n      ref={containerRef}\n      data-fullscreen-scroll\n      onPointerMove={handlePointerMove}\n      className={cn(\n        \"relative flex min-h-[520px] w-full flex-col justify-between overflow-hidden rounded-2xl border border-white/10 bg-[#0F071E] p-6 text-white shadow-2xl\",\n        className\n      )}\n    >\n      <canvas\n        ref={canvasRef}\n        aria-hidden=\"true\"\n        className=\"pointer-events-none absolute inset-0 h-full w-full\"\n      />\n\n      {children && (\n        <div className=\"relative z-10 flex min-h-[520px] w-full flex-col\">\n          {children}\n        </div>\n      )}\n    </div>\n  );\n}\n\nexport default LavaLamp;\n",
          "type": "registry:ui",
          "target": "components/ui/lava-lamp.tsx"
        },
        {
          "path": "lib/utils.ts",
          "content": "import { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...inputs: ClassValue[]) {\n  return twMerge(clsx(inputs));\n}\n\nexport async function copyToClipboard(text: string): Promise<boolean> {\n  if (typeof window === \"undefined\") return false;\n\n  try {\n    if (navigator.clipboard && window.isSecureContext) {\n      await navigator.clipboard.writeText(text);\n      return true;\n    }\n\n    const textArea = document.createElement(\"textarea\");\n    textArea.value = text;\n    textArea.style.position = \"fixed\";\n    textArea.style.left = \"-999999px\";\n    textArea.style.top = \"-999999px\";\n    document.body.appendChild(textArea);\n    textArea.focus();\n    textArea.select();\n    const succeeded = document.execCommand(\"copy\");\n    textArea.remove();\n    return succeeded;\n  } catch {\n    return false;\n  }\n}\n",
          "type": "registry:lib",
          "target": "lib/utils.ts"
        }
      ]
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "liquid-glass-card",
      "type": "registry:ui",
      "title": "Liquid Glass Card",
      "author": "Rishabh Bose <https://theb0se.vercel.app/>",
      "description": "Ultra-premium translucent frosted glass card featuring dynamic specular highlight cursor tracking, 3D perspective tilt, chromatic edge refraction, double-layer backdrop blur, and tactile click feedback.",
      "dependencies": [
        "framer-motion",
        "lucide-react",
        "clsx",
        "tailwind-merge"
      ],
      "files": [
        {
          "path": "components/ui/liquid-glass-card.tsx",
          "content": "\"use client\";\n\nimport React, { useState, useRef } from \"react\";\nimport { motion, useMotionValue, useSpring, useTransform } from \"framer-motion\";\nimport { Sparkles, CreditCard, Shield, Zap, Eye, Sliders } from \"lucide-react\";\nimport { cn } from \"@/lib/utils\";\n\nexport interface LiquidGlassCardProps {\n  /** Title inside glass card */\n  title?: string;\n  /** Subtitle or descriptor */\n  subtitle?: string;\n  /** Frost blur strength in px */\n  blurStrength?: number;\n  /** 3D Tilt sensitivity multiplier */\n  tiltFactor?: number;\n  /** Enable chromatic refraction bevel */\n  chromaticEdge?: boolean;\n  /** Optional custom card content */\n  children?: React.ReactNode;\n  /** Root container className */\n  className?: string;\n}\n\nexport function LiquidGlassCard({\n  title = \"Apple Card Titanium\",\n  subtitle = \"Mastercard • 7492 • World Elite\",\n  blurStrength = 24,\n  tiltFactor = 1.0,\n  chromaticEdge = true,\n  children,\n  className,\n}: LiquidGlassCardProps) {\n  const cardRef = useRef<HTMLDivElement>(null);\n  const [activePreset, setActivePreset] = useState<\"apple-card\" | \"spatial\" | \"audio\">(\"apple-card\");\n  const [currentTilt, setCurrentTilt] = useState(tiltFactor);\n  const [showChromatic, setShowChromatic] = useState(chromaticEdge);\n  const [frostedAlpha, setFrostedAlpha] = useState(0.25);\n  const [isPressed, setIsPressed] = useState(false);\n\n  // Mouse tilt tracking\n  const mouseX = useMotionValue(0.5);\n  const mouseY = useMotionValue(0.5);\n\n  const rotateXRaw = useTransform(mouseY, [0, 1], [15 * currentTilt, -15 * currentTilt]);\n  const rotateYRaw = useTransform(mouseX, [0, 1], [-18 * currentTilt, 18 * currentTilt]);\n\n  const rotateX = useSpring(rotateXRaw, { stiffness: 220, damping: 20 });\n  const rotateY = useSpring(rotateYRaw, { stiffness: 220, damping: 20 });\n\n  // Specular reflection position\n  const shineX = useTransform(mouseX, [0, 1], [\"0%\", \"100%\"]);\n  const shineY = useTransform(mouseY, [0, 1], [\"0%\", \"100%\"]);\n\n  const handleMouseMove = (e: React.MouseEvent<HTMLDivElement>) => {\n    if (!cardRef.current) return;\n    const rect = cardRef.current.getBoundingClientRect();\n    const x = (e.clientX - rect.left) / rect.width;\n    const y = (e.clientY - rect.top) / rect.height;\n    mouseX.set(x);\n    mouseY.set(y);\n  };\n\n  const handleMouseLeave = () => {\n    mouseX.set(0.5);\n    mouseY.set(0.5);\n  };\n\n  if (children) {\n    return (\n      <div className={cn(\"relative select-none\", className)} style={{ perspective: 1000 }}>\n        <motion.div\n          ref={cardRef}\n          onMouseMove={handleMouseMove}\n          onMouseLeave={handleMouseLeave}\n          onMouseDown={() => setIsPressed(true)}\n          onMouseUp={() => setIsPressed(false)}\n          style={{ rotateX, rotateY, transformStyle: \"preserve-3d\" }}\n          animate={{ scale: isPressed ? 0.98 : 1 }}\n          transition={{ scale: { type: \"spring\", stiffness: 450, damping: 25 } }}\n          className={cn(\n            \"group relative w-full cursor-grab active:cursor-grabbing rounded-3xl p-[1.5px] transition-shadow duration-300\",\n            showChromatic\n              ? \"bg-gradient-to-br from-cyan-400/50 via-white/40 to-pink-500/50 shadow-[0_20px_50px_rgba(0,0,0,0.6)]\"\n              : \"bg-white/20 shadow-[0_20px_45px_rgba(0,0,0,0.5)]\"\n          )}\n        >\n          <div\n            className=\"relative overflow-hidden rounded-[22px] border border-white/30 backdrop-blur-2xl transition-colors duration-300\"\n            style={{\n              backgroundColor: `rgba(255, 255, 255, ${frostedAlpha})`,\n              boxShadow: `\n                inset 0 1px 1px 0 rgba(255, 255, 255, 0.6),\n                inset 0 -1px 2px 0 rgba(0, 0, 0, 0.4)\n              `,\n            }}\n          >\n            <motion.div\n              className=\"pointer-events-none absolute -inset-full opacity-60 transition-opacity group-hover:opacity-100\"\n              style={{\n                background: `radial-gradient(circle 320px at ${shineX} ${shineY}, rgba(255, 255, 255, 0.6), transparent 70%)`,\n              }}\n            />\n            {showChromatic && (\n              <div\n                className=\"pointer-events-none absolute inset-0 opacity-25 mix-blend-overlay\"\n                style={{\n                  background:\n                    \"linear-gradient(135deg, rgba(56,189,248,0.5) 0%, rgba(236,72,153,0.5) 100%)\",\n                }}\n              />\n            )}\n            <div className=\"relative z-10 p-6 sm:p-8\">{children}</div>\n          </div>\n        </motion.div>\n      </div>\n    );\n  }\n\n  return (\n    <div\n      data-fullscreen-scroll\n      className={cn(\n        \"relative w-full min-h-[520px] overflow-hidden rounded-2xl border border-neutral-200/80 bg-[#060810] p-6 text-neutral-100 shadow-2xl transition-all dark:border-neutral-800\",\n        className\n      )}\n    >\n      {/* Dynamic atmospheric fluid background bubbles */}\n      <div className=\"pointer-events-none absolute inset-0 overflow-hidden\">\n        <div\n          className=\"absolute -top-24 -left-20 h-96 w-96 rounded-full blur-[90px] opacity-40 transition-transform duration-1000\"\n          style={{\n            background: \"radial-gradient(circle, #38BDF8 0%, #6366F1 60%, transparent 80%)\",\n          }}\n        />\n        <div\n          className=\"absolute -bottom-20 -right-16 h-96 w-96 rounded-full blur-[100px] opacity-35 transition-transform duration-1000\"\n          style={{\n            background: \"radial-gradient(circle, #EC4899 0%, #8B5CF6 60%, transparent 80%)\",\n          }}\n        />\n        <div\n          className=\"absolute top-1/2 left-1/3 h-64 w-64 -translate-y-1/2 rounded-full blur-[80px] opacity-25\"\n          style={{\n            background: \"radial-gradient(circle, #F59E0B 0%, #10B981 70%, transparent 80%)\",\n          }}\n        />\n      </div>\n\n      {/* Top Header & Preset Switches */}\n      <div className=\"relative z-10 flex flex-wrap items-center justify-between gap-4 border-b border-white/10 pb-4\">\n        <div>\n          <div className=\"inline-flex items-center gap-2 rounded-full border border-white/15 bg-white/10 px-3 py-1 text-xs font-medium text-white backdrop-blur-md\">\n            <Sparkles className=\"h-3 w-3 text-pink-400\" />\n            Liquid Glassmorphism Engine\n          </div>\n          <h2 className=\"mt-2 text-xl font-semibold tracking-tight text-white\">\n            Liquid Glass Specular Tilt Card\n          </h2>\n          <p className=\"text-xs text-neutral-400\">\n            Double-layer backdrop blur with dynamic cursor specular glare and chromatic edge refraction\n          </p>\n        </div>\n\n        {/* Card Template Presets */}\n        <div className=\"flex items-center gap-1.5 rounded-xl border border-white/10 bg-white/5 p-1 backdrop-blur-md\">\n          {([\"apple-card\", \"spatial\", \"audio\"] as const).map((preset) => (\n            <button\n              key={preset}\n              type=\"button\"\n              onClick={() => setActivePreset(preset)}\n              className={cn(\n                \"rounded-lg px-2.5 py-1 text-xs font-medium capitalize transition\",\n                activePreset === preset\n                  ? \"bg-white/20 text-white shadow-sm ring-1 ring-white/20\"\n                  : \"text-neutral-400 hover:text-white\"\n              )}\n            >\n              {preset.replace(\"-\", \" \")}\n            </button>\n          ))}\n        </div>\n      </div>\n\n      {/* Center 3D Interactive Perspective Viewport */}\n      <div\n        className=\"relative z-10 flex min-h-[350px] items-center justify-center py-8 select-none\"\n        style={{ perspective: 1000 }}\n      >\n        <motion.div\n          ref={cardRef}\n          onMouseMove={handleMouseMove}\n          onMouseLeave={handleMouseLeave}\n          onMouseDown={() => setIsPressed(true)}\n          onMouseUp={() => setIsPressed(false)}\n          style={{\n            rotateX,\n            rotateY,\n            transformStyle: \"preserve-3d\",\n          }}\n          animate={{\n            scale: isPressed ? 0.96 : 1,\n          }}\n          transition={{\n            scale: { type: \"spring\", stiffness: 450, damping: 25 },\n          }}\n          className={cn(\n            \"group relative w-full max-w-md cursor-grab active:cursor-grabbing rounded-3xl p-[1.5px] transition-shadow duration-300\",\n            showChromatic\n              ? \"bg-gradient-to-br from-cyan-400/50 via-white/40 to-pink-500/50 shadow-[0_20px_50px_rgba(0,0,0,0.6)]\"\n              : \"bg-white/20 shadow-[0_20px_45px_rgba(0,0,0,0.5)]\"\n          )}\n        >\n          {/* Double-layer Backdrop Blur Chassis */}\n          <div\n            className=\"relative overflow-hidden rounded-[22px] border border-white/30 backdrop-blur-2xl transition-colors duration-300\"\n            style={{\n              backgroundColor: `rgba(255, 255, 255, ${frostedAlpha})`,\n              boxShadow: `\n                inset 0 1px 1px 0 rgba(255, 255, 255, 0.6),\n                inset 0 -1px 2px 0 rgba(0, 0, 0, 0.4)\n              `,\n            }}\n          >\n            {/* Dynamic Specular Spotlight Highlight Tracking Cursor */}\n            <motion.div\n              className=\"pointer-events-none absolute -inset-full opacity-60 transition-opacity group-hover:opacity-100\"\n              style={{\n                background: `radial-gradient(circle 320px at ${shineX} ${shineY}, rgba(255, 255, 255, 0.6), transparent 70%)`,\n              }}\n            />\n\n            {/* Micro Chromatic Refraction Sheen Overlay */}\n            {showChromatic && (\n              <div\n                className=\"pointer-events-none absolute inset-0 opacity-25 mix-blend-overlay\"\n                style={{\n                  background:\n                    \"linear-gradient(135deg, rgba(56,189,248,0.5) 0%, rgba(236,72,153,0.5) 100%)\",\n                }}\n              />\n            )}\n\n            {/* Card Content Based on Preset */}\n            <div className=\"relative z-10 p-7\">\n              {children || (\n                <>\n                  {activePreset === \"apple-card\" && (\n                    <div className=\"space-y-12\">\n                      <div className=\"flex items-center justify-between\">\n                        <div className=\"flex items-center gap-2\">\n                          <CreditCard className=\"h-6 w-6 text-white drop-shadow\" />\n                          <span className=\"font-semibold tracking-wide text-white drop-shadow-sm\">\n                            Apple Card\n                          </span>\n                        </div>\n                        <span className=\"rounded-full bg-white/20 px-2.5 py-0.5 text-[10px] font-semibold text-white backdrop-blur-md\">\n                          Titanium Edition\n                        </span>\n                      </div>\n\n                      <div className=\"space-y-4\">\n                        <div className=\"h-9 w-12 rounded-lg border border-amber-300/40 bg-gradient-to-tr from-amber-400 to-amber-200/90 shadow-sm\" />\n                        <div>\n                          <div className=\"font-mono text-sm tracking-widest text-white/90 drop-shadow\">\n                            •••• •••• •••• 7492\n                          </div>\n                          <div className=\"mt-2 flex items-center justify-between text-xs text-white/80\">\n                            <span className=\"font-medium uppercase tracking-wider\">\n                              Alexander Wright\n                            </span>\n                            <span className=\"font-mono\">10/29</span>\n                          </div>\n                        </div>\n                      </div>\n                    </div>\n                  )}\n\n                  {activePreset === \"spatial\" && (\n                    <div className=\"space-y-6\">\n                      <div className=\"flex items-center justify-between\">\n                        <div className=\"flex items-center gap-2\">\n                          <Eye className=\"h-5 w-5 text-sky-300\" />\n                          <span className=\"font-semibold text-white\">Spatial Widget</span>\n                        </div>\n                        <span className=\"text-xs font-mono text-sky-200\">visionOS 2.0</span>\n                      </div>\n\n                      <div className=\"rounded-xl border border-white/20 bg-white/10 p-4 backdrop-blur-md\">\n                        <div className=\"text-xs font-medium text-white/90\">\n                          Immersive Environment\n                        </div>\n                        <div className=\"mt-1 text-[11px] text-white/70\">\n                          Haleakalā Crater • 100% Reality Blend\n                        </div>\n                        <div className=\"mt-3 flex items-center gap-2\">\n                          <div className=\"h-2 flex-1 rounded-full bg-white/20\">\n                            <div className=\"h-full w-3/4 rounded-full bg-sky-400\" />\n                          </div>\n                          <span className=\"text-[10px] font-mono text-white/80\">75%</span>\n                        </div>\n                      </div>\n\n                      <div className=\"flex items-center justify-between text-xs text-white/80\">\n                        <span>Audio Raytracing: Spatial</span>\n                        <Zap className=\"h-4 w-4 text-amber-300\" />\n                      </div>\n                    </div>\n                  )}\n\n                  {activePreset === \"audio\" && (\n                    <div className=\"space-y-6\">\n                      <div className=\"flex items-center justify-between\">\n                        <span className=\"text-xs font-semibold uppercase tracking-wider text-white/70\">\n                          AirPods Max\n                        </span>\n                        <span className=\"h-2 w-2 rounded-full bg-emerald-400 shadow-[0_0_6px_#34D399]\" />\n                      </div>\n\n                      <div className=\"text-center py-2\">\n                        <h4 className=\"text-lg font-bold text-white drop-shadow\">\n                          Symphony No. 9 in D Minor\n                        </h4>\n                        <p className=\"text-xs text-white/75 mt-0.5\">\n                          High-Res Lossless • Spatial Audio\n                        </p>\n                      </div>\n\n                      <div className=\"flex items-center justify-center gap-6 pt-2\">\n                        <button type=\"button\" className=\"text-white/80 hover:text-white transition\">\n                          ⏮\n                        </button>\n                        <button\n                          type=\"button\"\n                          className=\"flex h-11 w-11 items-center justify-center rounded-full bg-white/30 text-white shadow-lg backdrop-blur-md transition hover:scale-105\"\n                        >\n                          ⏸\n                        </button>\n                        <button type=\"button\" className=\"text-white/80 hover:text-white transition\">\n                          ⏭\n                        </button>\n                      </div>\n                    </div>\n                  )}\n                </>\n              )}\n            </div>\n          </div>\n        </motion.div>\n      </div>\n\n      {/* Interactive Controls Drawer */}\n      <div className=\"relative z-10 mt-4 grid grid-cols-1 gap-4 rounded-xl border border-white/10 bg-black/40 p-4 backdrop-blur-md sm:grid-cols-3\">\n        {/* Tilt Factor Slider */}\n        <div className=\"space-y-1.5\">\n          <div className=\"flex items-center justify-between text-xs\">\n            <span className=\"text-neutral-300 font-medium\">3D Tilt Sensitivity</span>\n            <span className=\"font-mono text-neutral-400\">{currentTilt.toFixed(1)}x</span>\n          </div>\n          <input\n            type=\"range\"\n            min={0.2}\n            max={2.0}\n            step={0.1}\n            value={currentTilt}\n            onChange={(e) => setCurrentTilt(parseFloat(e.target.value))}\n            className=\"h-1.5 w-full cursor-pointer appearance-none rounded-lg bg-neutral-700 accent-blue-500\"\n          />\n        </div>\n\n        {/* Frosted Opacity Slider */}\n        <div className=\"space-y-1.5\">\n          <div className=\"flex items-center justify-between text-xs\">\n            <span className=\"text-neutral-300 font-medium\">Glass Frosted Tint</span>\n            <span className=\"font-mono text-neutral-400\">{Math.round(frostedAlpha * 100)}%</span>\n          </div>\n          <input\n            type=\"range\"\n            min={0.1}\n            max={0.5}\n            step={0.05}\n            value={frostedAlpha}\n            onChange={(e) => setFrostedAlpha(parseFloat(e.target.value))}\n            className=\"h-1.5 w-full cursor-pointer appearance-none rounded-lg bg-neutral-700 accent-blue-500\"\n          />\n        </div>\n\n        {/* Chromatic Edge Refraction Toggle */}\n        <div className=\"flex items-center justify-between sm:justify-end gap-3 pt-2 sm:pt-0\">\n          <label className=\"flex items-center gap-2 cursor-pointer text-xs text-neutral-300\">\n            <input\n              type=\"checkbox\"\n              checked={showChromatic}\n              onChange={(e) => setShowChromatic(e.target.checked)}\n              className=\"rounded border-neutral-700 bg-neutral-800 text-pink-500 focus:ring-0\"\n            />\n            <span>Chromatic Edge Refraction</span>\n          </label>\n        </div>\n      </div>\n    </div>\n  );\n}\n\nexport default LiquidGlassCard;\n",
          "type": "registry:ui",
          "target": "components/ui/liquid-glass-card.tsx"
        },
        {
          "path": "lib/utils.ts",
          "content": "import { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...inputs: ClassValue[]) {\n  return twMerge(clsx(inputs));\n}\n\nexport async function copyToClipboard(text: string): Promise<boolean> {\n  if (typeof window === \"undefined\") return false;\n\n  try {\n    if (navigator.clipboard && window.isSecureContext) {\n      await navigator.clipboard.writeText(text);\n      return true;\n    }\n\n    const textArea = document.createElement(\"textarea\");\n    textArea.value = text;\n    textArea.style.position = \"fixed\";\n    textArea.style.left = \"-999999px\";\n    textArea.style.top = \"-999999px\";\n    document.body.appendChild(textArea);\n    textArea.focus();\n    textArea.select();\n    const succeeded = document.execCommand(\"copy\");\n    textArea.remove();\n    return succeeded;\n  } catch {\n    return false;\n  }\n}\n",
          "type": "registry:lib",
          "target": "lib/utils.ts"
        }
      ]
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "liquid-gradient-blob",
      "type": "registry:ui",
      "title": "Liquid Gradient Blob",
      "author": "Rishabh Bose <https://theb0se.vercel.app/>",
      "description": "Organic metaball background powered by an SVG `feGaussianBlur` + `feColorMatrix` alpha-threshold gooey filter where orbiting and cursor-tracked blobs fuse seamlessly.",
      "dependencies": [
        "framer-motion",
        "lucide-react",
        "clsx",
        "tailwind-merge"
      ],
      "files": [
        {
          "path": "components/ui/liquid-gradient-blob.tsx",
          "content": "\"use client\";\n\nimport React, { useId, useState } from \"react\";\nimport { motion } from \"framer-motion\";\nimport { Droplets } from \"lucide-react\";\nimport { cn } from \"@/lib/utils\";\n\nexport interface LiquidGradientBlobProps {\n  /** Array of blob fill colors. Default: [\"#8B5CF6\", \"#EC4899\", \"#06B6D4\", \"#3B82F6\"] */\n  colors?: string[];\n  /** Animation speed multiplier (1 = default). Default: 1 */\n  speed?: number;\n  /** SVG feGaussianBlur standard deviation for the gooey merge effect. Default: 22 */\n  gooeyIntensity?: number;\n  /** Optional foreground content */\n  children?: React.ReactNode;\n  className?: string;\n}\n\nconst DEFAULT_BLOB_COLORS = [\"#8B5CF6\", \"#EC4899\", \"#06B6D4\", \"#3B82F6\"];\n\nexport function LiquidGradientBlob({\n  colors = DEFAULT_BLOB_COLORS,\n  speed = 1,\n  gooeyIntensity = 22,\n  children,\n  className,\n}: LiquidGradientBlobProps) {\n  const filterId = useId().replace(/:/g, \"\");\n  const [pointer, setPointer] = useState({ x: 50, y: 50 });\n\n  const dur = Math.max(4, 12 / Math.max(0.2, speed));\n  const c = colors.length >= 3 ? colors : DEFAULT_BLOB_COLORS;\n\n  return (\n    <div\n      data-fullscreen-scroll\n      onMouseMove={(e) => {\n        const rect = e.currentTarget.getBoundingClientRect();\n        setPointer({\n          x: ((e.clientX - rect.left) / rect.width) * 100,\n          y: ((e.clientY - rect.top) / rect.height) * 100,\n        });\n      }}\n      className={cn(\n        \"relative flex min-h-[360px] w-full flex-col justify-between overflow-hidden rounded-3xl border border-neutral-800 bg-[#06060E] p-6 text-white shadow-sm\",\n        className\n      )}\n    >\n      {/* Hidden SVG Filter Definition: feGaussianBlur + feColorMatrix Gooey Threshold */}\n      <svg aria-hidden=\"true\" className=\"pointer-events-none absolute h-0 w-0\">\n        <defs>\n          <filter id={`gooey-${filterId}`}>\n            <feGaussianBlur\n              in=\"SourceGraphic\"\n              stdDeviation={gooeyIntensity}\n              result=\"blur\"\n            />\n            <feColorMatrix\n              in=\"blur\"\n              mode=\"matrix\"\n              values=\"1 0 0 0 0  0 1 0 0 0  0 0 1 0 0  0 0 0 24 -10\"\n              result=\"goo\"\n            />\n            <feBlend in=\"SourceGraphic\" in2=\"goo\" />\n          </filter>\n        </defs>\n      </svg>\n\n      {/* Gooey Filtered Metaball Stage */}\n      <div\n        aria-hidden=\"true\"\n        style={{ filter: `url(#gooey-${filterId})` }}\n        className=\"pointer-events-none absolute inset-0 overflow-hidden opacity-90\"\n      >\n        <motion.div\n          animate={{\n            x: [\"-15%\", \"25%\", \"-10%\", \"-15%\"],\n            y: [\"-10%\", \"20%\", \"-15%\", \"-10%\"],\n            scale: [1, 1.2, 0.9, 1],\n          }}\n          transition={{ duration: dur, repeat: Infinity, ease: \"easeInOut\" }}\n          style={{ background: c[0] }}\n          className=\"absolute left-[22%] top-[20%] h-44 w-44 rounded-full\"\n        />\n\n        <motion.div\n          animate={{\n            x: [\"20%\", \"-25%\", \"15%\", \"20%\"],\n            y: [\"15%\", \"-20%\", \"25%\", \"15%\"],\n            scale: [1.1, 0.85, 1.15, 1.1],\n          }}\n          transition={{\n            duration: dur * 1.15,\n            repeat: Infinity,\n            ease: \"easeInOut\",\n          }}\n          style={{ background: c[1] }}\n          className=\"absolute right-[22%] top-[25%] h-48 w-48 rounded-full\"\n        />\n\n        <motion.div\n          animate={{\n            x: [\"-10%\", \"20%\", \"-20%\", \"-10%\"],\n            y: [\"20%\", \"-18%\", \"12%\", \"20%\"],\n          }}\n          transition={{\n            duration: dur * 0.9,\n            repeat: Infinity,\n            ease: \"easeInOut\",\n          }}\n          style={{ background: c[2] }}\n          className=\"absolute bottom-[18%] left-[32%] h-40 w-40 rounded-full\"\n        />\n\n        {/* Cursor-Following Metaball */}\n        <motion.div\n          animate={{\n            left: `${pointer.x}%`,\n            top: `${pointer.y}%`,\n          }}\n          transition={{ type: \"spring\", stiffness: 120, damping: 20 }}\n          style={{ background: c[3] ?? c[0] }}\n          className=\"absolute h-36 w-36 -translate-x-1/2 -translate-y-1/2 rounded-full\"\n        />\n      </div>\n\n      {/* Foreground Content */}\n      <div className=\"relative z-10 flex flex-1 flex-col justify-between\">\n        {children ?? (\n          <>\n            <div className=\"flex items-center justify-between gap-2\">\n              <span className=\"inline-flex items-center gap-1.5 rounded-full border border-white/20 bg-black/35 px-3 py-1 font-mono text-[11px] font-medium text-white backdrop-blur-md\">\n                <Droplets className=\"h-3.5 w-3.5 text-pink-300\" />\n                SVG Gooey Filter · feColorMatrix\n              </span>\n              <span className=\"font-mono text-[11px] text-white/60\">\n                Blur: {gooeyIntensity}px\n              </span>\n            </div>\n\n            <div className=\"my-auto max-w-md py-8\">\n              <h3 className=\"text-2xl font-bold tracking-tight text-white drop-shadow-sm sm:text-3xl\">\n                Liquid Metaball Fusion\n              </h3>\n              <p className=\"mt-2 text-xs leading-relaxed text-white/85 sm:text-sm\">\n                Powered by an SVG{\" \"}\n                <code className=\"font-mono\">feGaussianBlur</code> +{\" \"}\n                <code className=\"font-mono\">feColorMatrix</code> alpha-threshold\n                filter so drifting blobs snap and fuse like liquid lava.\n              </p>\n            </div>\n\n            <div className=\"font-mono text-[11px] text-white/60\">\n              Move your cursor to fuse the interactive metaball with orbiting blobs\n            </div>\n          </>\n        )}\n      </div>\n    </div>\n  );\n}\n\nexport default LiquidGradientBlob;\n",
          "type": "registry:ui",
          "target": "components/ui/liquid-gradient-blob.tsx"
        },
        {
          "path": "lib/utils.ts",
          "content": "import { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...inputs: ClassValue[]) {\n  return twMerge(clsx(inputs));\n}\n\nexport async function copyToClipboard(text: string): Promise<boolean> {\n  if (typeof window === \"undefined\") return false;\n\n  try {\n    if (navigator.clipboard && window.isSecureContext) {\n      await navigator.clipboard.writeText(text);\n      return true;\n    }\n\n    const textArea = document.createElement(\"textarea\");\n    textArea.value = text;\n    textArea.style.position = \"fixed\";\n    textArea.style.left = \"-999999px\";\n    textArea.style.top = \"-999999px\";\n    document.body.appendChild(textArea);\n    textArea.focus();\n    textArea.select();\n    const succeeded = document.execCommand(\"copy\");\n    textArea.remove();\n    return succeeded;\n  } catch {\n    return false;\n  }\n}\n",
          "type": "registry:lib",
          "target": "lib/utils.ts"
        }
      ]
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "liquid-pill-tabs",
      "type": "registry:ui",
      "title": "Liquid Pill Tabs",
      "author": "Rishabh Bose <https://theb0se.vercel.app/>",
      "description": "Segmented navigation tab bar with dual-layer spring layout projection for active and hover indicator pills and roving WAI-ARIA keyboard control.",
      "dependencies": [
        "framer-motion",
        "clsx",
        "tailwind-merge"
      ],
      "files": [
        {
          "path": "components/ui/liquid-pill-tabs.tsx",
          "content": "\"use client\";\n\nimport React, { useId, useRef, useState } from \"react\";\nimport { motion, useReducedMotion } from \"framer-motion\";\nimport { cn } from \"@/lib/utils\";\n\nexport interface LiquidTabItem {\n  id: string;\n  label: string;\n  badge?: string | number;\n}\n\nexport interface LiquidPillTabsProps {\n  /** Array of tab definitions. Defaults to a 4-item studio view switcher. */\n  tabs?: LiquidTabItem[];\n  /** Controlled active tab ID */\n  activeTab?: string;\n  /** Initial active tab ID for uncontrolled usage */\n  defaultActiveTab?: string;\n  /** Spring stiffness coefficient for pill morphing. Default: 380 */\n  stiffness?: number;\n  /** Spring damping coefficient for pill morphing. Default: 26 */\n  damping?: number;\n  /** Callback fired when active tab changes */\n  onChange?: (id: string) => void;\n  className?: string;\n}\n\nconst DEFAULT_TABS: LiquidTabItem[] = [\n  { id: \"preview\", label: \"Preview\" },\n  { id: \"physics\", label: \"Spring Config\", badge: \"3\" },\n  { id: \"code\", label: \"Source\" },\n  { id: \"a11y\", label: \"Accessibility\" },\n];\n\nexport function LiquidPillTabs({\n  tabs = DEFAULT_TABS,\n  activeTab: controlledActive,\n  defaultActiveTab = \"preview\",\n  stiffness = 380,\n  damping = 26,\n  onChange,\n  className,\n}: LiquidPillTabsProps) {\n  const shouldReduceMotion = useReducedMotion() ?? false;\n  const instanceId = useId();\n  const [internalActive, setInternalActive] = useState<string>(\n    defaultActiveTab || tabs[0]?.id || \"\"\n  );\n  const [hoveredId, setHoveredId] = useState<string | null>(null);\n  const tabRefs = useRef<Array<HTMLButtonElement | null>>([]);\n\n  const currentActive =\n    controlledActive !== undefined ? controlledActive : internalActive;\n\n  const selectTab = (id: string) => {\n    if (controlledActive === undefined) {\n      setInternalActive(id);\n    }\n    onChange?.(id);\n  };\n\n  const handleKeyDown = (\n    index: number,\n    e: React.KeyboardEvent<HTMLButtonElement>\n  ) => {\n    if (e.key === \"ArrowRight\") {\n      e.preventDefault();\n      const nextIdx = (index + 1) % tabs.length;\n      const nextTab = tabs[nextIdx];\n      if (nextTab) {\n        selectTab(nextTab.id);\n        tabRefs.current[nextIdx]?.focus();\n      }\n    } else if (e.key === \"ArrowLeft\") {\n      e.preventDefault();\n      const prevIdx = (index - 1 + tabs.length) % tabs.length;\n      const prevTab = tabs[prevIdx];\n      if (prevTab) {\n        selectTab(prevTab.id);\n        tabRefs.current[prevIdx]?.focus();\n      }\n    } else if (e.key === \"Home\") {\n      e.preventDefault();\n      const first = tabs[0];\n      if (first) {\n        selectTab(first.id);\n        tabRefs.current[0]?.focus();\n      }\n    } else if (e.key === \"End\") {\n      e.preventDefault();\n      const lastIdx = tabs.length - 1;\n      const last = tabs[lastIdx];\n      if (last) {\n        selectTab(last.id);\n        tabRefs.current[lastIdx]?.focus();\n      }\n    }\n  };\n\n  return (\n    <div\n      role=\"tablist\"\n      aria-label=\"View mode tabs\"\n      onMouseLeave={() => setHoveredId(null)}\n      className={cn(\n        \"relative inline-flex flex-wrap items-center gap-1 rounded-2xl border border-neutral-200 bg-neutral-100/80 p-1.5 backdrop-blur-md dark:border-[#222222] dark:bg-[#0D0D0D]\",\n        className\n      )}\n    >\n      {tabs.map((tab, idx) => {\n        const isActive = currentActive === tab.id;\n        const isHovered = hoveredId === tab.id;\n\n        return (\n          <button\n            key={tab.id}\n            ref={(el) => {\n              tabRefs.current[idx] = el;\n            }}\n            type=\"button\"\n            role=\"tab\"\n            aria-selected={isActive}\n            tabIndex={isActive ? 0 : -1}\n            onClick={() => selectTab(tab.id)}\n            onMouseEnter={() => setHoveredId(tab.id)}\n            onKeyDown={(e) => handleKeyDown(idx, e)}\n            className={cn(\n              \"relative z-10 inline-flex items-center gap-2 rounded-xl px-3.5 py-2 text-xs font-semibold transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-black dark:focus-visible:ring-white\",\n              isActive\n                ? \"text-white dark:text-black\"\n                : \"text-neutral-600 hover:text-black dark:text-neutral-400 dark:hover:text-white\"\n            )}\n          >\n            {/* Hover Ghost Pill */}\n            {isHovered && !isActive && (\n              <motion.span\n                layoutId={`${instanceId}-hover-pill`}\n                aria-hidden=\"true\"\n                transition={\n                  shouldReduceMotion\n                    ? { duration: 0 }\n                    : { type: \"spring\", stiffness: 420, damping: 30 }\n                }\n                className=\"pointer-events-none absolute inset-0 -z-10 rounded-xl bg-neutral-200/70 dark:bg-[#1B1B1B]\"\n              />\n            )}\n\n            {/* Primary Active Liquid Pill */}\n            {isActive && (\n              <motion.span\n                layoutId={`${instanceId}-active-pill`}\n                aria-hidden=\"true\"\n                transition={\n                  shouldReduceMotion\n                    ? { duration: 0 }\n                    : {\n                        type: \"spring\",\n                        stiffness,\n                        damping,\n                        mass: 0.6,\n                      }\n                }\n                className=\"pointer-events-none absolute inset-0 -z-10 rounded-xl bg-black shadow-sm dark:bg-white\"\n              />\n            )}\n\n            <span>{tab.label}</span>\n\n            {tab.badge !== undefined && (\n              <span\n                className={cn(\n                  \"rounded-full px-1.5 py-0.2 text-[10px] font-bold tabular-nums transition-colors\",\n                  isActive\n                    ? \"bg-white/20 text-white dark:bg-black/15 dark:text-black\"\n                    : \"bg-neutral-200 text-neutral-700 dark:bg-[#1F1F1F] dark:text-neutral-300\"\n                )}\n              >\n                {tab.badge}\n              </span>\n            )}\n          </button>\n        );\n      })}\n    </div>\n  );\n}\n\nexport default LiquidPillTabs;\n",
          "type": "registry:ui",
          "target": "components/ui/liquid-pill-tabs.tsx"
        },
        {
          "path": "lib/utils.ts",
          "content": "import { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...inputs: ClassValue[]) {\n  return twMerge(clsx(inputs));\n}\n\nexport async function copyToClipboard(text: string): Promise<boolean> {\n  if (typeof window === \"undefined\") return false;\n\n  try {\n    if (navigator.clipboard && window.isSecureContext) {\n      await navigator.clipboard.writeText(text);\n      return true;\n    }\n\n    const textArea = document.createElement(\"textarea\");\n    textArea.value = text;\n    textArea.style.position = \"fixed\";\n    textArea.style.left = \"-999999px\";\n    textArea.style.top = \"-999999px\";\n    document.body.appendChild(textArea);\n    textArea.focus();\n    textArea.select();\n    const succeeded = document.execCommand(\"copy\");\n    textArea.remove();\n    return succeeded;\n  } catch {\n    return false;\n  }\n}\n",
          "type": "registry:lib",
          "target": "lib/utils.ts"
        }
      ]
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "live-card-form",
      "type": "registry:ui",
      "title": "Live Card Form",
      "author": "Rishabh Bose <https://theb0se.vercel.app/>",
      "description": "Interactive payment checkout form paired with a photorealistic 3D credit card that automatically flips 180° when CVC is focused, with brand detection and Luhn algorithm validation.",
      "dependencies": [
        "framer-motion",
        "lucide-react",
        "clsx",
        "tailwind-merge"
      ],
      "files": [
        {
          "path": "components/ui/live-card-form.tsx",
          "content": "\"use client\";\n\nimport React, { useState } from \"react\";\nimport { motion, AnimatePresence } from \"framer-motion\";\nimport {\n  CreditCard,\n  Lock,\n  CheckCircle2,\n  AlertCircle,\n  Wifi,\n  Sparkles,\n  RefreshCw,\n  ShieldCheck,\n  ArrowRight,\n} from \"lucide-react\";\nimport { cn } from \"@/lib/utils\";\n\nexport type CardBrand = \"visa\" | \"mastercard\" | \"amex\" | \"discover\" | \"unknown\";\n\nfunction detectCardBrand(number: string): CardBrand {\n  const clean = number.replace(/\\s+/g, \"\");\n  if (/^4/.test(clean)) return \"visa\";\n  if (/^(5[1-5]|2[2-7])/.test(clean)) return \"mastercard\";\n  if (/^3[47]/.test(clean)) return \"amex\";\n  if (/^(6011|65|64[4-9]|622)/.test(clean)) return \"discover\";\n  return \"unknown\";\n}\n\nfunction formatCardNumber(value: string, brand: CardBrand): string {\n  const digits = value.replace(/\\D/g, \"\").slice(0, brand === \"amex\" ? 15 : 16);\n  if (brand === \"amex\") {\n    // 4-6-5 format\n    const parts = [digits.slice(0, 4), digits.slice(4, 10), digits.slice(10, 15)];\n    return parts.filter(Boolean).join(\" \");\n  }\n  // 4-4-4-4 format\n  const parts = digits.match(/.{1,4}/g);\n  return parts ? parts.join(\" \") : digits;\n}\n\nfunction checkLuhn(val: string): boolean {\n  const digits = val.replace(/\\D/g, \"\");\n  if (digits.length < 13) return false;\n  let sum = 0;\n  let shouldDouble = false;\n  for (let i = digits.length - 1; i >= 0; i--) {\n    let digit = parseInt(digits.charAt(i), 10);\n    if (shouldDouble) {\n      digit *= 2;\n      if (digit > 9) digit -= 9;\n    }\n    sum += digit;\n    shouldDouble = !shouldDouble;\n  }\n  return sum % 10 === 0;\n}\n\nexport interface LiveCardFormProps {\n  className?: string;\n  defaultAmount?: string;\n  onSuccess?: () => void;\n}\n\nexport function LiveCardForm({\n  className,\n  defaultAmount = \"$89.00\",\n}: LiveCardFormProps) {\n  const [cardNumber, setCardNumber] = useState(\"4242 4242 4242 4242\");\n  const [cardHolder, setCardHolder] = useState(\"ALEXANDER MERCER\");\n  const [expiry, setExpiry] = useState(\"12/28\");\n  const [cvc, setCvc] = useState(\"892\");\n  const [isFlipped, setIsFlipped] = useState(false);\n  const [isSubmitting, setIsSubmitting] = useState(false);\n  const [isSuccess, setIsSuccess] = useState(false);\n\n  const brand = detectCardBrand(cardNumber);\n  const isValidLuhn = checkLuhn(cardNumber);\n\n  const handleCardNumberChange = (e: React.ChangeEvent<HTMLInputElement>) => {\n    const raw = e.target.value;\n    const detected = detectCardBrand(raw);\n    setCardNumber(formatCardNumber(raw, detected));\n  };\n\n  const handleExpiryChange = (e: React.ChangeEvent<HTMLInputElement>) => {\n    let val = e.target.value.replace(/\\D/g, \"\").slice(0, 4);\n    if (val.length >= 3) {\n      val = val.slice(0, 2) + \"/\" + val.slice(2);\n    }\n    setExpiry(val);\n  };\n\n  const handleCvcChange = (e: React.ChangeEvent<HTMLInputElement>) => {\n    const val = e.target.value.replace(/\\D/g, \"\").slice(0, brand === \"amex\" ? 4 : 3);\n    setCvc(val);\n  };\n\n  const handleFillDemo = (type: \"visa\" | \"mastercard\" | \"amex\") => {\n    if (type === \"visa\") {\n      setCardNumber(\"4242 4242 4242 4242\");\n      setCardHolder(\"JANE DOE\");\n      setExpiry(\"08/29\");\n      setCvc(\"345\");\n    } else if (type === \"mastercard\") {\n      setCardNumber(\"5555 5555 5555 4444\");\n      setCardHolder(\"THOMAS ANDERSON\");\n      setExpiry(\"11/27\");\n      setCvc(\"882\");\n    } else if (type === \"amex\") {\n      setCardNumber(\"3782 822463 10005\");\n      setCardHolder(\"ELEANOR SHELL\");\n      setExpiry(\"05/30\");\n      setCvc(\"1234\");\n    }\n    setIsSuccess(false);\n  };\n\n  const handleSubmit = (e: React.FormEvent) => {\n    e.preventDefault();\n    setIsSubmitting(true);\n    setTimeout(() => {\n      setIsSubmitting(false);\n      setIsSuccess(true);\n      setTimeout(() => setIsSuccess(false), 4000);\n    }, 1200);\n  };\n\n  const getBrandGradient = () => {\n    switch (brand) {\n      case \"visa\":\n        return \"from-[#1a1f71] via-[#0d1440] to-[#04081c]\";\n      case \"mastercard\":\n        return \"from-[#251010] via-[#1a0f18] to-[#090b14]\";\n      case \"amex\":\n        return \"from-[#004b6e] via-[#012f48] to-[#011422]\";\n      case \"discover\":\n        return \"from-[#442306] via-[#2d1405] to-[#090b14]\";\n      default:\n        return \"from-neutral-800 via-neutral-900 to-black\";\n    }\n  };\n\n  return (\n    <div\n      data-fullscreen-scroll\n      className={cn(\n        \"relative w-full min-h-[520px] overflow-hidden rounded-2xl border border-neutral-800 bg-[#070913] p-6 text-white flex flex-col justify-between shadow-2xl selection:bg-indigo-500/30\",\n        className\n      )}\n    >\n      {/* Background ambient lighting */}\n      <div className=\"pointer-events-none absolute inset-0 overflow-hidden\">\n        <div className=\"absolute top-10 right-10 h-80 w-80 rounded-full bg-indigo-600/10 blur-[100px]\" />\n        <div className=\"absolute bottom-10 left-10 h-72 w-72 rounded-full bg-violet-600/10 blur-[90px]\" />\n      </div>\n\n      {/* Main Content Grid: 3D Card vs Form */}\n      <div className=\"relative z-10 w-full max-w-5xl mx-auto my-auto grid grid-cols-1 lg:grid-cols-12 gap-8 items-center py-4\">\n        {/* Left Side: 3D Interactive Card Preview */}\n        <div className=\"lg:col-span-5 flex flex-col items-center justify-center\">\n          <div\n            className=\"w-full max-w-[380px] h-[230px] cursor-pointer\"\n            style={{ perspective: 1000 }}\n            onClick={() => setIsFlipped(!isFlipped)}\n          >\n            <motion.div\n              animate={{ rotateY: isFlipped ? 180 : 0 }}\n              transition={{ duration: 0.7, type: \"spring\", stiffness: 260, damping: 24 }}\n              className=\"relative w-full h-full rounded-2xl shadow-2xl transition-all\"\n              style={{ transformStyle: \"preserve-3d\" }}\n            >\n              {/* Card Front */}\n              <div\n                className={cn(\n                  \"absolute inset-0 rounded-2xl p-6 flex flex-col justify-between border border-white/15 bg-gradient-to-br shadow-2xl overflow-hidden\",\n                  getBrandGradient()\n                )}\n                style={{ backfaceVisibility: \"hidden\" }}\n              >\n                {/* Holographic Sheen Layer */}\n                <div className=\"pointer-events-none absolute -inset-full bg-gradient-to-tr from-transparent via-white/10 to-transparent rotate-45 opacity-60\" />\n\n                {/* Card Top: Chip + Wireless + Brand */}\n                <div className=\"flex items-center justify-between z-10\">\n                  <div className=\"flex items-center gap-3\">\n                    {/* Metallic EMV Chip */}\n                    <div className=\"h-8 w-11 rounded-md bg-gradient-to-br from-amber-200 via-amber-400 to-amber-600 border border-amber-300/40 p-1 flex flex-col justify-between shadow-inner\">\n                      <div className=\"w-full h-0.5 bg-amber-700/40 rounded\" />\n                      <div className=\"w-full h-0.5 bg-amber-700/40 rounded\" />\n                      <div className=\"w-full h-0.5 bg-amber-700/40 rounded\" />\n                    </div>\n                    {/* Wireless Contactless Icon */}\n                    <Wifi className=\"h-4 w-4 text-white/60 rotate-90\" />\n                  </div>\n\n                  {/* Brand Badge */}\n                  <BrandLogo brand={brand} />\n                </div>\n\n                {/* Card Number */}\n                <div className=\"z-10 tracking-[0.2em] font-mono text-lg sm:text-xl font-medium text-white drop-shadow\">\n                  {cardNumber || \"•••• •••• •••• ••••\"}\n                </div>\n\n                {/* Card Bottom: Holder + Expiry */}\n                <div className=\"flex items-end justify-between z-10 text-xs font-mono\">\n                  <div>\n                    <div className=\"text-[9px] uppercase tracking-wider text-white/60\">\n                      Card Holder\n                    </div>\n                    <div className=\"font-semibold text-neutral-100 tracking-wider truncate max-w-[190px]\">\n                      {cardHolder || \"FULL NAME\"}\n                    </div>\n                  </div>\n                  <div className=\"text-right\">\n                    <div className=\"text-[9px] uppercase tracking-wider text-white/60\">\n                      Expires\n                    </div>\n                    <div className=\"font-semibold text-neutral-100 tracking-wider\">\n                      {expiry || \"MM/YY\"}\n                    </div>\n                  </div>\n                </div>\n              </div>\n\n              {/* Card Back */}\n              <div\n                className={cn(\n                  \"absolute inset-0 rounded-2xl flex flex-col justify-between border border-white/15 bg-gradient-to-br shadow-2xl overflow-hidden py-5\",\n                  getBrandGradient()\n                )}\n                style={{\n                  backfaceVisibility: \"hidden\",\n                  transform: \"rotateY(180deg)\",\n                }}\n              >\n                {/* Magnetic Stripe */}\n                <div className=\"w-full h-11 bg-neutral-950 mt-1 shadow-inner\" />\n\n                {/* Signature Strip + CVC */}\n                <div className=\"px-6 flex items-center gap-3\">\n                  <div className=\"flex-1 h-9 bg-neutral-200/90 rounded px-3 flex items-center justify-between text-neutral-900 font-serif italic text-xs select-none\">\n                    <span className=\"truncate\">{cardHolder || \"Authorized Signature\"}</span>\n                  </div>\n                  <div className=\"w-16 h-8 rounded bg-white text-neutral-900 font-mono font-bold flex items-center justify-center text-sm shadow\">\n                    {cvc || \"•••\"}\n                  </div>\n                </div>\n\n                {/* Telemetry info */}\n                <div className=\"px-6 text-[9px] text-white/50 leading-relaxed font-mono flex items-center justify-between\">\n                  <span>PULSE EMV GLOBAL NETWORK</span>\n                  <span>CLICK TO FLIP</span>\n                </div>\n              </div>\n            </motion.div>\n          </div>\n\n          <div className=\"mt-4 flex items-center gap-2 text-xs text-neutral-400\">\n            <span className=\"h-2 w-2 rounded-full bg-emerald-400 animate-pulse\" />\n            <span>Interactive 3D Preview (Auto-flips on CVC focus)</span>\n          </div>\n        </div>\n\n        {/* Right Side: Form Inputs */}\n        <div className=\"lg:col-span-7 bg-neutral-900/60 border border-neutral-800 rounded-2xl p-6 backdrop-blur-xl\">\n          <div className=\"flex items-center justify-between pb-4 border-b border-neutral-800\">\n            <div>\n              <h3 className=\"text-lg font-semibold text-white\">Payment Details</h3>\n              <p className=\"text-xs text-neutral-400\">Complete your transaction with end-to-end encryption</p>\n            </div>\n            <div className=\"flex items-center gap-1.5 px-2.5 py-1 rounded-full bg-emerald-500/10 border border-emerald-500/20 text-emerald-400 text-xs font-medium\">\n              <ShieldCheck className=\"h-3.5 w-3.5\" />\n              <span>PCI-DSS Level 1</span>\n            </div>\n          </div>\n\n          <form onSubmit={handleSubmit} className=\"mt-5 space-y-4\">\n            {/* Card Number Input */}\n            <div>\n              <div className=\"flex items-center justify-between mb-1.5\">\n                <label className=\"text-xs font-medium text-neutral-300\">\n                  Card Number\n                </label>\n                {isValidLuhn && (\n                  <span className=\"flex items-center gap-1 text-[11px] text-emerald-400 font-medium\">\n                    <CheckCircle2 className=\"h-3 w-3\" />\n                    Luhn Verified\n                  </span>\n                )}\n              </div>\n              <div className=\"relative\">\n                <input\n                  type=\"text\"\n                  value={cardNumber}\n                  onChange={handleCardNumberChange}\n                  placeholder=\"4242 4242 4242 4242\"\n                  className={cn(\n                    \"w-full rounded-xl bg-neutral-950/80 border px-3.5 py-2.5 text-sm font-mono text-white placeholder-neutral-500 focus:outline-none transition-all\",\n                    isValidLuhn\n                      ? \"border-emerald-500/50 focus:border-emerald-500 focus:ring-1 focus:ring-emerald-500\"\n                      : \"border-neutral-700/80 focus:border-indigo-500 focus:ring-1 focus:ring-indigo-500\"\n                  )}\n                />\n                <div className=\"absolute right-3 top-1/2 -translate-y-1/2 pointer-events-none\">\n                  <BrandLogo brand={brand} small />\n                </div>\n              </div>\n            </div>\n\n            {/* Cardholder Name */}\n            <div>\n              <label className=\"block text-xs font-medium text-neutral-300 mb-1.5\">\n                Cardholder Name\n              </label>\n              <input\n                type=\"text\"\n                value={cardHolder}\n                onChange={(e) => setCardHolder(e.target.value.toUpperCase())}\n                placeholder=\"ALEXANDER MERCER\"\n                className=\"w-full rounded-xl bg-neutral-950/80 border border-neutral-700/80 px-3.5 py-2.5 text-sm text-white placeholder-neutral-500 focus:outline-none focus:border-indigo-500 focus:ring-1 focus:ring-indigo-500 transition-all font-mono uppercase\"\n              />\n            </div>\n\n            {/* Expiry and CVC Row */}\n            <div className=\"grid grid-cols-2 gap-4\">\n              <div>\n                <label className=\"block text-xs font-medium text-neutral-300 mb-1.5\">\n                  Expiration Date\n                </label>\n                <input\n                  type=\"text\"\n                  value={expiry}\n                  onChange={handleExpiryChange}\n                  placeholder=\"MM/YY\"\n                  maxLength={5}\n                  className=\"w-full rounded-xl bg-neutral-950/80 border border-neutral-700/80 px-3.5 py-2.5 text-sm font-mono text-white placeholder-neutral-500 focus:outline-none focus:border-indigo-500 focus:ring-1 focus:ring-indigo-500 transition-all\"\n                />\n              </div>\n\n              <div>\n                <div className=\"flex items-center justify-between mb-1.5\">\n                  <label className=\"text-xs font-medium text-neutral-300\">\n                    CVC / CVV\n                  </label>\n                  <span className=\"text-[10px] text-neutral-500\">\n                    {brand === \"amex\" ? \"4 digits\" : \"3 digits\"}\n                  </span>\n                </div>\n                <div className=\"relative\">\n                  <input\n                    type=\"password\"\n                    value={cvc}\n                    onChange={handleCvcChange}\n                    onFocus={() => setIsFlipped(true)}\n                    onBlur={() => setIsFlipped(false)}\n                    placeholder={brand === \"amex\" ? \"••••\" : \"•••\"}\n                    maxLength={brand === \"amex\" ? 4 : 3}\n                    className=\"w-full rounded-xl bg-neutral-950/80 border border-neutral-700/80 px-3.5 py-2.5 text-sm font-mono text-white placeholder-neutral-500 focus:outline-none focus:border-indigo-500 focus:ring-1 focus:ring-indigo-500 transition-all\"\n                  />\n                  <Lock className=\"absolute right-3 top-1/2 -translate-y-1/2 h-3.5 w-3.5 text-neutral-500 pointer-events-none\" />\n                </div>\n              </div>\n            </div>\n\n            {/* Submit Action */}\n            <button\n              type=\"submit\"\n              disabled={isSubmitting}\n              className=\"mt-2 w-full py-3 px-4 rounded-xl bg-gradient-to-r from-indigo-500 to-violet-600 hover:from-indigo-400 hover:to-violet-500 text-white font-medium text-sm shadow-lg shadow-indigo-500/25 flex items-center justify-center gap-2 transition-all disabled:opacity-60 active:scale-[0.99]\"\n            >\n              {isSubmitting ? (\n                <>\n                  <RefreshCw className=\"h-4 w-4 animate-spin\" />\n                  <span>Authorizing Payment...</span>\n                </>\n              ) : isSuccess ? (\n                <>\n                  <CheckCircle2 className=\"h-4 w-4 text-emerald-300\" />\n                  <span>Authorized & Settled!</span>\n                </>\n              ) : (\n                <>\n                  <Lock className=\"h-3.5 w-3.5\" />\n                  <span>Pay {defaultAmount} Securely</span>\n                  <ArrowRight className=\"h-4 w-4 ml-1\" />\n                </>\n              )}\n            </button>\n          </form>\n        </div>\n      </div>\n    </div>\n  );\n}\n\nfunction BrandLogo({ brand, small = false }: { brand: CardBrand; small?: boolean }) {\n  if (brand === \"visa\") {\n    return (\n      <span\n        className={cn(\n          \"font-black tracking-tighter text-blue-400 italic font-sans\",\n          small ? \"text-xs\" : \"text-lg\"\n        )}\n      >\n        VISA\n      </span>\n    );\n  }\n  if (brand === \"mastercard\") {\n    return (\n      <div className=\"flex items-center -space-x-1.5\">\n        <div className={cn(\"rounded-full bg-red-500\", small ? \"h-3.5 w-3.5\" : \"h-5 w-5\")} />\n        <div className={cn(\"rounded-full bg-amber-400/90\", small ? \"h-3.5 w-3.5\" : \"h-5 w-5\")} />\n      </div>\n    );\n  }\n  if (brand === \"amex\") {\n    return (\n      <span\n        className={cn(\n          \"font-bold font-mono tracking-widest text-sky-400 border border-sky-400/40 rounded px-1\",\n          small ? \"text-[10px]\" : \"text-xs\"\n        )}\n      >\n        AMEX\n      </span>\n    );\n  }\n  if (brand === \"discover\") {\n    return (\n      <span\n        className={cn(\n          \"font-bold font-sans text-orange-400 tracking-wide\",\n          small ? \"text-[10px]\" : \"text-xs\"\n        )}\n      >\n        DISCOVER\n      </span>\n    );\n  }\n  return <CreditCard className={cn(\"text-neutral-500\", small ? \"h-4 w-4\" : \"h-5 w-5\")} />;\n}\n\nexport default LiveCardForm;\n",
          "type": "registry:ui",
          "target": "components/ui/live-card-form.tsx"
        },
        {
          "path": "lib/utils.ts",
          "content": "import { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...inputs: ClassValue[]) {\n  return twMerge(clsx(inputs));\n}\n\nexport async function copyToClipboard(text: string): Promise<boolean> {\n  if (typeof window === \"undefined\") return false;\n\n  try {\n    if (navigator.clipboard && window.isSecureContext) {\n      await navigator.clipboard.writeText(text);\n      return true;\n    }\n\n    const textArea = document.createElement(\"textarea\");\n    textArea.value = text;\n    textArea.style.position = \"fixed\";\n    textArea.style.left = \"-999999px\";\n    textArea.style.top = \"-999999px\";\n    document.body.appendChild(textArea);\n    textArea.focus();\n    textArea.select();\n    const succeeded = document.execCommand(\"copy\");\n    textArea.remove();\n    return succeeded;\n  } catch {\n    return false;\n  }\n}\n",
          "type": "registry:lib",
          "target": "lib/utils.ts"
        }
      ]
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "magnetic-breadcrumb",
      "type": "registry:ui",
      "title": "Magnetic Breadcrumb",
      "author": "Rishabh Bose <https://theb0se.vercel.app/>",
      "description": "Hierarchical breadcrumb navigation trail with a spring-projected hover capsule and subtle vertical lift across path segments.",
      "dependencies": [
        "framer-motion",
        "lucide-react",
        "clsx",
        "tailwind-merge"
      ],
      "files": [
        {
          "path": "components/ui/magnetic-breadcrumb.tsx",
          "content": "\"use client\";\n\nimport React, { useId, useState } from \"react\";\nimport { motion, useReducedMotion } from \"framer-motion\";\nimport { ChevronRight, Home } from \"lucide-react\";\nimport { cn } from \"@/lib/utils\";\n\nexport interface BreadcrumbSegment {\n  id: string;\n  label: string;\n  href?: string;\n}\n\nexport interface MagneticBreadcrumbProps {\n  /** Ordered array of breadcrumb path segments. */\n  items?: BreadcrumbSegment[];\n  /** Spring stiffness coefficient for sliding hover pill. Default: 380 */\n  stiffness?: number;\n  /** Spring damping coefficient for sliding hover pill. Default: 26 */\n  damping?: number;\n  /** Callback fired when a segment is clicked */\n  onSelect?: (id: string) => void;\n  className?: string;\n}\n\nconst DEFAULT_SEGMENTS: BreadcrumbSegment[] = [\n  { id: \"root\", label: \"Workspace\" },\n  { id: \"registry\", label: \"Registry v2\" },\n  { id: \"primitives\", label: \"Primitives\" },\n  { id: \"kinetic\", label: \"MagneticBreadcrumb\" },\n];\n\nexport function MagneticBreadcrumb({\n  items = DEFAULT_SEGMENTS,\n  stiffness = 380,\n  damping = 26,\n  onSelect,\n  className,\n}: MagneticBreadcrumbProps) {\n  const shouldReduceMotion = useReducedMotion() ?? false;\n  const instanceId = useId();\n  const [activeId, setActiveId] = useState<string>(\n    items[items.length - 1]?.id || \"kinetic\"\n  );\n  const [hoveredId, setHoveredId] = useState<string | null>(null);\n\n  return (\n    <nav\n      aria-label=\"Breadcrumb\"\n      onMouseLeave={() => setHoveredId(null)}\n      className={cn(\n        \"inline-flex flex-wrap items-center gap-1 py-2\",\n        className\n      )}\n    >\n      <ol className=\"flex flex-wrap items-center gap-1\">\n        {items.map((segment, index) => {\n          const isCurrent = activeId === segment.id;\n          const isHovered = hoveredId === segment.id;\n\n          return (\n            <li key={segment.id} className=\"flex items-center gap-1\">\n              <motion.button\n                type=\"button\"\n                aria-current={isCurrent ? \"page\" : undefined}\n                onClick={() => {\n                  setActiveId(segment.id);\n                  onSelect?.(segment.id);\n                }}\n                onMouseEnter={() => setHoveredId(segment.id)}\n                onFocus={() => setHoveredId(segment.id)}\n                whileHover={shouldReduceMotion ? undefined : { y: -1 }}\n                whileTap={shouldReduceMotion ? undefined : { scale: 0.96 }}\n                transition={{ type: \"spring\", stiffness, damping }}\n                className={cn(\n                  \"relative z-10 inline-flex items-center gap-1.5 rounded-xl px-2.5 py-1.5 text-xs font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-black dark:focus-visible:ring-white\",\n                  isCurrent\n                    ? \"font-semibold text-black dark:text-white\"\n                    : \"text-neutral-500 hover:text-black dark:text-neutral-400 dark:hover:text-white\"\n                )}\n              >\n                {isHovered && (\n                  <motion.span\n                    layoutId={`${instanceId}-crumb-pill`}\n                    aria-hidden=\"true\"\n                    transition={\n                      shouldReduceMotion\n                        ? { duration: 0 }\n                        : { type: \"spring\", stiffness, damping }\n                    }\n                    className=\"pointer-events-none absolute inset-0 -z-10 rounded-xl bg-neutral-100 dark:bg-[#181818]\"\n                  />\n                )}\n\n                {index === 0 && <Home className=\"h-3.5 w-3.5\" />}\n                <span>{segment.label}</span>\n              </motion.button>\n\n              {index < items.length - 1 && (\n                <ChevronRight\n                  aria-hidden=\"true\"\n                  className=\"h-3.5 w-3.5 text-neutral-300 dark:text-neutral-600\"\n                />\n              )}\n            </li>\n          );\n        })}\n      </ol>\n    </nav>\n  );\n}\n\nexport default MagneticBreadcrumb;\n",
          "type": "registry:ui",
          "target": "components/ui/magnetic-breadcrumb.tsx"
        },
        {
          "path": "lib/utils.ts",
          "content": "import { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...inputs: ClassValue[]) {\n  return twMerge(clsx(inputs));\n}\n\nexport async function copyToClipboard(text: string): Promise<boolean> {\n  if (typeof window === \"undefined\") return false;\n\n  try {\n    if (navigator.clipboard && window.isSecureContext) {\n      await navigator.clipboard.writeText(text);\n      return true;\n    }\n\n    const textArea = document.createElement(\"textarea\");\n    textArea.value = text;\n    textArea.style.position = \"fixed\";\n    textArea.style.left = \"-999999px\";\n    textArea.style.top = \"-999999px\";\n    document.body.appendChild(textArea);\n    textArea.focus();\n    textArea.select();\n    const succeeded = document.execCommand(\"copy\");\n    textArea.remove();\n    return succeeded;\n  } catch {\n    return false;\n  }\n}\n",
          "type": "registry:lib",
          "target": "lib/utils.ts"
        }
      ]
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "magnetic-button",
      "type": "registry:ui",
      "title": "Magnetic Button",
      "author": "Rishabh Bose <https://theb0se.vercel.app/>",
      "description": "Tactile button with dual-layer spring attraction that gravitates toward the pointer with configurable mass, stiffness, and damping.",
      "dependencies": [
        "framer-motion",
        "clsx",
        "tailwind-merge"
      ],
      "files": [
        {
          "path": "components/ui/magnetic-button.tsx",
          "content": "\"use client\";\n\nimport React, { useRef, useState } from \"react\";\nimport {\n  motion,\n  useMotionValue,\n  useSpring,\n  useReducedMotion,\n  type HTMLMotionProps,\n} from \"framer-motion\";\nimport { cn } from \"@/lib/utils\";\n\nexport interface MagneticButtonProps\n  extends Omit<HTMLMotionProps<\"button\">, \"children\"> {\n  children: React.ReactNode;\n  /** Pull intensity multiplier (0.1 to 1). Default: 0.35 */\n  strength?: number;\n  /** Spring stiffness. Default: 180 */\n  stiffness?: number;\n  /** Spring damping. Default: 15 */\n  damping?: number;\n  /** Spring mass. Default: 0.2 */\n  mass?: number;\n  /** Visual style preset */\n  variant?: \"primary\" | \"secondary\" | \"outline\" | \"glow\";\n  /** Size preset */\n  size?: \"sm\" | \"md\" | \"lg\";\n}\n\nexport function MagneticButton({\n  children,\n  className,\n  strength = 0.35,\n  stiffness = 180,\n  damping = 15,\n  mass = 0.2,\n  variant = \"primary\",\n  size = \"md\",\n  onMouseMove,\n  onMouseLeave,\n  ...props\n}: MagneticButtonProps) {\n  const ref = useRef<HTMLButtonElement>(null);\n  const shouldReduceMotion = useReducedMotion();\n  const [isHovered, setIsHovered] = useState(false);\n\n  const rawX = useMotionValue(0);\n  const rawY = useMotionValue(0);\n\n  const springConfig = { stiffness, damping, mass };\n  const x = useSpring(rawX, springConfig);\n  const y = useSpring(rawY, springConfig);\n\n  const innerX = useSpring(useMotionValue(0), {\n    stiffness: stiffness * 1.2,\n    damping,\n    mass,\n  });\n  const innerY = useSpring(useMotionValue(0), {\n    stiffness: stiffness * 1.2,\n    damping,\n    mass,\n  });\n\n  const handleMouseMove = (e: React.MouseEvent<HTMLButtonElement>) => {\n    if (!ref.current || shouldReduceMotion) return;\n\n    const rect = ref.current.getBoundingClientRect();\n    const centerX = rect.left + rect.width / 2;\n    const centerY = rect.top + rect.height / 2;\n\n    const deltaX = (e.clientX - centerX) * strength;\n    const deltaY = (e.clientY - centerY) * strength;\n\n    rawX.set(deltaX);\n    rawY.set(deltaY);\n    innerX.set(deltaX * 0.35);\n    innerY.set(deltaY * 0.35);\n\n    onMouseMove?.(e);\n  };\n\n  const handleMouseLeave = (e: React.MouseEvent<HTMLButtonElement>) => {\n    setIsHovered(false);\n    rawX.set(0);\n    rawY.set(0);\n    innerX.set(0);\n    innerY.set(0);\n    onMouseLeave?.(e);\n  };\n\n  const variantStyles: Record<\n    NonNullable<MagneticButtonProps[\"variant\"]>,\n    string\n  > = {\n    primary:\n      \"bg-black text-white hover:bg-neutral-800 border border-black dark:bg-white dark:text-black dark:hover:bg-neutral-200 dark:border-white\",\n    secondary:\n      \"bg-neutral-100 text-black hover:bg-neutral-200 border border-neutral-200 dark:bg-[#141414] dark:text-white dark:hover:bg-[#1F1F1F] dark:border-[#262626]\",\n    outline:\n      \"bg-transparent text-black border border-neutral-300 hover:border-black hover:bg-black/5 dark:text-white dark:border-[#262626] dark:hover:border-white dark:hover:bg-white/5\",\n    glow:\n      \"bg-white text-black border border-black/40 hover:border-black shadow-sm dark:bg-[#0A0A0A] dark:text-white dark:border-white/40 dark:hover:border-white dark:shadow-[0_0_24px_-4px_rgba(255,255,255,0.22)]\",\n  };\n\n  const sizeStyles: Record<NonNullable<MagneticButtonProps[\"size\"]>, string> = {\n    sm: \"px-3.5 py-2 text-xs rounded-lg gap-1.5\",\n    md: \"px-5 py-2.5 text-sm rounded-xl gap-2\",\n    lg: \"px-6 py-3 text-sm rounded-xl gap-2.5\",\n  };\n\n  return (\n    <motion.button\n      ref={ref}\n      type=\"button\"\n      onMouseEnter={() => setIsHovered(true)}\n      onMouseMove={handleMouseMove}\n      onMouseLeave={handleMouseLeave}\n      style={{\n        x: shouldReduceMotion ? 0 : x,\n        y: shouldReduceMotion ? 0 : y,\n      }}\n      whileTap={shouldReduceMotion ? undefined : { scale: 0.97 }}\n      className={cn(\n        \"relative inline-flex items-center justify-center font-medium tracking-tight transition-colors duration-200 select-none focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-black dark:focus-visible:ring-white focus-visible:ring-offset-2\",\n        variantStyles[variant],\n        sizeStyles[size],\n        className\n      )}\n      {...props}\n    >\n      <span\n        aria-hidden=\"true\"\n        className={cn(\n          \"pointer-events-none absolute inset-0 rounded-[inherit] transition-opacity duration-300\",\n          isHovered ? \"opacity-100\" : \"opacity-0\"\n        )}\n        style={{\n          background:\n            \"radial-gradient(circle at center, rgba(128,128,128,0.12), transparent 70%)\",\n        }}\n      />\n\n      <motion.span\n        style={{\n          x: shouldReduceMotion ? 0 : innerX,\n          y: shouldReduceMotion ? 0 : innerY,\n        }}\n        className=\"relative z-10 inline-flex items-center gap-2\"\n      >\n        {children}\n      </motion.span>\n    </motion.button>\n  );\n}\n",
          "type": "registry:ui",
          "target": "components/ui/magnetic-button.tsx"
        },
        {
          "path": "lib/utils.ts",
          "content": "import { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...inputs: ClassValue[]) {\n  return twMerge(clsx(inputs));\n}\n\nexport async function copyToClipboard(text: string): Promise<boolean> {\n  if (typeof window === \"undefined\") return false;\n\n  try {\n    if (navigator.clipboard && window.isSecureContext) {\n      await navigator.clipboard.writeText(text);\n      return true;\n    }\n\n    const textArea = document.createElement(\"textarea\");\n    textArea.value = text;\n    textArea.style.position = \"fixed\";\n    textArea.style.left = \"-999999px\";\n    textArea.style.top = \"-999999px\";\n    document.body.appendChild(textArea);\n    textArea.focus();\n    textArea.select();\n    const succeeded = document.execCommand(\"copy\");\n    textArea.remove();\n    return succeeded;\n  } catch {\n    return false;\n  }\n}\n",
          "type": "registry:lib",
          "target": "lib/utils.ts"
        }
      ]
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "magnetic-popover-menu",
      "type": "registry:ui",
      "title": "Magnetic Popover Menu",
      "author": "Rishabh Bose <https://theb0se.vercel.app/>",
      "description": "Floating command popover menu with origin-scaled spring entry, a shared-layout magnetic row highlight, and keyboard arrow navigation.",
      "dependencies": [
        "framer-motion",
        "lucide-react",
        "clsx",
        "tailwind-merge"
      ],
      "files": [
        {
          "path": "components/ui/magnetic-popover-menu.tsx",
          "content": "\"use client\";\n\nimport React, { useEffect, useId, useRef, useState } from \"react\";\nimport { AnimatePresence, motion, useReducedMotion } from \"framer-motion\";\nimport {\n  Command,\n  Copy,\n  Sparkles,\n  Terminal,\n  Share2,\n  ChevronDown,\n} from \"lucide-react\";\nimport { cn } from \"@/lib/utils\";\n\nexport interface PopoverCommandItem {\n  id: string;\n  label: string;\n  shortcut: string;\n  icon: React.ReactNode;\n}\n\nexport interface MagneticPopoverMenuProps {\n  /** Trigger button label. Default: \"Quick Actions\" */\n  triggerLabel?: string;\n  /** Array of popover menu items. */\n  items?: PopoverCommandItem[];\n  /** Hooke's Law spring stiffness coefficient. Default: 380 */\n  stiffness?: number;\n  /** Spring damping coefficient. Default: 26 */\n  damping?: number;\n  /** Callback fired when an item is selected */\n  onSelect?: (id: string) => void;\n  className?: string;\n}\n\nconst DEFAULT_ITEMS: PopoverCommandItem[] = [\n  {\n    id: \"install\",\n    label: \"Copy CLI Command\",\n    shortcut: \"⌘C\",\n    icon: <Terminal className=\"h-3.5 w-3.5\" />,\n  },\n  {\n    id: \"source\",\n    label: \"Copy .tsx Source\",\n    shortcut: \"⌘S\",\n    icon: <Copy className=\"h-3.5 w-3.5\" />,\n  },\n  {\n    id: \"tune\",\n    label: \"Tune Spring Constants\",\n    shortcut: \"⌘K\",\n    icon: <Sparkles className=\"h-3.5 w-3.5\" />,\n  },\n  {\n    id: \"share\",\n    label: \"Share Component URL\",\n    shortcut: \"⌘U\",\n    icon: <Share2 className=\"h-3.5 w-3.5\" />,\n  },\n];\n\nexport function MagneticPopoverMenu({\n  triggerLabel = \"Quick Actions\",\n  items = DEFAULT_ITEMS,\n  stiffness = 380,\n  damping = 26,\n  onSelect,\n  className,\n}: MagneticPopoverMenuProps) {\n  const shouldReduceMotion = useReducedMotion() ?? false;\n  const instanceId = useId();\n  const containerRef = useRef<HTMLDivElement | null>(null);\n  const itemRefs = useRef<Array<HTMLButtonElement | null>>([]);\n\n  const [isOpen, setIsOpen] = useState(false);\n  const [activeIndex, setActiveIndex] = useState<number>(0);\n\n  useEffect(() => {\n    if (!isOpen) return;\n    const handleOutside = (e: MouseEvent) => {\n      if (\n        containerRef.current &&\n        !containerRef.current.contains(e.target as Node)\n      ) {\n        setIsOpen(false);\n      }\n    };\n    const handleEsc = (e: KeyboardEvent) => {\n      if (e.key === \"Escape\") {\n        setIsOpen(false);\n      }\n    };\n    window.addEventListener(\"mousedown\", handleOutside);\n    window.addEventListener(\"keydown\", handleEsc);\n    return () => {\n      window.removeEventListener(\"mousedown\", handleOutside);\n      window.removeEventListener(\"keydown\", handleEsc);\n    };\n  }, [isOpen]);\n\n  const handleKeyDown = (e: React.KeyboardEvent<HTMLDivElement>) => {\n    if (!isOpen) return;\n    if (e.key === \"ArrowDown\") {\n      e.preventDefault();\n      const next = (activeIndex + 1) % items.length;\n      setActiveIndex(next);\n      itemRefs.current[next]?.focus();\n    } else if (e.key === \"ArrowUp\") {\n      e.preventDefault();\n      const prev = (activeIndex - 1 + items.length) % items.length;\n      setActiveIndex(prev);\n      itemRefs.current[prev]?.focus();\n    }\n  };\n\n  return (\n    <div\n      ref={containerRef}\n      onKeyDown={handleKeyDown}\n      className={cn(\"relative inline-block\", className)}\n    >\n      <motion.button\n        type=\"button\"\n        aria-haspopup=\"menu\"\n        aria-expanded={isOpen}\n        onClick={() => setIsOpen((prev) => !prev)}\n        whileTap={shouldReduceMotion ? undefined : { scale: 0.96 }}\n        className=\"inline-flex h-11 items-center gap-2 rounded-2xl border border-neutral-200 bg-white px-4 text-xs font-semibold text-black shadow-sm transition-colors hover:border-black focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-black dark:border-[#222222] dark:bg-[#0A0A0A] dark:text-white dark:hover:border-white dark:focus-visible:ring-white\"\n      >\n        <Command className=\"h-3.5 w-3.5\" />\n        <span>{triggerLabel}</span>\n        <ChevronDown\n          className={cn(\n            \"h-3.5 w-3.5 text-neutral-400 transition-transform duration-200\",\n            isOpen && \"rotate-180 text-black dark:text-white\"\n          )}\n        />\n      </motion.button>\n\n      <AnimatePresence>\n        {isOpen && (\n          <motion.div\n            role=\"menu\"\n            aria-label={triggerLabel}\n            initial={\n              shouldReduceMotion\n                ? { opacity: 0 }\n                : { opacity: 0, scale: 0.92, y: -6 }\n            }\n            animate={{ opacity: 1, scale: 1, y: 0 }}\n            exit={\n              shouldReduceMotion\n                ? { opacity: 0 }\n                : { opacity: 0, scale: 0.94, y: -4 }\n            }\n            transition={{ type: \"spring\", stiffness, damping }}\n            className=\"absolute left-0 top-full z-30 mt-2 w-60 origin-top-left rounded-2xl border border-neutral-200 bg-white p-1.5 shadow-xl dark:border-[#262626] dark:bg-[#0D0D0D]\"\n          >\n            {items.map((item, idx) => {\n              const isHighlighted = activeIndex === idx;\n\n              return (\n                <button\n                  key={item.id}\n                  ref={(el) => {\n                    itemRefs.current[idx] = el;\n                  }}\n                  type=\"button\"\n                  role=\"menuitem\"\n                  onMouseEnter={() => setActiveIndex(idx)}\n                  onFocus={() => setActiveIndex(idx)}\n                  onClick={() => {\n                    onSelect?.(item.id);\n                    setIsOpen(false);\n                  }}\n                  className=\"relative z-10 flex w-full items-center justify-between rounded-xl px-3 py-2 text-left text-xs font-medium text-black transition-colors focus-visible:outline-none dark:text-white\"\n                >\n                  {isHighlighted && (\n                    <motion.span\n                      layoutId={`${instanceId}-popover-highlight`}\n                      aria-hidden=\"true\"\n                      transition={\n                        shouldReduceMotion\n                          ? { duration: 0 }\n                          : { type: \"spring\", stiffness: 420, damping: 28 }\n                      }\n                      className=\"pointer-events-none absolute inset-0 -z-10 rounded-xl bg-neutral-100 dark:bg-[#1A1A1A]\"\n                    />\n                  )}\n\n                  <span className=\"flex items-center gap-2.5\">\n                    {item.icon}\n                    <span>{item.label}</span>\n                  </span>\n\n                  <kbd className=\"rounded border border-neutral-200 bg-white px-1.5 py-0.5 font-mono text-[10px] text-neutral-400 dark:border-[#262626] dark:bg-[#121212]\">\n                    {item.shortcut}\n                  </kbd>\n                </button>\n              );\n            })}\n          </motion.div>\n        )}\n      </AnimatePresence>\n    </div>\n  );\n}\n\nexport default MagneticPopoverMenu;\n",
          "type": "registry:ui",
          "target": "components/ui/magnetic-popover-menu.tsx"
        },
        {
          "path": "lib/utils.ts",
          "content": "import { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...inputs: ClassValue[]) {\n  return twMerge(clsx(inputs));\n}\n\nexport async function copyToClipboard(text: string): Promise<boolean> {\n  if (typeof window === \"undefined\") return false;\n\n  try {\n    if (navigator.clipboard && window.isSecureContext) {\n      await navigator.clipboard.writeText(text);\n      return true;\n    }\n\n    const textArea = document.createElement(\"textarea\");\n    textArea.value = text;\n    textArea.style.position = \"fixed\";\n    textArea.style.left = \"-999999px\";\n    textArea.style.top = \"-999999px\";\n    document.body.appendChild(textArea);\n    textArea.focus();\n    textArea.select();\n    const succeeded = document.execCommand(\"copy\");\n    textArea.remove();\n    return succeeded;\n  } catch {\n    return false;\n  }\n}\n",
          "type": "registry:lib",
          "target": "lib/utils.ts"
        }
      ]
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "matrix-rain",
      "type": "registry:ui",
      "title": "Matrix Rain",
      "author": "Rishabh Bose <https://theb0se.vercel.app/>",
      "description": "Canvas 2D digital rain cascade with incandescent white leading glyphs, phosphor trail decay, and real-time character mutation across Katakana, Binary, and Hexadecimal character sets.",
      "dependencies": [
        "lucide-react",
        "clsx",
        "tailwind-merge"
      ],
      "files": [
        {
          "path": "components/ui/matrix-rain.tsx",
          "content": "\"use client\";\n\nimport React, { useEffect, useRef, useState } from \"react\";\nimport { Terminal, Zap, Cpu, RefreshCw, Layers } from \"lucide-react\";\nimport { cn } from \"@/lib/utils\";\n\nexport interface MatrixRainProps {\n  /** Primary phosphor color in hex format (e.g., \"#10B981\") */\n  color?: string;\n  /** Fall speed multiplier */\n  speed?: number;\n  /** Stream density multiplier (0.3 to 2.0) */\n  density?: number;\n  /** Glyph character set */\n  charset?: \"katakana\" | \"binary\" | \"hex\";\n  /** Font size in pixels */\n  fontSize?: number;\n  /** Optional overlay content */\n  children?: React.ReactNode;\n  /** Additional container classes */\n  className?: string;\n}\n\nconst CHARSETS: Record<\"katakana\" | \"binary\" | \"hex\", string> = {\n  katakana:\n    \"アァカサタナハマヤャラワガザダバパイィキシチニヒミリヰギジヂビピウゥクスツヌフムユュルグズブヅプエェケセテネヘメレヱゲゼデベペオォコソトノホモヨョロヲゴゾドボポヴッン0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ<>|=+*:\",\n  binary: \"01\",\n  hex: \"0123456789ABCDEF\",\n};\n\ninterface StreamDrop {\n  layer: 0 | 1 | 2; // 0 = far, 1 = mid, 2 = near\n  x: number;\n  y: number;\n  speed: number;\n  length: number;\n  fontSize: number;\n  chars: string[];\n  glitchTimers: number[];\n  mutationRate: number;\n}\n\nfunction hexToRgb(hex: string): { r: number; g: number; b: number } {\n  const clean = hex.replace(\"#\", \"\");\n  const full =\n    clean.length === 3\n      ? clean\n          .split(\"\")\n          .map((c) => c + c)\n          .join(\"\")\n      : clean;\n  const num = parseInt(full, 16);\n  if (Number.isNaN(num)) return { r: 16, g: 185, b: 129 };\n  return {\n    r: (num >> 16) & 255,\n    g: (num >> 8) & 255,\n    b: num & 255,\n  };\n}\n\nexport function MatrixRain({\n  color: propColor = \"#10B981\",\n  speed: propSpeed = 1.0,\n  density: propDensity = 1.0,\n  charset: propCharset = \"katakana\",\n  fontSize: propFontSize = 15,\n  children,\n  className,\n}: MatrixRainProps) {\n  const containerRef = useRef<HTMLDivElement>(null);\n  const canvasRef = useRef<HTMLCanvasElement>(null);\n  const pointerRef = useRef<{ x: number; y: number; active: boolean }>({\n    x: -9999,\n    y: -9999,\n    active: false,\n  });\n\n  const [activeCharset, setActiveCharset] = useState<\n    \"katakana\" | \"binary\" | \"hex\"\n  >(propCharset);\n  const [activeColor, setActiveColor] = useState<string>(propColor);\n  const [activeSpeed, setActiveSpeed] = useState<number>(propSpeed);\n  const [activeDensity, setActiveDensity] = useState<number>(propDensity);\n  const [streamCount, setStreamCount] = useState<number>(0);\n\n  useEffect(() => {\n    setActiveCharset(propCharset);\n  }, [propCharset]);\n\n  useEffect(() => {\n    setActiveColor(propColor);\n  }, [propColor]);\n\n  useEffect(() => {\n    setActiveSpeed(propSpeed);\n  }, [propSpeed]);\n\n  useEffect(() => {\n    setActiveDensity(propDensity);\n  }, [propDensity]);\n\n  useEffect(() => {\n    const container = containerRef.current;\n    const canvas = canvasRef.current;\n    if (!container || !canvas) return;\n\n    const ctx = canvas.getContext(\"2d\");\n    if (!ctx) return;\n\n    let animationFrameId = 0;\n    let width = 0;\n    let height = 0;\n    let drops: StreamDrop[] = [];\n\n    const glyphPool = CHARSETS[activeCharset] || CHARSETS.katakana;\n    const randomGlyph = () =>\n      glyphPool[Math.floor(Math.random() * glyphPool.length)] || \"0\";\n\n    const createLayerDrops = (\n      layer: 0 | 1 | 2,\n      layerFontSize: number,\n      densityFactor: number,\n      speedRange: [number, number],\n      lengthRange: [number, number]\n    ): StreamDrop[] => {\n      const colStep = Math.max(9, layerFontSize);\n      const totalCols = Math.ceil(width / colStep);\n      const count = Math.max(\n        4,\n        Math.floor(\n          totalCols *\n            densityFactor *\n            Math.min(2.2, Math.max(0.3, activeDensity))\n        )\n      );\n\n      return Array.from({ length: count }, (_, i) => {\n        const colIndex = Math.floor((i / count) * totalCols);\n        const length = Math.floor(\n          lengthRange[0] + Math.random() * (lengthRange[1] - lengthRange[0])\n        );\n        return {\n          layer,\n          x:\n            colIndex * colStep +\n            layerFontSize * 0.5 +\n            (Math.random() - 0.5) * 4,\n          y: Math.random() * height * 1.4 - height * 0.7,\n          speed:\n            (speedRange[0] + Math.random() * (speedRange[1] - speedRange[0])) *\n            layerFontSize *\n            0.12,\n          length,\n          fontSize: layerFontSize,\n          chars: Array.from({ length: length + 8 }, randomGlyph),\n          glitchTimers: Array.from({ length: length + 8 }, () =>\n            Math.random()\n          ),\n          mutationRate:\n            layer === 1\n              ? 0.03 + Math.random() * 0.06\n              : 0.015 + Math.random() * 0.04,\n        };\n      });\n    };\n\n    const initStreams = () => {\n      const farFont = Math.max(10, Math.round(propFontSize * 0.72));\n      const midFont = Math.max(12, propFontSize);\n      const nearFont = Math.max(18, Math.round(propFontSize * 1.48));\n\n      const farDrops = createLayerDrops(0, farFont, 0.75, [0.45, 0.85], [14, 28]);\n      const midDrops = createLayerDrops(1, midFont, 0.95, [0.85, 1.55], [14, 30]);\n      const nearDrops = createLayerDrops(2, nearFont, 0.22, [1.45, 2.25], [8, 16]);\n\n      drops = [...farDrops, ...midDrops, ...nearDrops];\n      setStreamCount(drops.length);\n    };\n\n    const updateSize = () => {\n      const rect = container.getBoundingClientRect();\n      const dpr = Math.min(window.devicePixelRatio || 1, 2);\n      width = Math.max(1, Math.floor(rect.width));\n      height = Math.max(1, Math.floor(rect.height));\n      canvas.width = width * dpr;\n      canvas.height = height * dpr;\n      ctx.setTransform(dpr, 0, 0, dpr, 0, 0);\n      initStreams();\n    };\n\n    updateSize();\n    const observer = new ResizeObserver(updateSize);\n    observer.observe(container);\n\n    const rgb = hexToRgb(activeColor);\n    const brightR = Math.min(255, rgb.r + 135);\n    const brightG = Math.min(255, rgb.g + 135);\n    const brightB = Math.min(255, rgb.b + 135);\n\n    const render = () => {\n      // Crisp full-frame dark phosphor clear + subtle ambient depth gradient\n      ctx.fillStyle = \"#02060A\";\n      ctx.fillRect(0, 0, width, height);\n\n      const bgGlow = ctx.createRadialGradient(\n        width * 0.5,\n        height * 0.45,\n        20,\n        width * 0.5,\n        height * 0.5,\n        Math.max(width, height) * 0.75\n      );\n      bgGlow.addColorStop(0, `rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, 0.07)`);\n      bgGlow.addColorStop(1, \"rgba(2, 6, 10, 0)\");\n      ctx.fillStyle = bgGlow;\n      ctx.fillRect(0, 0, width, height);\n\n      const ptr = pointerRef.current;\n      const parallaxOffset = ptr.active\n        ? (ptr.x / Math.max(1, width) - 0.5) * 28\n        : 0;\n\n      ctx.textAlign = \"center\";\n      ctx.textBaseline = \"middle\";\n\n      let currentLayer = -1;\n\n      for (let i = 0; i < drops.length; i++) {\n        const drop = drops[i];\n\n        if (drop.layer !== currentLayer) {\n          currentLayer = drop.layer;\n          const weight = currentLayer === 0 ? \"500\" : \"700\";\n          ctx.font = `${weight} ${drop.fontSize}px ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace`;\n        }\n\n        drop.y += drop.speed * activeSpeed;\n\n        const layerShift =\n          drop.layer === 0\n            ? -parallaxOffset * 0.35\n            : drop.layer === 1\n            ? parallaxOffset * 0.25\n            : parallaxOffset * 0.85;\n\n        const drawX = ((drop.x + layerShift) % width + width) % width;\n        const stepY = drop.fontSize * 1.05;\n        const headRow = Math.floor(drop.y / stepY);\n\n        // Soft vertical phosphor bloom spine behind mid & near streams\n        if (drop.layer >= 1) {\n          const headY = headRow * stepY;\n          const tailTopY = (headRow - drop.length * 0.75) * stepY;\n          if (headY > 0 && tailTopY < height) {\n            const spineGrad = ctx.createLinearGradient(\n              drawX,\n              Math.max(0, tailTopY),\n              drawX,\n              Math.min(height, headY + stepY)\n            );\n            const maxSpineAlpha = drop.layer === 2 ? 0.14 : 0.09;\n            spineGrad.addColorStop(0, `rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, 0)`);\n            spineGrad.addColorStop(\n              0.85,\n              `rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, ${maxSpineAlpha})`\n            );\n            spineGrad.addColorStop(\n              1,\n              `rgba(${brightR}, ${brightG}, ${brightB}, ${maxSpineAlpha * 1.5})`\n            );\n            ctx.fillStyle = spineGrad;\n            ctx.fillRect(\n              drawX - drop.fontSize * 0.45,\n              Math.max(0, tailTopY),\n              drop.fontSize * 0.9,\n              Math.min(height, headY + stepY) - Math.max(0, tailTopY)\n            );\n          }\n        }\n\n        const baseLayerAlpha =\n          drop.layer === 0 ? 0.34 : drop.layer === 1 ? 0.92 : 0.52;\n\n        for (let j = 0; j < drop.length; j++) {\n          const charY = (headRow - j) * stepY;\n          if (charY < -drop.fontSize || charY > height + drop.fontSize) {\n            continue;\n          }\n\n          // Deterministic slot tied to grid row so characters stay stationary in space while the illumination wave falls through them\n          const charSlot =\n            ((headRow - j) % drop.chars.length + drop.chars.length) %\n            drop.chars.length;\n\n          if (Math.random() < drop.mutationRate * (j === 0 ? 2.5 : 0.5)) {\n            drop.chars[charSlot] = randomGlyph();\n            drop.glitchTimers[charSlot] = 1.0;\n          } else {\n            drop.glitchTimers[charSlot] = Math.max(\n              0,\n              drop.glitchTimers[charSlot] - 0.04\n            );\n          }\n\n          const ch = drop.chars[charSlot];\n\n          // Pointer proximity boost\n          let pointerBoost = 0;\n          if (ptr.active) {\n            const dist = Math.hypot(drawX - ptr.x, charY - ptr.y);\n            if (dist < 130) {\n              pointerBoost = (1 - dist / 130) * 0.55;\n            }\n          }\n\n          if (j === 0) {\n            // Incandescent white-hot lead character with bloom\n            ctx.save();\n            ctx.shadowColor = `rgba(${brightR}, ${brightG}, ${brightB}, 0.95)`;\n            ctx.shadowBlur = drop.layer === 0 ? 4 : drop.layer === 1 ? 14 : 20;\n            ctx.fillStyle =\n              drop.layer === 0\n                ? `rgba(${brightR}, ${brightG}, ${brightB}, 0.75)`\n                : \"#FFFFFF\";\n            ctx.fillText(ch, drawX, charY);\n            ctx.restore();\n          } else if (j <= 2) {\n            // Sub-head high-energy phosphor transition\n            const subAlpha = Math.min(1, baseLayerAlpha + pointerBoost);\n            ctx.fillStyle = `rgba(${brightR}, ${brightG}, ${brightB}, ${subAlpha.toFixed(\n              3\n            )})`;\n            ctx.fillText(ch, drawX, charY);\n          } else {\n            // Smooth exponential phosphor decay along tail + occasional bright glitch character\n            const progress = j / drop.length;\n            const decay = Math.pow(1 - progress, 1.65);\n            const glitchFlash = drop.glitchTimers[charSlot] * 0.35;\n            const finalAlpha = Math.min(\n              1,\n              (decay * baseLayerAlpha + glitchFlash + pointerBoost)\n            );\n\n            if (finalAlpha > 0.02) {\n              if (drop.glitchTimers[charSlot] > 0.65 && drop.layer === 1) {\n                ctx.fillStyle = `rgba(${brightR}, ${brightG}, ${brightB}, ${finalAlpha.toFixed(\n                  3\n                )})`;\n              } else {\n                ctx.fillStyle = `rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, ${finalAlpha.toFixed(\n                  3\n                )})`;\n              }\n              ctx.fillText(ch, drawX, charY);\n            }\n          }\n        }\n\n        // Respawn stream once tail clears bottom of screen\n        if ((headRow - drop.length) * stepY > height + drop.fontSize * 2) {\n          drop.y = -Math.random() * height * 0.45;\n        }\n      }\n\n      animationFrameId = requestAnimationFrame(render);\n    };\n\n    animationFrameId = requestAnimationFrame(render);\n\n    return () => {\n      cancelAnimationFrame(animationFrameId);\n      observer.disconnect();\n    };\n  }, [activeCharset, activeColor, activeSpeed, activeDensity, propFontSize]);\n\n  return (\n    <div\n      ref={containerRef}\n      data-fullscreen-scroll\n      onMouseMove={(e) => {\n        const rect = e.currentTarget.getBoundingClientRect();\n        pointerRef.current = {\n          x: e.clientX - rect.left,\n          y: e.clientY - rect.top,\n          active: true,\n        };\n      }}\n      onMouseLeave={() => {\n        pointerRef.current.active = false;\n      }}\n      className={cn(\n        \"relative w-full min-h-[520px] overflow-hidden rounded-2xl border border-emerald-500/20 bg-[#02060A] text-slate-100 shadow-2xl\",\n        className\n      )}\n    >\n      <canvas\n        ref={canvasRef}\n        aria-hidden=\"true\"\n        className=\"pointer-events-none absolute inset-0 h-full w-full\"\n      />\n\n      {/* Authentic CRT Scanline & Vignette Overlay */}\n      <div\n        aria-hidden=\"true\"\n        className=\"pointer-events-none absolute inset-0 bg-[linear-gradient(to_bottom,transparent_50%,rgba(0,0,0,0.28)_50%)] bg-[length:100%_4px] opacity-60\"\n      />\n      <div\n        aria-hidden=\"true\"\n        className=\"pointer-events-none absolute inset-0 bg-[radial-gradient(circle_at_center,transparent_40%,rgba(1,4,9,0.86)_100%)]\"\n      />\n\n      {children && (\n        <div className=\"relative z-10 flex min-h-[520px] w-full flex-col\">\n          {children}\n        </div>\n      )}\n    </div>\n  );\n}\n\nexport default MatrixRain;\n",
          "type": "registry:ui",
          "target": "components/ui/matrix-rain.tsx"
        },
        {
          "path": "lib/utils.ts",
          "content": "import { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...inputs: ClassValue[]) {\n  return twMerge(clsx(inputs));\n}\n\nexport async function copyToClipboard(text: string): Promise<boolean> {\n  if (typeof window === \"undefined\") return false;\n\n  try {\n    if (navigator.clipboard && window.isSecureContext) {\n      await navigator.clipboard.writeText(text);\n      return true;\n    }\n\n    const textArea = document.createElement(\"textarea\");\n    textArea.value = text;\n    textArea.style.position = \"fixed\";\n    textArea.style.left = \"-999999px\";\n    textArea.style.top = \"-999999px\";\n    document.body.appendChild(textArea);\n    textArea.focus();\n    textArea.select();\n    const succeeded = document.execCommand(\"copy\");\n    textArea.remove();\n    return succeeded;\n  } catch {\n    return false;\n  }\n}\n",
          "type": "registry:lib",
          "target": "lib/utils.ts"
        }
      ]
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "mesh-gradient",
      "type": "registry:ui",
      "title": "Mesh Gradient",
      "author": "Rishabh Bose <https://theb0se.vercel.app/>",
      "description": "Apple Music and macOS-inspired fluid multi-point mesh gradient where 5 color nodes orbit on independent trajectories and blend seamlessly.",
      "dependencies": [
        "lucide-react",
        "clsx",
        "tailwind-merge"
      ],
      "files": [
        {
          "path": "components/ui/mesh-gradient.tsx",
          "content": "\"use client\";\n\nimport React, { useState } from \"react\";\nimport { Sparkles } from \"lucide-react\";\nimport { cn } from \"@/lib/utils\";\n\nexport interface MeshGradientProps {\n  /** Array of 4 to 5 hex colors blended across the mesh */\n  colors?: string[];\n  /** Animation speed multiplier (1 = default). Default: 1 */\n  speed?: number;\n  /** Blur radius in pixels. Default: 70 */\n  blur?: number;\n  /** Overlay subtle noise grain. Default: true */\n  grain?: boolean;\n  /** Optional foreground content */\n  children?: React.ReactNode;\n  className?: string;\n}\n\nconst MESH_PRESETS: Record<string, string[]> = {\n  \"Apple Music\": [\"#FF2D55\", \"#5856D6\", \"#FF9500\", \"#AF52DE\", \"#00C7BE\"],\n  Sequoia: [\"#1E3A8A\", \"#0EA5E9\", \"#F97316\", \"#FACC15\", \"#4338CA\"],\n  Obsidian: [\"#312E81\", \"#4C1D95\", \"#0F766E\", \"#1E40AF\", \"#701A75\"],\n};\n\nexport function MeshGradient({\n  colors = MESH_PRESETS[\"Apple Music\"],\n  speed = 1,\n  blur = 70,\n  grain = true,\n  children,\n  className,\n}: MeshGradientProps) {\n  const [presetName, setPresetName] = useState<string>(\"Apple Music\");\n  const [palette, setPalette] = useState<string[]>(colors);\n\n  const c = palette.length >= 4 ? palette : MESH_PRESETS[\"Apple Music\"];\n  const dur = Math.max(5, 16 / Math.max(0.2, speed));\n\n  return (\n    <div\n      data-fullscreen-scroll\n      className={cn(\n        \"relative flex min-h-[360px] w-full flex-col justify-between overflow-hidden rounded-3xl border border-neutral-800 bg-[#080711] p-6 text-white shadow-sm\",\n        className\n      )}\n    >\n      <style>{`\n        @keyframes bose-mesh-orbit-1 {\n          0%, 100% { transform: translate(0%, 0%) scale(1); }\n          50% { transform: translate(28%, 22%) scale(1.25); }\n        }\n        @keyframes bose-mesh-orbit-2 {\n          0%, 100% { transform: translate(0%, 0%) scale(1.1); }\n          50% { transform: translate(-26%, 24%) scale(0.9); }\n        }\n        @keyframes bose-mesh-orbit-3 {\n          0%, 100% { transform: translate(0%, 0%) scale(0.95); }\n          50% { transform: translate(24%, -26%) scale(1.2); }\n        }\n        @keyframes bose-mesh-orbit-4 {\n          0%, 100% { transform: translate(0%, 0%) scale(1.05); }\n          50% { transform: translate(-22%, -20%) scale(1.15); }\n        }\n      `}</style>\n\n      {/* Multi-Point Blurred Mesh Canvas */}\n      <div\n        aria-hidden=\"true\"\n        style={{ filter: `blur(${blur}px) saturate(140%)` }}\n        className=\"pointer-events-none absolute -inset-12 overflow-hidden opacity-90\"\n      >\n        <div\n          style={{\n            background: c[0],\n            animation: `bose-mesh-orbit-1 ${dur}s ease-in-out infinite`,\n          }}\n          className=\"absolute left-[5%] top-[5%] h-72 w-72 rounded-full\"\n        />\n        <div\n          style={{\n            background: c[1],\n            animation: `bose-mesh-orbit-2 ${dur * 1.2}s ease-in-out infinite`,\n          }}\n          className=\"absolute right-[8%] top-[10%] h-80 w-80 rounded-full\"\n        />\n        <div\n          style={{\n            background: c[2],\n            animation: `bose-mesh-orbit-3 ${dur * 0.9}s ease-in-out infinite`,\n          }}\n          className=\"absolute bottom-[5%] left-[15%] h-72 w-72 rounded-full\"\n        />\n        <div\n          style={{\n            background: c[3],\n            animation: `bose-mesh-orbit-4 ${dur * 1.35}s ease-in-out infinite`,\n          }}\n          className=\"absolute bottom-[8%] right-[12%] h-72 w-72 rounded-full\"\n        />\n        {c[4] && (\n          <div\n            style={{\n              background: c[4],\n              animation: `bose-mesh-orbit-1 ${dur * 1.1}s ease-in-out infinite reverse`,\n            }}\n            className=\"absolute left-1/3 top-1/3 h-64 w-64 rounded-full\"\n          />\n        )}\n      </div>\n\n      {/* Subtle Film Grain */}\n      {grain && (\n        <div\n          aria-hidden=\"true\"\n          className=\"pointer-events-none absolute inset-0 opacity-[0.15] mix-blend-overlay [background-image:radial-gradient(rgba(255,255,255,0.7)_1px,transparent_0)] [background-size:3px_3px]\"\n        />\n      )}\n\n      {/* Foreground Content */}\n      <div className=\"relative z-10 flex flex-1 flex-col justify-between\">\n        {children ?? (\n          <>\n            <div className=\"flex flex-wrap items-center justify-between gap-2\">\n              <span className=\"inline-flex items-center gap-1.5 rounded-full border border-white/20 bg-black/30 px-3 py-1 font-mono text-[11px] font-medium text-white backdrop-blur-md\">\n                <Sparkles className=\"h-3.5 w-3.5\" />\n                Mesh Gradient · {presetName}\n              </span>\n\n              <div className=\"flex items-center gap-1 rounded-full border border-white/20 bg-black/30 p-1 backdrop-blur-md\">\n                {Object.keys(MESH_PRESETS).map((name) => (\n                  <button\n                    key={name}\n                    type=\"button\"\n                    onClick={() => {\n                      setPresetName(name);\n                      setPalette(MESH_PRESETS[name]);\n                    }}\n                    className={cn(\n                      \"rounded-full px-2.5 py-0.5 font-mono text-[10px] font-semibold transition-colors\",\n                      presetName === name\n                        ? \"bg-white text-black\"\n                        : \"text-white/80 hover:text-white\"\n                    )}\n                  >\n                    {name}\n                  </button>\n                ))}\n              </div>\n            </div>\n\n            <div className=\"my-auto max-w-md py-8\">\n              <h3 className=\"text-2xl font-bold tracking-tight text-white drop-shadow-sm sm:text-3xl\">\n                Fluid Multi-Point Mesh\n              </h3>\n              <p className=\"mt-2 text-xs leading-relaxed text-white/85 sm:text-sm\">\n                Five color control points orbiting smoothly on independent CSS\n                trajectories and blended with a {blur}px Gaussian diffusion\n                filter.\n              </p>\n            </div>\n\n            <div className=\"flex items-center gap-2\">\n              {c.map((hex, i) => (\n                <span\n                  key={i}\n                  style={{ backgroundColor: hex }}\n                  className=\"h-4 w-4 rounded-full border border-white/40 shadow-xs\"\n                />\n              ))}\n              <span className=\"ml-1 font-mono text-[11px] text-white/75\">\n                5 Control Points · {blur}px Blur\n              </span>\n            </div>\n          </>\n        )}\n      </div>\n    </div>\n  );\n}\n\nexport default MeshGradient;\n",
          "type": "registry:ui",
          "target": "components/ui/mesh-gradient.tsx"
        },
        {
          "path": "lib/utils.ts",
          "content": "import { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...inputs: ClassValue[]) {\n  return twMerge(clsx(inputs));\n}\n\nexport async function copyToClipboard(text: string): Promise<boolean> {\n  if (typeof window === \"undefined\") return false;\n\n  try {\n    if (navigator.clipboard && window.isSecureContext) {\n      await navigator.clipboard.writeText(text);\n      return true;\n    }\n\n    const textArea = document.createElement(\"textarea\");\n    textArea.value = text;\n    textArea.style.position = \"fixed\";\n    textArea.style.left = \"-999999px\";\n    textArea.style.top = \"-999999px\";\n    document.body.appendChild(textArea);\n    textArea.focus();\n    textArea.select();\n    const succeeded = document.execCommand(\"copy\");\n    textArea.remove();\n    return succeeded;\n  } catch {\n    return false;\n  }\n}\n",
          "type": "registry:lib",
          "target": "lib/utils.ts"
        }
      ]
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "modal-popup",
      "type": "registry:ui",
      "title": "Modal Popup",
      "author": "Rishabh Bose <https://theb0se.vercel.app/>",
      "description": "Animated popup modal dialog with spring scale transitions, top-level portal rendering, danger/confirm variants, and Escape dismissal.",
      "dependencies": [
        "framer-motion",
        "lucide-react",
        "clsx",
        "tailwind-merge"
      ],
      "files": [
        {
          "path": "components/ui/modal-popup.tsx",
          "content": "\"use client\";\n\nimport React, { useEffect, useState, useCallback } from \"react\";\nimport { createPortal } from \"react-dom\";\nimport { AnimatePresence, motion, useReducedMotion } from \"framer-motion\";\nimport { X } from \"lucide-react\";\nimport { cn } from \"@/lib/utils\";\n\nexport type ModalSize = \"sm\" | \"md\" | \"lg\";\nexport type ModalVariant = \"default\" | \"danger\";\n\nexport interface ModalPopupProps {\n  /** Controlled open state */\n  open?: boolean;\n  /** Default open state when uncontrolled */\n  defaultOpen?: boolean;\n  /** Callback when open state changes */\n  onOpenChange?: (open: boolean) => void;\n  /** Dialog title */\n  title?: string;\n  /** Dialog subtitle/description */\n  description?: string;\n  /** Width preset */\n  size?: ModalSize;\n  /** Visual style for confirm action (\"default\" | \"danger\") */\n  variant?: ModalVariant;\n  /** Default trigger button label */\n  triggerLabel?: string;\n  /** Custom trigger element */\n  trigger?: React.ReactNode;\n  /** Primary confirm button text */\n  confirmLabel?: string;\n  /** Cancel button text */\n  cancelLabel?: string;\n  /** Hide default footer buttons when rendering a custom form in children */\n  hideFooter?: boolean;\n  /** Callback when confirm button is clicked */\n  onConfirm?: () => void;\n  /** Custom body content */\n  children?: React.ReactNode;\n  /** Additional dialog class names */\n  className?: string;\n}\n\nconst SIZE_CLASSES: Record<ModalSize, string> = {\n  sm: \"max-w-sm\",\n  md: \"max-w-md\",\n  lg: \"max-w-lg\",\n};\n\nexport function ModalPopup({\n  open: controlledOpen,\n  defaultOpen = false,\n  onOpenChange,\n  title = \"Confirm Deployment\",\n  description = \"This action will build and deploy your latest commit to production.\",\n  size = \"md\",\n  variant = \"default\",\n  triggerLabel = \"Open Popup\",\n  trigger,\n  confirmLabel = \"Confirm\",\n  cancelLabel = \"Cancel\",\n  hideFooter = false,\n  onConfirm,\n  children,\n  className,\n}: ModalPopupProps) {\n  const shouldReduceMotion = useReducedMotion();\n  const [mounted, setMounted] = useState(false);\n  const [internalOpen, setInternalOpen] = useState(defaultOpen);\n  const isOpen = controlledOpen !== undefined ? controlledOpen : internalOpen;\n\n  useEffect(() => {\n    setMounted(true);\n  }, []);\n\n  const setOpen = useCallback(\n    (next: boolean) => {\n      if (controlledOpen === undefined) {\n        setInternalOpen(next);\n      }\n      onOpenChange?.(next);\n    },\n    [controlledOpen, onOpenChange]\n  );\n\n  useEffect(() => {\n    if (!isOpen) return;\n    const previousOverflow = document.body.style.overflow;\n    document.body.style.overflow = \"hidden\";\n\n    const handleKey = (e: KeyboardEvent) => {\n      if (e.key === \"Escape\") setOpen(false);\n    };\n    window.addEventListener(\"keydown\", handleKey);\n    return () => {\n      document.body.style.overflow = previousOverflow;\n      window.removeEventListener(\"keydown\", handleKey);\n    };\n  }, [isOpen, setOpen]);\n\n  const modalContent = (\n    <AnimatePresence>\n      {isOpen && (\n        <div className=\"fixed inset-0 z-[9999] flex items-center justify-center p-4\">\n          {/* Backdrop */}\n          <motion.div\n            initial={{ opacity: 0 }}\n            animate={{ opacity: 1 }}\n            exit={{ opacity: 0 }}\n            transition={{ duration: shouldReduceMotion ? 0 : 0.18 }}\n            onClick={() => setOpen(false)}\n            className=\"fixed inset-0 z-[9998] bg-black/60 backdrop-blur-xs\"\n            aria-hidden=\"true\"\n          />\n\n          {/* Dialog Card */}\n          <motion.div\n            role=\"dialog\"\n            aria-modal=\"true\"\n            aria-label={title}\n            initial={\n              shouldReduceMotion\n                ? { opacity: 0 }\n                : { opacity: 0, scale: 0.94, y: 10 }\n            }\n            animate={\n              shouldReduceMotion ? { opacity: 1 } : { opacity: 1, scale: 1, y: 0 }\n            }\n            exit={\n              shouldReduceMotion\n                ? { opacity: 0 }\n                : { opacity: 0, scale: 0.96, y: 6 }\n            }\n            transition={{\n              type: \"spring\",\n              stiffness: 420,\n              damping: 30,\n            }}\n            className={cn(\n              \"relative z-[9999] w-full overflow-hidden rounded-2xl border border-neutral-200 bg-white p-6 text-black shadow-2xl dark:border-[#242424] dark:bg-[#0A0A0A] dark:text-white\",\n              SIZE_CLASSES[size],\n              className\n            )}\n          >\n            {/* Header */}\n            <div className=\"flex items-start justify-between gap-4\">\n              <div>\n                <h3 className=\"text-base font-semibold tracking-tight text-black dark:text-white\">\n                  {title}\n                </h3>\n                {description && (\n                  <p className=\"mt-1.5 text-xs leading-relaxed text-neutral-500 dark:text-neutral-400\">\n                    {description}\n                  </p>\n                )}\n              </div>\n\n              <button\n                type=\"button\"\n                onClick={() => setOpen(false)}\n                aria-label=\"Close popup\"\n                className=\"cursor-pointer rounded-lg border border-neutral-200 p-1.5 text-neutral-500 transition-colors hover:border-black hover:text-black dark:border-[#262626] dark:hover:border-white dark:hover:text-white\"\n              >\n                <X className=\"h-4 w-4\" />\n              </button>\n            </div>\n\n            {/* Body */}\n            {children && (\n              <div className=\"mt-4 text-xs text-neutral-600 dark:text-neutral-300\">\n                {children}\n              </div>\n            )}\n\n            {/* Footer Actions */}\n            {!hideFooter && (\n              <div className=\"mt-6 flex items-center justify-end gap-2\">\n                <button\n                  type=\"button\"\n                  onClick={() => setOpen(false)}\n                  className=\"cursor-pointer rounded-xl border border-neutral-200 px-3.5 py-2 text-xs font-medium text-neutral-600 transition-colors hover:border-black hover:text-black dark:border-[#262626] dark:text-neutral-400 dark:hover:border-white dark:hover:text-white\"\n                >\n                  {cancelLabel}\n                </button>\n                <button\n                  type=\"button\"\n                  onClick={() => {\n                    onConfirm?.();\n                    setOpen(false);\n                  }}\n                  className={cn(\n                    \"cursor-pointer rounded-xl px-4 py-2 text-xs font-medium transition-colors\",\n                    variant === \"danger\"\n                      ? \"bg-red-600 text-white hover:bg-red-700\"\n                      : \"bg-black text-white hover:bg-neutral-800 dark:bg-white dark:text-black dark:hover:bg-neutral-200\"\n                  )}\n                >\n                  {confirmLabel}\n                </button>\n              </div>\n            )}\n          </motion.div>\n        </div>\n      )}\n    </AnimatePresence>\n  );\n\n  return (\n    <>\n      {trigger ? (\n        <div onClick={() => setOpen(true)} className=\"inline-block cursor-pointer\">\n          {trigger}\n        </div>\n      ) : (\n        <button\n          type=\"button\"\n          onClick={() => setOpen(true)}\n          className=\"inline-flex cursor-pointer items-center justify-center rounded-xl bg-black px-4 py-2 text-xs font-medium text-white transition-colors hover:bg-neutral-800 dark:bg-white dark:text-black dark:hover:bg-neutral-200\"\n        >\n          {triggerLabel}\n        </button>\n      )}\n\n      {mounted && createPortal(modalContent, document.body)}\n    </>\n  );\n}\n\nexport default ModalPopup;\n",
          "type": "registry:ui",
          "target": "components/ui/modal-popup.tsx"
        },
        {
          "path": "lib/utils.ts",
          "content": "import { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...inputs: ClassValue[]) {\n  return twMerge(clsx(inputs));\n}\n\nexport async function copyToClipboard(text: string): Promise<boolean> {\n  if (typeof window === \"undefined\") return false;\n\n  try {\n    if (navigator.clipboard && window.isSecureContext) {\n      await navigator.clipboard.writeText(text);\n      return true;\n    }\n\n    const textArea = document.createElement(\"textarea\");\n    textArea.value = text;\n    textArea.style.position = \"fixed\";\n    textArea.style.left = \"-999999px\";\n    textArea.style.top = \"-999999px\";\n    document.body.appendChild(textArea);\n    textArea.focus();\n    textArea.select();\n    const succeeded = document.execCommand(\"copy\");\n    textArea.remove();\n    return succeeded;\n  } catch {\n    return false;\n  }\n}\n",
          "type": "registry:lib",
          "target": "lib/utils.ts"
        }
      ]
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "morphing-action-button",
      "type": "registry:ui",
      "title": "Morphing Action Button",
      "author": "Rishabh Bose <https://theb0se.vercel.app/>",
      "description": "Multi-phase stateful pill button that morphs its bounding width across Idle, Compiling, and Published states using spring layout projection.",
      "dependencies": [
        "framer-motion",
        "lucide-react",
        "clsx",
        "tailwind-merge"
      ],
      "files": [
        {
          "path": "components/ui/morphing-action-button.tsx",
          "content": "\"use client\";\n\nimport React, { useState } from \"react\";\nimport { AnimatePresence, motion, useReducedMotion } from \"framer-motion\";\nimport { ArrowRight, Check, Loader2, AlertTriangle } from \"lucide-react\";\nimport { cn } from \"@/lib/utils\";\n\nexport type ActionPhase = \"idle\" | \"loading\" | \"success\" | \"error\";\n\nexport interface MorphingActionButtonProps {\n  /** Label shown in resting idle phase. Default: \"Publish Registry\" */\n  idleLabel?: string;\n  /** Label shown during async loading phase. Default: \"Compiling...\" */\n  loadingLabel?: string;\n  /** Label shown upon completion. Default: \"Published v2.4\" */\n  successLabel?: string;\n  /** Simulate an error state on every second click for demo purposes. Default: false */\n  simulateError?: boolean;\n  /** Hooke's Law spring stiffness coefficient for pill width morphing. Default: 380 */\n  stiffness?: number;\n  /** Spring damping coefficient for pill width morphing. Default: 26 */\n  damping?: number;\n  className?: string;\n}\n\nexport function MorphingActionButton({\n  idleLabel = \"Publish Registry\",\n  loadingLabel = \"Compiling...\",\n  successLabel = \"Published v2.4\",\n  simulateError = false,\n  stiffness = 380,\n  damping = 26,\n  className,\n}: MorphingActionButtonProps) {\n  const shouldReduceMotion = useReducedMotion() ?? false;\n  const [phase, setPhase] = useState<ActionPhase>(\"idle\");\n  const [runCount, setRunCount] = useState(0);\n\n  const handleTrigger = () => {\n    if (phase === \"loading\") return;\n    if (phase !== \"idle\") {\n      setPhase(\"idle\");\n      return;\n    }\n\n    setPhase(\"loading\");\n    const nextRun = runCount + 1;\n    setRunCount(nextRun);\n\n    setTimeout(() => {\n      if (simulateError && nextRun % 2 === 0) {\n        setPhase(\"error\");\n      } else {\n        setPhase(\"success\");\n      }\n      setTimeout(() => {\n        setPhase(\"idle\");\n      }, 1800);\n    }, 950);\n  };\n\n  return (\n    <motion.button\n      layout\n      type=\"button\"\n      aria-live=\"polite\"\n      onClick={handleTrigger}\n      animate={\n        phase === \"error\" && !shouldReduceMotion\n          ? { x: [0, -7, 7, -4, 4, 0] }\n          : { x: 0 }\n      }\n      transition={\n        shouldReduceMotion\n          ? { duration: 0.01 }\n          : { type: \"spring\", stiffness, damping }\n      }\n      className={cn(\n        \"relative inline-flex h-12 items-center justify-center overflow-hidden rounded-full border px-6 text-xs font-semibold shadow-sm transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-black focus-visible:ring-offset-2 dark:focus-visible:ring-white\",\n        phase === \"idle\" &&\n          \"border-black bg-black text-white hover:opacity-90 dark:border-white dark:bg-white dark:text-black\",\n        phase === \"loading\" &&\n          \"border-neutral-300 bg-neutral-100 text-neutral-700 dark:border-[#262626] dark:bg-[#141414] dark:text-neutral-300\",\n        phase === \"success\" &&\n          \"border-black bg-white text-black dark:border-white dark:bg-[#0D0D0D] dark:text-white\",\n        phase === \"error\" &&\n          \"border-neutral-800 bg-neutral-900 text-white dark:border-neutral-300 dark:bg-neutral-200 dark:text-black\",\n        className\n      )}\n    >\n      <AnimatePresence mode=\"popLayout\" initial={false}>\n        {phase === \"idle\" && (\n          <motion.span\n            key=\"idle\"\n            initial={{ opacity: 0, y: 10 }}\n            animate={{ opacity: 1, y: 0 }}\n            exit={{ opacity: 0, y: -10 }}\n            transition={{ duration: 0.15 }}\n            className=\"inline-flex items-center gap-2 whitespace-nowrap\"\n          >\n            <span>{idleLabel}</span>\n            <ArrowRight className=\"h-3.5 w-3.5\" />\n          </motion.span>\n        )}\n\n        {phase === \"loading\" && (\n          <motion.span\n            key=\"loading\"\n            initial={{ opacity: 0, y: 10 }}\n            animate={{ opacity: 1, y: 0 }}\n            exit={{ opacity: 0, y: -10 }}\n            transition={{ duration: 0.15 }}\n            className=\"inline-flex items-center gap-2 whitespace-nowrap\"\n          >\n            <Loader2 className=\"h-3.5 w-3.5 animate-spin\" />\n            <span>{loadingLabel}</span>\n          </motion.span>\n        )}\n\n        {phase === \"success\" && (\n          <motion.span\n            key=\"success\"\n            initial={{ opacity: 0, scale: 0.85 }}\n            animate={{ opacity: 1, scale: 1 }}\n            exit={{ opacity: 0, scale: 0.85 }}\n            transition={{ type: \"spring\", stiffness: 420, damping: 22 }}\n            className=\"inline-flex items-center gap-2 whitespace-nowrap\"\n          >\n            <Check className=\"h-4 w-4\" />\n            <span>{successLabel}</span>\n          </motion.span>\n        )}\n\n        {phase === \"error\" && (\n          <motion.span\n            key=\"error\"\n            initial={{ opacity: 0, scale: 0.85 }}\n            animate={{ opacity: 1, scale: 1 }}\n            exit={{ opacity: 0, scale: 0.85 }}\n            transition={{ duration: 0.15 }}\n            className=\"inline-flex items-center gap-2 whitespace-nowrap\"\n          >\n            <AlertTriangle className=\"h-3.5 w-3.5\" />\n            <span>Build Failed • Retry</span>\n          </motion.span>\n        )}\n      </AnimatePresence>\n    </motion.button>\n  );\n}\n\nexport default MorphingActionButton;\n",
          "type": "registry:ui",
          "target": "components/ui/morphing-action-button.tsx"
        },
        {
          "path": "lib/utils.ts",
          "content": "import { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...inputs: ClassValue[]) {\n  return twMerge(clsx(inputs));\n}\n\nexport async function copyToClipboard(text: string): Promise<boolean> {\n  if (typeof window === \"undefined\") return false;\n\n  try {\n    if (navigator.clipboard && window.isSecureContext) {\n      await navigator.clipboard.writeText(text);\n      return true;\n    }\n\n    const textArea = document.createElement(\"textarea\");\n    textArea.value = text;\n    textArea.style.position = \"fixed\";\n    textArea.style.left = \"-999999px\";\n    textArea.style.top = \"-999999px\";\n    document.body.appendChild(textArea);\n    textArea.focus();\n    textArea.select();\n    const succeeded = document.execCommand(\"copy\");\n    textArea.remove();\n    return succeeded;\n  } catch {\n    return false;\n  }\n}\n",
          "type": "registry:lib",
          "target": "lib/utils.ts"
        }
      ]
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "morphing-dialog",
      "type": "registry:ui",
      "title": "Morphing Dialog",
      "author": "Rishabh Bose <https://theb0se.vercel.app/>",
      "description": "Origin-morphing modal overlay that expands seamlessly from its trigger button bounding box with spring layout projection and vertical drag-to-dismiss.",
      "dependencies": [
        "framer-motion",
        "lucide-react",
        "clsx",
        "tailwind-merge"
      ],
      "files": [
        {
          "path": "components/ui/morphing-dialog.tsx",
          "content": "\"use client\";\n\nimport React, { useEffect, useId, useRef, useState } from \"react\";\nimport {\n  AnimatePresence,\n  motion,\n  useReducedMotion,\n  type PanInfo,\n} from \"framer-motion\";\nimport { Sparkles, X, ArrowUpRight } from \"lucide-react\";\nimport { cn } from \"@/lib/utils\";\n\nexport interface MorphingDialogProps {\n  /** Trigger button title text. Default: \"Inspect Spring Telemetry\" */\n  triggerTitle?: string;\n  /** Subtitle shown inside the compact trigger card. Default: \"Click to expand shared-layout surface\" */\n  triggerSubtitle?: string;\n  /** Modal dialog heading. Default: \"Hooke's Law Telemetry Architecture\" */\n  dialogTitle?: string;\n  /** Modal dialog body description. */\n  dialogDescription?: string;\n  /** Controlled open state */\n  open?: boolean;\n  /** Callback when open state changes */\n  onOpenChange?: (open: boolean) => void;\n  /** Spring stiffness coefficient for shared layout projection. Default: 290 */\n  stiffness?: number;\n  /** Spring damping coefficient for shared layout projection. Default: 26 */\n  damping?: number;\n  /** Optional custom content inside the expanded dialog body */\n  children?: React.ReactNode;\n  className?: string;\n}\n\nexport function MorphingDialog({\n  triggerTitle = \"Inspect Spring Telemetry\",\n  triggerSubtitle = \"Click to expand shared-layout surface\",\n  dialogTitle = \"Hooke's Law Telemetry Architecture\",\n  dialogDescription = \"Every BoseUI overlay morphs directly from the bounding box of its origin trigger using GPU-accelerated layout projection, complete with vertical drag-to-dismiss elasticity.\",\n  open: controlledOpen,\n  onOpenChange,\n  stiffness = 290,\n  damping = 26,\n  children,\n  className,\n}: MorphingDialogProps) {\n  const shouldReduceMotion = useReducedMotion() ?? false;\n  const uniqueId = useId();\n  const layoutId = `morphing-dialog-${uniqueId}`;\n\n  const [internalOpen, setInternalOpen] = useState(false);\n  const isOpen = controlledOpen !== undefined ? controlledOpen : internalOpen;\n\n  const triggerRef = useRef<HTMLButtonElement | null>(null);\n  const closeButtonRef = useRef<HTMLButtonElement | null>(null);\n\n  const setOpen = (next: boolean) => {\n    if (controlledOpen === undefined) {\n      setInternalOpen(next);\n    }\n    onOpenChange?.(next);\n    if (!next) {\n      requestAnimationFrame(() => {\n        triggerRef.current?.focus();\n      });\n    }\n  };\n\n  useEffect(() => {\n    if (!isOpen) return;\n\n    const timer = requestAnimationFrame(() => {\n      closeButtonRef.current?.focus();\n    });\n\n    const handleKeyDown = (e: KeyboardEvent) => {\n      if (e.key === \"Escape\") {\n        e.preventDefault();\n        setOpen(false);\n      }\n    };\n\n    window.addEventListener(\"keydown\", handleKeyDown);\n    return () => {\n      cancelAnimationFrame(timer);\n      window.removeEventListener(\"keydown\", handleKeyDown);\n    };\n  });\n\n  const handleDragEnd = (\n    _event: MouseEvent | TouchEvent | PointerEvent,\n    info: PanInfo\n  ) => {\n    if (Math.abs(info.offset.y) > 85 || Math.abs(info.velocity.y) > 420) {\n      setOpen(false);\n    }\n  };\n\n  const springConfig = shouldReduceMotion\n    ? { duration: 0.01 }\n    : { type: \"spring\" as const, stiffness, damping };\n\n  return (\n    <div className={cn(\"relative inline-block\", className)}>\n      {/* Origin Trigger Card */}\n      <motion.button\n        ref={triggerRef}\n        type=\"button\"\n        layoutId={layoutId}\n        onClick={() => setOpen(true)}\n        aria-haspopup=\"dialog\"\n        aria-expanded={isOpen}\n        transition={springConfig}\n        className=\"group flex items-center gap-3.5 rounded-2xl border border-neutral-200 bg-white px-5 py-4 text-left shadow-sm transition-colors hover:border-black focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-black dark:border-[#222222] dark:bg-[#0A0A0A] dark:hover:border-white dark:focus-visible:ring-white\"\n      >\n        <motion.div\n          layoutId={`${layoutId}-icon`}\n          transition={springConfig}\n          className=\"flex h-10 w-10 shrink-0 items-center justify-center rounded-xl border border-neutral-200 bg-neutral-50 text-black dark:border-[#262626] dark:bg-[#141414] dark:text-white\"\n        >\n          <Sparkles className=\"h-4 w-4\" />\n        </motion.div>\n\n        <div className=\"pr-2\">\n          <motion.div\n            layoutId={`${layoutId}-title`}\n            transition={springConfig}\n            className=\"text-sm font-semibold text-black dark:text-white\"\n          >\n            {triggerTitle}\n          </motion.div>\n          <motion.div\n            layoutId={`${layoutId}-subtitle`}\n            transition={springConfig}\n            className=\"mt-0.5 text-xs text-neutral-500 dark:text-neutral-400\"\n          >\n            {triggerSubtitle}\n          </motion.div>\n        </div>\n\n        <ArrowUpRight className=\"ml-auto h-4 w-4 text-neutral-400 transition-transform group-hover:-translate-y-0.5 group-hover:translate-x-0.5 group-hover:text-black dark:group-hover:text-white\" />\n      </motion.button>\n\n      {/* Shared-Element Expanded Modal Overlay */}\n      <AnimatePresence>\n        {isOpen && (\n          <div className=\"fixed inset-0 z-50 flex items-center justify-center p-4\">\n            {/* Backdrop */}\n            <motion.div\n              initial={{ opacity: 0 }}\n              animate={{ opacity: 1 }}\n              exit={{ opacity: 0 }}\n              transition={{ duration: 0.18 }}\n              onClick={() => setOpen(false)}\n              aria-hidden=\"true\"\n              className=\"fixed inset-0 bg-black/50 backdrop-blur-sm\"\n            />\n\n            {/* Dialog Surface */}\n            <motion.div\n              role=\"dialog\"\n              aria-modal=\"true\"\n              aria-labelledby={`${uniqueId}-heading`}\n              aria-describedby={`${uniqueId}-desc`}\n              layoutId={layoutId}\n              transition={springConfig}\n              drag={shouldReduceMotion ? false : \"y\"}\n              dragConstraints={{ top: 0, bottom: 0 }}\n              dragElastic={0.35}\n              onDragEnd={handleDragEnd}\n              className=\"relative z-10 w-full max-w-md overflow-hidden rounded-3xl border border-neutral-200 bg-white p-6 text-left shadow-2xl dark:border-[#262626] dark:bg-[#0D0D0D]\"\n            >\n              {/* Drag Handle Indicator */}\n              <div\n                aria-hidden=\"true\"\n                className=\"mx-auto mb-4 h-1 w-10 rounded-full bg-neutral-200 dark:bg-[#262626]\"\n              />\n\n              <div className=\"flex items-start justify-between gap-4\">\n                <div className=\"flex items-center gap-3\">\n                  <motion.div\n                    layoutId={`${layoutId}-icon`}\n                    transition={springConfig}\n                    className=\"flex h-10 w-10 shrink-0 items-center justify-center rounded-xl border border-neutral-200 bg-neutral-50 text-black dark:border-[#262626] dark:bg-[#141414] dark:text-white\"\n                  >\n                    <Sparkles className=\"h-4 w-4\" />\n                  </motion.div>\n                  <div>\n                    <motion.h3\n                      id={`${uniqueId}-heading`}\n                      layoutId={`${layoutId}-title`}\n                      transition={springConfig}\n                      className=\"text-base font-semibold text-black dark:text-white\"\n                    >\n                      {dialogTitle}\n                    </motion.h3>\n                    <motion.p\n                      layoutId={`${layoutId}-subtitle`}\n                      transition={springConfig}\n                      className=\"text-xs text-neutral-500 dark:text-neutral-400\"\n                    >\n                      Shared-element projection • Drag vertically to dismiss\n                    </motion.p>\n                  </div>\n                </div>\n\n                <button\n                  ref={closeButtonRef}\n                  type=\"button\"\n                  aria-label=\"Close dialog\"\n                  onClick={() => setOpen(false)}\n                  className=\"flex h-8 w-8 items-center justify-center rounded-full border border-neutral-200 text-neutral-500 transition-colors hover:border-black hover:text-black focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-black dark:border-[#262626] dark:hover:border-white dark:hover:text-white dark:focus-visible:ring-white\"\n                >\n                  <X className=\"h-4 w-4\" />\n                </button>\n              </div>\n\n              <motion.div\n                initial={{ opacity: 0, y: 6 }}\n                animate={{ opacity: 1, y: 0 }}\n                exit={{ opacity: 0, y: 4 }}\n                transition={{ delay: 0.05, duration: 0.18 }}\n                className=\"mt-5\"\n              >\n                <p\n                  id={`${uniqueId}-desc`}\n                  className=\"text-xs leading-relaxed text-neutral-600 dark:text-neutral-300\"\n                >\n                  {dialogDescription}\n                </p>\n\n                {children || (\n                  <div className=\"mt-4 grid grid-cols-3 gap-2 rounded-2xl border border-neutral-200 bg-neutral-50 p-3 dark:border-[#1F1F1F] dark:bg-[#141414]\">\n                    <div>\n                      <div className=\"text-[10px] uppercase tracking-wider text-neutral-400\">\n                        Stiffness\n                      </div>\n                      <div className=\"mt-0.5 font-mono text-xs font-semibold text-black dark:text-white\">\n                        {stiffness} N/m\n                      </div>\n                    </div>\n                    <div>\n                      <div className=\"text-[10px] uppercase tracking-wider text-neutral-400\">\n                        Damping\n                      </div>\n                      <div className=\"mt-0.5 font-mono text-xs font-semibold text-black dark:text-white\">\n                        {damping} Ns/m\n                      </div>\n                    </div>\n                    <div>\n                      <div className=\"text-[10px] uppercase tracking-wider text-neutral-400\">\n                        Dismiss\n                      </div>\n                      <div className=\"mt-0.5 font-mono text-xs font-semibold text-black dark:text-white\">\n                        &gt;85px / Esc\n                      </div>\n                    </div>\n                  </div>\n                )}\n\n                <div className=\"mt-5 flex justify-end\">\n                  <button\n                    type=\"button\"\n                    onClick={() => setOpen(false)}\n                    className=\"rounded-xl bg-black px-4 py-2 text-xs font-semibold text-white transition-opacity hover:opacity-90 dark:bg-white dark:text-black\"\n                  >\n                    Done\n                  </button>\n                </div>\n              </motion.div>\n            </motion.div>\n          </div>\n        )}\n      </AnimatePresence>\n    </div>\n  );\n}\n\nexport default MorphingDialog;\n",
          "type": "registry:ui",
          "target": "components/ui/morphing-dialog.tsx"
        },
        {
          "path": "lib/utils.ts",
          "content": "import { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...inputs: ClassValue[]) {\n  return twMerge(clsx(inputs));\n}\n\nexport async function copyToClipboard(text: string): Promise<boolean> {\n  if (typeof window === \"undefined\") return false;\n\n  try {\n    if (navigator.clipboard && window.isSecureContext) {\n      await navigator.clipboard.writeText(text);\n      return true;\n    }\n\n    const textArea = document.createElement(\"textarea\");\n    textArea.value = text;\n    textArea.style.position = \"fixed\";\n    textArea.style.left = \"-999999px\";\n    textArea.style.top = \"-999999px\";\n    document.body.appendChild(textArea);\n    textArea.focus();\n    textArea.select();\n    const succeeded = document.execCommand(\"copy\");\n    textArea.remove();\n    return succeeded;\n  } catch {\n    return false;\n  }\n}\n",
          "type": "registry:lib",
          "target": "lib/utils.ts"
        }
      ]
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "morphing-mega-menu",
      "type": "registry:ui",
      "title": "Morphing Mega Menu",
      "author": "Rishabh Bose <https://theb0se.vercel.app/>",
      "description": "Stripe-style floating mega menu popover that fluidly glides across navigation links with spring physics, morphing width, height, and caret position synchronously.",
      "dependencies": [
        "framer-motion",
        "lucide-react",
        "clsx",
        "tailwind-merge"
      ],
      "files": [
        {
          "path": "components/ui/morphing-mega-menu.tsx",
          "content": "\"use client\";\n\nimport React, { useState, useRef, useEffect } from \"react\";\nimport { motion, AnimatePresence } from \"framer-motion\";\nimport {\n  CreditCard,\n  Receipt,\n  Network,\n  Smartphone,\n  Layers,\n  Building2,\n  ShoppingCart,\n  Globe2,\n  BookOpen,\n  Code2,\n  Terminal,\n  Cpu,\n  ArrowRight,\n  Sparkles,\n  ChevronRight,\n  ShieldCheck,\n  Zap,\n} from \"lucide-react\";\nimport { cn } from \"@/lib/utils\";\n\nexport interface NavItem {\n  id: string;\n  label: string;\n}\n\nexport interface MorphingMegaMenuProps {\n  className?: string;\n  stiffness?: number;\n  damping?: number;\n  embedded?: boolean;\n}\n\nconst NAV_ITEMS: NavItem[] = [\n  { id: \"products\", label: \"Products\" },\n  { id: \"solutions\", label: \"Solutions\" },\n  { id: \"developers\", label: \"Developers\" },\n];\n\nexport function MorphingMegaMenu({\n  className,\n  stiffness = 380,\n  damping = 30,\n  embedded = false,\n}: MorphingMegaMenuProps) {\n  const [activeTab, setActiveTab] = useState<string | null>(\"products\");\n  const [navCoords, setNavCoords] = useState<{\n    left: number;\n    width: number;\n    height: number;\n    arrowX: number;\n  }>({ left: 0, width: 480, height: 320, arrowX: 100 });\n\n  const navRef = useRef<HTMLDivElement>(null);\n  const tabRefs = useRef<{ [key: string]: HTMLButtonElement | null }>({});\n  const panelRefs = useRef<{ [key: string]: HTMLDivElement | null }>({});\n\n  const [activeStiffness, setActiveStiffness] = useState(stiffness);\n  const [activeDamping, setActiveDamping] = useState(damping);\n  const [pinOpen, setPinOpen] = useState(false);\n\n  // Measure and align popover when active tab changes\n  useEffect(() => {\n    if (!activeTab || !navRef.current) return;\n    const tabEl = tabRefs.current[activeTab];\n    const panelEl = panelRefs.current[activeTab];\n    const navRect = navRef.current.getBoundingClientRect();\n\n    if (tabEl && panelEl) {\n      const tabRect = tabEl.getBoundingClientRect();\n      const panelRect = panelEl.getBoundingClientRect();\n\n      const tabCenter = tabRect.left + tabRect.width / 2 - navRect.left;\n      const targetLeft = Math.max(16, tabCenter - panelRect.width / 2);\n      const arrowX = tabCenter - targetLeft;\n\n      setNavCoords({\n        left: targetLeft,\n        width: panelRect.width,\n        height: panelRect.height,\n        arrowX,\n      });\n    }\n  }, [activeTab]);\n\n  const handleMouseEnterTab = (id: string) => {\n    setActiveTab(id);\n  };\n\n  if (embedded) {\n    return (\n      <div\n        ref={navRef}\n        onMouseLeave={() => {\n          if (!pinOpen) setActiveTab(null);\n        }}\n        className={cn(\"relative flex items-center\", className)}\n      >\n        {/* Main Nav Items */}\n        <nav className=\"flex items-center space-x-1\" role=\"menubar\">\n          {NAV_ITEMS.map((item) => {\n            const isActive = activeTab === item.id;\n            return (\n              <button\n                key={item.id}\n                ref={(el) => {\n                  tabRefs.current[item.id] = el;\n                }}\n                onMouseEnter={() => handleMouseEnterTab(item.id)}\n                onClick={() => setActiveTab(activeTab === item.id ? null : item.id)}\n                aria-expanded={isActive}\n                className={cn(\n                  \"relative px-4 py-1.5 text-sm font-medium transition-colors rounded-lg\",\n                  isActive\n                    ? \"text-white\"\n                    : \"text-neutral-400 hover:text-neutral-200\"\n                )}\n              >\n                {item.label}\n                {isActive && (\n                  <motion.div\n                    layoutId=\"navTabPillEmbedded\"\n                    className=\"absolute inset-0 rounded-lg bg-neutral-800/80 -z-10\"\n                    transition={{\n                      type: \"spring\",\n                      stiffness: activeStiffness,\n                      damping: activeDamping,\n                    }}\n                  />\n                )}\n              </button>\n            );\n          })}\n        </nav>\n\n        {/* Morphing Popover Floating Container */}\n        <AnimatePresence>\n          {activeTab && (\n            <motion.div\n              initial={false}\n              animate={{\n                x: navCoords.left,\n                width: navCoords.width,\n                height: navCoords.height,\n                opacity: 1,\n                scale: 1,\n              }}\n              exit={{ opacity: 0, scale: 0.95 }}\n              transition={{\n                type: \"spring\",\n                stiffness: activeStiffness,\n                damping: activeDamping,\n              }}\n              className=\"absolute top-full mt-3 left-0 z-50 overflow-hidden rounded-2xl border border-neutral-700/60 bg-[#0d101f]/95 shadow-2xl backdrop-blur-2xl\"\n              style={{\n                boxShadow:\n                  \"0 20px 50px -10px rgba(0,0,0,0.7), 0 0 0 1px rgba(255,255,255,0.06)\",\n              }}\n            >\n              {/* Synchronized Caret / Arrow */}\n              <motion.div\n                className=\"absolute -top-1.5 z-50 h-3 w-3 rotate-45 border-l border-t border-neutral-700/60 bg-[#0d101f]\"\n                animate={{ x: navCoords.arrowX - 6 }}\n                transition={{\n                  type: \"spring\",\n                  stiffness: activeStiffness,\n                  damping: activeDamping,\n                }}\n              />\n\n              {/* Dropdown Panels Container */}\n              <div className=\"relative overflow-hidden\">\n                <AnimatePresence mode=\"wait\">\n                  {activeTab === \"products\" && (\n                    <motion.div\n                      key=\"products\"\n                      ref={(el) => {\n                        panelRefs.current[\"products\"] = el;\n                      }}\n                      initial={{ opacity: 0, x: -16 }}\n                      animate={{ opacity: 1, x: 0 }}\n                      exit={{ opacity: 0, x: 16 }}\n                      transition={{ duration: 0.18 }}\n                      className=\"w-[520px] p-6\"\n                    >\n                      <div className=\"text-xs font-semibold uppercase tracking-wider text-neutral-400 mb-4 flex items-center gap-2\">\n                        <Layers className=\"h-3.5 w-3.5 text-indigo-400\" />\n                        <span>Core Infrastructure</span>\n                      </div>\n                      <div className=\"grid grid-cols-2 gap-4\">\n                        <PanelItem\n                          icon={<CreditCard className=\"h-5 w-5 text-indigo-400\" />}\n                          title=\"Payments\"\n                          description=\"Online card payments and multi-currency checkout\"\n                        />\n                        <PanelItem\n                          icon={<Receipt className=\"h-5 w-5 text-emerald-400\" />}\n                          title=\"Billing\"\n                          description=\"Smart subscription lifecycles and usage metering\"\n                        />\n                        <PanelItem\n                          icon={<Network className=\"h-5 w-5 text-cyan-400\" />}\n                          title=\"Connect\"\n                          description=\"Marketplace payouts and seller onboarding\"\n                        />\n                        <PanelItem\n                          icon={<Smartphone className=\"h-5 w-5 text-violet-400\" />}\n                          title=\"Terminal\"\n                          description=\"In-person POS readers and hardware integration\"\n                        />\n                      </div>\n                    </motion.div>\n                  )}\n\n                  {activeTab === \"solutions\" && (\n                    <motion.div\n                      key=\"solutions\"\n                      ref={(el) => {\n                        panelRefs.current[\"solutions\"] = el;\n                      }}\n                      initial={{ opacity: 0, x: -16 }}\n                      animate={{ opacity: 1, x: 0 }}\n                      exit={{ opacity: 0, x: 16 }}\n                      transition={{ duration: 0.18 }}\n                      className=\"w-[480px] p-6\"\n                    >\n                      <div className=\"text-xs font-semibold uppercase tracking-wider text-neutral-400 mb-4 flex items-center gap-2\">\n                        <Sparkles className=\"h-3.5 w-3.5 text-amber-400\" />\n                        <span>Engineered by Industry</span>\n                      </div>\n                      <div className=\"space-y-3\">\n                        <PanelItem\n                          icon={<Building2 className=\"h-5 w-5 text-amber-400\" />}\n                          title=\"SaaS & Subscription\"\n                          description=\"Predictable recurring revenues and automated billing\"\n                        />\n                        <PanelItem\n                          icon={<Globe2 className=\"h-5 w-5 text-blue-400\" />}\n                          title=\"Global Platforms\"\n                          description=\"Multi-sided marketplaces with split payments\"\n                        />\n                        <PanelItem\n                          icon={<ShoppingCart className=\"h-5 w-5 text-rose-400\" />}\n                          title=\"E-Commerce Stores\"\n                          description=\"Frictionless conversion and instant localized checkout\"\n                        />\n                      </div>\n                    </motion.div>\n                  )}\n\n                  {activeTab === \"developers\" && (\n                    <motion.div\n                      key=\"developers\"\n                      ref={(el) => {\n                        panelRefs.current[\"developers\"] = el;\n                      }}\n                      initial={{ opacity: 0, x: -16 }}\n                      animate={{ opacity: 1, x: 0 }}\n                      exit={{ opacity: 0, x: 16 }}\n                      transition={{ duration: 0.18 }}\n                      className=\"w-[500px] p-6\"\n                    >\n                      <div className=\"text-xs font-semibold uppercase tracking-wider text-neutral-400 mb-4 flex items-center gap-2\">\n                        <Code2 className=\"h-3.5 w-3.5 text-emerald-400\" />\n                        <span>Documentation & APIs</span>\n                      </div>\n                      <div className=\"grid grid-cols-2 gap-4\">\n                        <PanelItem\n                          icon={<BookOpen className=\"h-5 w-5 text-emerald-400\" />}\n                          title=\"Documentation\"\n                          description=\"Full architectural guides and code quickstarts\"\n                        />\n                        <PanelItem\n                          icon={<Terminal className=\"h-5 w-5 text-indigo-400\" />}\n                          title=\"API Reference\"\n                          description=\"Deterministic REST endpoints and SDK client libraries\"\n                        />\n                        <PanelItem\n                          icon={<Cpu className=\"h-5 w-5 text-purple-400\" />}\n                          title=\"Webhooks & Events\"\n                          description=\"Real-time distributed stream notifications\"\n                        />\n                        <PanelItem\n                          icon={<Zap className=\"h-5 w-5 text-yellow-400\" />}\n                          title=\"Sandbox Playground\"\n                          description=\"Test API keys and test credit card numbers\"\n                        />\n                      </div>\n                    </motion.div>\n                  )}\n                </AnimatePresence>\n              </div>\n            </motion.div>\n          )}\n        </AnimatePresence>\n      </div>\n    );\n  }\n\n  return (\n    <div\n      data-fullscreen-scroll\n      className={cn(\n        \"relative w-full min-h-[520px] overflow-hidden rounded-2xl border border-neutral-800 bg-[#070913] p-6 text-white flex flex-col justify-between shadow-2xl selection:bg-indigo-500/30\",\n        className\n      )}\n    >\n      {/* Background ambient glow */}\n      <div className=\"pointer-events-none absolute inset-0 overflow-hidden\">\n        <div className=\"absolute -top-32 left-1/2 h-96 w-[640px] -translate-x-1/2 rounded-full bg-gradient-to-tr from-indigo-600/20 via-purple-600/15 to-cyan-500/10 blur-[120px]\" />\n        <div className=\"absolute -bottom-32 left-1/4 h-80 w-[420px] rounded-full bg-blue-600/10 blur-[100px]\" />\n      </div>\n\n      {/* Top Header / Demo Navbar Area */}\n      <div className=\"relative z-20 w-full max-w-4xl mx-auto pt-2\">\n        <div className=\"flex items-center justify-between pb-6 border-b border-neutral-800/80\">\n          <div className=\"flex items-center gap-2\">\n            <div className=\"h-8 w-8 rounded-lg bg-gradient-to-br from-indigo-500 to-violet-600 flex items-center justify-center shadow-lg shadow-indigo-500/30\">\n              <Zap className=\"h-4 w-4 text-white\" />\n            </div>\n            <span className=\"font-semibold text-lg tracking-tight bg-gradient-to-r from-white via-neutral-200 to-neutral-400 bg-clip-text text-transparent\">\n              PulseEngine\n            </span>\n            <span className=\"text-xs px-2 py-0.5 rounded-full bg-indigo-500/10 border border-indigo-500/20 text-indigo-300 font-mono\">\n              v3.2\n            </span>\n          </div>\n\n          <div className=\"flex items-center gap-3 text-xs text-neutral-400\">\n            <span className=\"hidden sm:inline\">Stripe-style morphing popover</span>\n            <button\n              onClick={() => setPinOpen(!pinOpen)}\n              className={cn(\n                \"px-2.5 py-1 rounded-md text-xs font-medium transition-colors border\",\n                pinOpen\n                  ? \"bg-indigo-500/20 border-indigo-500/40 text-indigo-300\"\n                  : \"bg-neutral-800/60 border-neutral-700/50 text-neutral-400 hover:text-white\"\n              )}\n            >\n              {pinOpen ? \"Pinned Open\" : \"Pin Menu\"}\n            </button>\n          </div>\n        </div>\n\n        {/* Navigation Bar */}\n        <div\n          ref={navRef}\n          onMouseLeave={() => {\n            if (!pinOpen) setActiveTab(null);\n          }}\n          className=\"relative mt-6 flex items-center justify-between rounded-xl border border-neutral-800 bg-neutral-900/60 px-4 py-2.5 backdrop-blur-xl\"\n        >\n          {/* Main Nav Items */}\n          <nav className=\"flex items-center space-x-1\" role=\"menubar\">\n            {NAV_ITEMS.map((item) => {\n              const isActive = activeTab === item.id;\n              return (\n                <button\n                  key={item.id}\n                  ref={(el) => {\n                    tabRefs.current[item.id] = el;\n                  }}\n                  onMouseEnter={() => handleMouseEnterTab(item.id)}\n                  onClick={() => setActiveTab(item.id)}\n                  aria-expanded={isActive}\n                  className={cn(\n                    \"relative px-4 py-1.5 text-sm font-medium transition-colors rounded-lg\",\n                    isActive\n                      ? \"text-white\"\n                      : \"text-neutral-400 hover:text-neutral-200\"\n                  )}\n                >\n                  {item.label}\n                  {isActive && (\n                    <motion.div\n                      layoutId=\"navTabPill\"\n                      className=\"absolute inset-0 rounded-lg bg-neutral-800/80 -z-10\"\n                      transition={{\n                        type: \"spring\",\n                        stiffness: activeStiffness,\n                        damping: activeDamping,\n                      }}\n                    />\n                  )}\n                </button>\n              );\n            })}\n          </nav>\n\n          {/* Action CTAs */}\n          <div className=\"flex items-center space-x-3 text-sm\">\n            <button className=\"text-neutral-400 hover:text-white text-xs font-medium transition-colors\">\n              Sign in\n            </button>\n            <button className=\"px-3 py-1.5 rounded-lg bg-gradient-to-r from-indigo-500 to-violet-600 hover:from-indigo-400 hover:to-violet-500 text-white text-xs font-semibold shadow-md shadow-indigo-500/20 flex items-center gap-1.5 transition-all\">\n              <span>Start Free</span>\n              <ArrowRight className=\"h-3 w-3\" />\n            </button>\n          </div>\n\n          {/* Morphing Popover Floating Container */}\n          <AnimatePresence>\n            {activeTab && (\n              <motion.div\n                initial={false}\n                animate={{\n                  x: navCoords.left,\n                  width: navCoords.width,\n                  height: navCoords.height,\n                  opacity: 1,\n                  scale: 1,\n                }}\n                exit={{ opacity: 0, scale: 0.95 }}\n                transition={{\n                  type: \"spring\",\n                  stiffness: activeStiffness,\n                  damping: activeDamping,\n                }}\n                className=\"absolute top-full mt-3 left-0 z-50 overflow-hidden rounded-2xl border border-neutral-700/60 bg-[#0d101f]/95 shadow-2xl backdrop-blur-2xl\"\n                style={{\n                  boxShadow:\n                    \"0 20px 50px -10px rgba(0,0,0,0.7), 0 0 0 1px rgba(255,255,255,0.06)\",\n                }}\n              >\n                {/* Synchronized Caret / Arrow */}\n                <motion.div\n                  className=\"absolute -top-1.5 z-50 h-3 w-3 rotate-45 border-l border-t border-neutral-700/60 bg-[#0d101f]\"\n                  animate={{ x: navCoords.arrowX - 6 }}\n                  transition={{\n                    type: \"spring\",\n                    stiffness: activeStiffness,\n                    damping: activeDamping,\n                  }}\n                />\n\n                {/* Dropdown Panels Container */}\n                <div className=\"relative overflow-hidden\">\n                  <AnimatePresence mode=\"wait\">\n                    {activeTab === \"products\" && (\n                      <motion.div\n                        key=\"products\"\n                        ref={(el) => {\n                          panelRefs.current[\"products\"] = el;\n                        }}\n                        initial={{ opacity: 0, x: -16 }}\n                        animate={{ opacity: 1, x: 0 }}\n                        exit={{ opacity: 0, x: 16 }}\n                        transition={{ duration: 0.18 }}\n                        className=\"w-[520px] p-6\"\n                      >\n                        <div className=\"text-xs font-semibold uppercase tracking-wider text-neutral-400 mb-4 flex items-center gap-2\">\n                          <Layers className=\"h-3.5 w-3.5 text-indigo-400\" />\n                          <span>Core Infrastructure</span>\n                        </div>\n                        <div className=\"grid grid-cols-2 gap-4\">\n                          <PanelItem\n                            icon={<CreditCard className=\"h-5 w-5 text-indigo-400\" />}\n                            title=\"Payments\"\n                            description=\"Online card payments and multi-currency checkout\"\n                          />\n                          <PanelItem\n                            icon={<Receipt className=\"h-5 w-5 text-emerald-400\" />}\n                            title=\"Billing\"\n                            description=\"Smart subscription lifecycles and usage metering\"\n                          />\n                          <PanelItem\n                            icon={<Network className=\"h-5 w-5 text-cyan-400\" />}\n                            title=\"Connect\"\n                            description=\"Marketplace payouts and seller onboarding\"\n                          />\n                          <PanelItem\n                            icon={<Smartphone className=\"h-5 w-5 text-amber-400\" />}\n                            title=\"Terminal\"\n                            description=\"Custom in-person POS hardware and EMV tap\"\n                          />\n                        </div>\n\n                        <div className=\"mt-5 pt-4 border-t border-neutral-800/80 flex items-center justify-between text-xs text-neutral-400\">\n                          <span className=\"flex items-center gap-1.5 text-indigo-300 font-medium\">\n                            <Sparkles className=\"h-3.5 w-3.5\" />\n                            Radar Fraud Defense included\n                          </span>\n                          <a\n                            href=\"#all-products\"\n                            className=\"text-neutral-300 hover:text-white flex items-center gap-1 group\"\n                          >\n                            <span>Explore all 24 products</span>\n                            <ChevronRight className=\"h-3 w-3 group-hover:translate-x-0.5 transition-transform\" />\n                          </a>\n                        </div>\n                      </motion.div>\n                    )}\n\n                    {activeTab === \"solutions\" && (\n                      <motion.div\n                        key=\"solutions\"\n                        ref={(el) => {\n                          panelRefs.current[\"solutions\"] = el;\n                        }}\n                        initial={{ opacity: 0, x: -16 }}\n                        animate={{ opacity: 1, x: 0 }}\n                        exit={{ opacity: 0, x: 16 }}\n                        transition={{ duration: 0.18 }}\n                        className=\"w-[460px] p-6\"\n                      >\n                        <div className=\"text-xs font-semibold uppercase tracking-wider text-neutral-400 mb-4 flex items-center gap-2\">\n                          <Building2 className=\"h-3.5 w-3.5 text-purple-400\" />\n                          <span>Tailored by Business Model</span>\n                        </div>\n                        <div className=\"space-y-3\">\n                          <SolutionRow\n                            icon={<Zap className=\"h-4 w-4 text-purple-400\" />}\n                            title=\"SaaS & Software\"\n                            desc=\"Optimize recurring revenue with automated dunning\"\n                          />\n                          <SolutionRow\n                            icon={<Globe2 className=\"h-4 w-4 text-blue-400\" />}\n                            title=\"Platforms & Marketplaces\"\n                            desc=\"Route splits and escrow payouts across 135+ currencies\"\n                          />\n                          <SolutionRow\n                            icon={<ShoppingCart className=\"h-4 w-4 text-pink-400\" />}\n                            title=\"Global E-commerce\"\n                            desc=\"Single-click mobile checkout with Apple Pay & Google Pay\"\n                          />\n                        </div>\n                        <div className=\"mt-4 pt-3 border-t border-neutral-800/80 text-xs text-neutral-400 flex items-center justify-between\">\n                          <span>Enterprise Tier Available</span>\n                          <a href=\"#solutions\" className=\"text-purple-400 hover:underline\">\n                            Case studies &rarr;\n                          </a>\n                        </div>\n                      </motion.div>\n                    )}\n\n                    {activeTab === \"developers\" && (\n                      <motion.div\n                        key=\"developers\"\n                        ref={(el) => {\n                          panelRefs.current[\"developers\"] = el;\n                        }}\n                        initial={{ opacity: 0, x: -16 }}\n                        animate={{ opacity: 1, x: 0 }}\n                        exit={{ opacity: 0, x: 16 }}\n                        transition={{ duration: 0.18 }}\n                        className=\"w-[490px] p-6\"\n                      >\n                        <div className=\"text-xs font-semibold uppercase tracking-wider text-neutral-400 mb-4 flex items-center gap-2\">\n                          <Code2 className=\"h-3.5 w-3.5 text-cyan-400\" />\n                          <span>Developer Tools & APIs</span>\n                        </div>\n                        <div className=\"grid grid-cols-2 gap-3\">\n                          <DevItem\n                            icon={<BookOpen className=\"h-4 w-4 text-cyan-400\" />}\n                            title=\"Documentation\"\n                            desc=\"Quickstarts & recipes\"\n                          />\n                          <DevItem\n                            icon={<Terminal className=\"h-4 w-4 text-emerald-400\" />}\n                            title=\"API Reference\"\n                            desc=\"REST & OpenAPI schemas\"\n                          />\n                          <DevItem\n                            icon={<Cpu className=\"h-4 w-4 text-violet-400\" />}\n                            title=\"Client SDKs\"\n                            desc=\"Node, Python, Go, iOS\"\n                          />\n                          <DevItem\n                            icon={<ShieldCheck className=\"h-4 w-4 text-amber-400\" />}\n                            title=\"Test Sandboxes\"\n                            desc=\"Mock clock & webhooks\"\n                          />\n                        </div>\n                        <div className=\"mt-4 pt-3 border-t border-neutral-800/80 bg-neutral-900/60 -mx-6 -mb-6 px-6 py-3 rounded-b-2xl flex items-center justify-between text-xs\">\n                          <code className=\"text-neutral-400 font-mono text-[11px]\">\n                            npm i @pulse/sdk\n                          </code>\n                          <span className=\"text-neutral-400\">99.999% SLA Uptime</span>\n                        </div>\n                      </motion.div>\n                    )}\n                  </AnimatePresence>\n                </div>\n              </motion.div>\n            )}\n          </AnimatePresence>\n        </div>\n      </div>\n\n      {/* Interactive Controls Stage Preview */}\n      <div className=\"relative z-10 mt-20 pt-6 border-t border-neutral-800/80\">\n        <div className=\"flex flex-wrap items-center justify-between gap-4 text-xs\">\n          <div className=\"flex items-center gap-2 text-neutral-400\">\n            <span className=\"font-medium text-neutral-300\">Hover / Preview Target:</span>\n            {NAV_ITEMS.map((item) => (\n              <button\n                key={item.id}\n                onClick={() => setActiveTab(item.id)}\n                className={cn(\n                  \"px-2.5 py-1 rounded-md font-mono transition-colors\",\n                  activeTab === item.id\n                    ? \"bg-indigo-600 text-white font-semibold\"\n                    : \"bg-neutral-800/70 text-neutral-400 hover:text-white\"\n                )}\n              >\n                {item.label}\n              </button>\n            ))}\n          </div>\n\n          <div className=\"flex items-center gap-4 text-neutral-400\">\n            <div className=\"flex items-center gap-2\">\n              <span>Stiffness ({activeStiffness}):</span>\n              <input\n                type=\"range\"\n                min=\"200\"\n                max=\"600\"\n                value={activeStiffness}\n                onChange={(e) => setActiveStiffness(Number(e.target.value))}\n                className=\"w-20 accent-indigo-500\"\n              />\n            </div>\n            <div className=\"flex items-center gap-2\">\n              <span>Damping ({activeDamping}):</span>\n              <input\n                type=\"range\"\n                min=\"15\"\n                max=\"50\"\n                value={activeDamping}\n                onChange={(e) => setActiveDamping(Number(e.target.value))}\n                className=\"w-20 accent-indigo-500\"\n              />\n            </div>\n          </div>\n        </div>\n      </div>\n    </div>\n  );\n}\n\nfunction PanelItem({\n  icon,\n  title,\n  description,\n}: {\n  icon: React.ReactNode;\n  title: string;\n  description: string;\n}) {\n  return (\n    <div className=\"group flex items-start gap-3 rounded-xl p-2.5 transition-colors hover:bg-neutral-800/50 cursor-pointer\">\n      <div className=\"mt-0.5 rounded-lg bg-neutral-800 p-2 text-neutral-300 group-hover:bg-neutral-700/80 transition-colors\">\n        {icon}\n      </div>\n      <div>\n        <h4 className=\"text-sm font-semibold text-neutral-100 group-hover:text-white\">\n          {title}\n        </h4>\n        <p className=\"mt-0.5 text-xs leading-relaxed text-neutral-400 line-clamp-2\">\n          {description}\n        </p>\n      </div>\n    </div>\n  );\n}\n\nfunction SolutionRow({\n  icon,\n  title,\n  desc,\n}: {\n  icon: React.ReactNode;\n  title: string;\n  desc: string;\n}) {\n  return (\n    <div className=\"group flex items-center justify-between rounded-xl p-2.5 transition-colors hover:bg-neutral-800/50 cursor-pointer\">\n      <div className=\"flex items-center gap-3\">\n        <div className=\"rounded-lg bg-neutral-800 p-2 text-neutral-300 group-hover:bg-neutral-700/80 transition-colors\">\n          {icon}\n        </div>\n        <div>\n          <h4 className=\"text-sm font-semibold text-neutral-200 group-hover:text-white\">\n            {title}\n          </h4>\n          <p className=\"text-xs text-neutral-400\">{desc}</p>\n        </div>\n      </div>\n      <ChevronRight className=\"h-4 w-4 text-neutral-500 group-hover:text-neutral-300 group-hover:translate-x-0.5 transition-transform\" />\n    </div>\n  );\n}\n\nfunction DevItem({\n  icon,\n  title,\n  desc,\n}: {\n  icon: React.ReactNode;\n  title: string;\n  desc: string;\n}) {\n  return (\n    <div className=\"group flex items-start gap-3 rounded-xl p-2.5 transition-colors hover:bg-neutral-800/50 cursor-pointer\">\n      <div className=\"mt-0.5 rounded-lg bg-neutral-800 p-2 text-neutral-300 group-hover:bg-neutral-700/80 transition-colors\">\n        {icon}\n      </div>\n      <div>\n        <h4 className=\"text-sm font-semibold text-neutral-200 group-hover:text-white\">\n          {title}\n        </h4>\n        <p className=\"mt-0.5 text-xs text-neutral-400\">{desc}</p>\n      </div>\n    </div>\n  );\n}\n\nexport default MorphingMegaMenu;\n",
          "type": "registry:ui",
          "target": "components/ui/morphing-mega-menu.tsx"
        },
        {
          "path": "lib/utils.ts",
          "content": "import { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...inputs: ClassValue[]) {\n  return twMerge(clsx(inputs));\n}\n\nexport async function copyToClipboard(text: string): Promise<boolean> {\n  if (typeof window === \"undefined\") return false;\n\n  try {\n    if (navigator.clipboard && window.isSecureContext) {\n      await navigator.clipboard.writeText(text);\n      return true;\n    }\n\n    const textArea = document.createElement(\"textarea\");\n    textArea.value = text;\n    textArea.style.position = \"fixed\";\n    textArea.style.left = \"-999999px\";\n    textArea.style.top = \"-999999px\";\n    document.body.appendChild(textArea);\n    textArea.focus();\n    textArea.select();\n    const succeeded = document.execCommand(\"copy\");\n    textArea.remove();\n    return succeeded;\n  } catch {\n    return false;\n  }\n}\n",
          "type": "registry:lib",
          "target": "lib/utils.ts"
        }
      ]
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "multi-select-tag-input",
      "type": "registry:ui",
      "title": "Multi-Select Tag Input",
      "author": "Rishabh Bose <https://theb0se.vercel.app/>",
      "description": "Interactive tag and chip input with live autocomplete suggestions, custom tag creation via Enter or comma, Backspace removal, and max-tag limits.",
      "dependencies": [
        "framer-motion",
        "lucide-react",
        "clsx",
        "tailwind-merge"
      ],
      "files": [
        {
          "path": "components/ui/multi-select-tag-input.tsx",
          "content": "\"use client\";\n\nimport React, { useState, useRef, useEffect, useId, useMemo } from \"react\";\nimport { AnimatePresence, motion, useReducedMotion } from \"framer-motion\";\nimport { X, Plus, Tag, Check } from \"lucide-react\";\nimport { cn } from \"@/lib/utils\";\n\nexport interface TagSuggestion {\n  value: string;\n  label: string;\n  category?: string;\n}\n\nexport interface MultiSelectTagInputProps {\n  /** Suggested tags shown in the dropdown */\n  suggestions?: TagSuggestion[];\n  /** Controlled array of selected tag values */\n  value?: string[];\n  /** Initial selected tag values for uncontrolled mode */\n  defaultValue?: string[];\n  /** Callback fired whenever selected tags change */\n  onChange?: (tags: string[]) => void;\n  /** Input placeholder when empty */\n  placeholder?: string;\n  /** Optional field label */\n  label?: string;\n  /** Maximum number of tags allowed. Default: 8 */\n  maxTags?: number;\n  /** Allow creating custom tags not in suggestions by pressing Enter or comma. Default: true */\n  allowCustomTags?: boolean;\n  /** Disable input and tag removal */\n  disabled?: boolean;\n  className?: string;\n}\n\nconst DEFAULT_SUGGESTIONS: TagSuggestion[] = [\n  { value: \"react\", label: \"React\", category: \"Frontend\" },\n  { value: \"typescript\", label: \"TypeScript\", category: \"Language\" },\n  { value: \"tailwind\", label: \"Tailwind CSS\", category: \"Styling\" },\n  { value: \"framer-motion\", label: \"Framer Motion\", category: \"Animation\" },\n  { value: \"nextjs\", label: \"Next.js\", category: \"Framework\" },\n  { value: \"accessibility\", label: \"Accessibility (WAI-ARIA)\", category: \"UX\" },\n  { value: \"design-systems\", label: \"Design Systems\", category: \"UI\" },\n  { value: \"graphql\", label: \"GraphQL\", category: \"API\" },\n];\n\nexport function MultiSelectTagInput({\n  suggestions = DEFAULT_SUGGESTIONS,\n  value,\n  defaultValue = [\"react\", \"typescript\", \"framer-motion\"],\n  onChange,\n  placeholder = \"Add tag or select...\",\n  label = \"Tech Stack Tags\",\n  maxTags = 8,\n  allowCustomTags = true,\n  disabled = false,\n  className,\n}: MultiSelectTagInputProps) {\n  const shouldReduceMotion = useReducedMotion() ?? false;\n  const listboxId = useId();\n  const isControlled = value !== undefined;\n\n  const [internalTags, setInternalTags] = useState<string[]>(defaultValue);\n  const selectedTags = isControlled ? value : internalTags;\n\n  const [inputValue, setInputValue] = useState(\"\");\n  const [open, setOpen] = useState(false);\n  const [activeIndex, setActiveIndex] = useState(0);\n\n  const containerRef = useRef<HTMLDivElement>(null);\n  const inputRef = useRef<HTMLInputElement>(null);\n  const listRef = useRef<HTMLDivElement>(null);\n\n  const updateTags = (next: string[]) => {\n    if (!isControlled) {\n      setInternalTags(next);\n    }\n    onChange?.(next);\n  };\n\n  const getTagLabel = (val: string) => {\n    const match = suggestions.find(\n      (s) => s.value.toLowerCase() === val.toLowerCase()\n    );\n    return match ? match.label : val;\n  };\n\n  const filteredSuggestions = useMemo(() => {\n    const q = inputValue.trim().toLowerCase();\n    return suggestions.filter((item) => {\n      const alreadySelected = selectedTags.some(\n        (t) => t.toLowerCase() === item.value.toLowerCase()\n      );\n      if (alreadySelected) return false;\n      if (!q) return true;\n      return (\n        item.label.toLowerCase().includes(q) ||\n        item.value.toLowerCase().includes(q) ||\n        (item.category?.toLowerCase().includes(q) ?? false)\n      );\n    });\n  }, [suggestions, selectedTags, inputValue]);\n\n  const isAtLimit = selectedTags.length >= maxTags;\n\n  const addTag = (rawVal: string) => {\n    if (disabled || isAtLimit) return;\n    const trimmed = rawVal.trim().replace(/,+$/, \"\");\n    if (!trimmed) return;\n\n    // Check if matches existing suggestion value or label\n    const existingSuggestion = suggestions.find(\n      (s) =>\n        s.value.toLowerCase() === trimmed.toLowerCase() ||\n        s.label.toLowerCase() === trimmed.toLowerCase()\n    );\n\n    const normalizedValue = existingSuggestion\n      ? existingSuggestion.value\n      : trimmed;\n\n    if (!existingSuggestion && !allowCustomTags) return;\n\n    const isDuplicate = selectedTags.some(\n      (t) => t.toLowerCase() === normalizedValue.toLowerCase()\n    );\n    if (isDuplicate) {\n      setInputValue(\"\");\n      return;\n    }\n\n    updateTags([...selectedTags, normalizedValue]);\n    setInputValue(\"\");\n    setActiveIndex(0);\n    inputRef.current?.focus();\n  };\n\n  const removeTag = (tagToRemove: string) => {\n    if (disabled) return;\n    updateTags(selectedTags.filter((t) => t !== tagToRemove));\n  };\n\n  useEffect(() => {\n    setActiveIndex(0);\n  }, [inputValue]);\n\n  useEffect(() => {\n    if (!open || !listRef.current) return;\n    const activeEl = listRef.current.querySelector<HTMLElement>(\n      `[data-index=\"${activeIndex}\"]`\n    );\n    activeEl?.scrollIntoView({ block: \"nearest\" });\n  }, [activeIndex, open]);\n\n  useEffect(() => {\n    const handleOutside = (e: MouseEvent) => {\n      if (\n        containerRef.current &&\n        !containerRef.current.contains(e.target as Node)\n      ) {\n        setOpen(false);\n      }\n    };\n    document.addEventListener(\"mousedown\", handleOutside);\n    return () => document.removeEventListener(\"mousedown\", handleOutside);\n  }, []);\n\n  const handleKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {\n    if (disabled) return;\n\n    if (e.key === \"ArrowDown\") {\n      e.preventDefault();\n      if (!open) {\n        setOpen(true);\n        return;\n      }\n      if (filteredSuggestions.length > 0) {\n        setActiveIndex((prev) => (prev + 1) % filteredSuggestions.length);\n      }\n    } else if (e.key === \"ArrowUp\") {\n      e.preventDefault();\n      if (filteredSuggestions.length > 0) {\n        setActiveIndex(\n          (prev) =>\n            (prev - 1 + filteredSuggestions.length) %\n            filteredSuggestions.length\n        );\n      }\n    } else if (e.key === \"Enter\" || e.key === \",\") {\n      if (e.key === \",\" && !inputValue.trim()) {\n        e.preventDefault();\n        return;\n      }\n      if (open && filteredSuggestions[activeIndex] && !inputValue.endsWith(\",\")) {\n        e.preventDefault();\n        addTag(filteredSuggestions[activeIndex].value);\n      } else if (inputValue.trim()) {\n        e.preventDefault();\n        addTag(inputValue);\n      }\n    } else if (\n      e.key === \"Backspace\" &&\n      inputValue === \"\" &&\n      selectedTags.length > 0\n    ) {\n      e.preventDefault();\n      removeTag(selectedTags[selectedTags.length - 1]);\n    } else if (e.key === \"Escape\") {\n      setOpen(false);\n    }\n  };\n\n  return (\n    <div ref={containerRef} className={cn(\"relative w-full max-w-md\", className)}>\n      {(label || maxTags) && (\n        <div className=\"mb-1.5 flex items-center justify-between\">\n          {label && (\n            <label\n              onClick={() => inputRef.current?.focus()}\n              className=\"cursor-pointer text-xs font-medium text-neutral-600 dark:text-neutral-400\"\n            >\n              {label}\n            </label>\n          )}\n          <div className=\"flex items-center gap-2\">\n            {selectedTags.length > 0 && !disabled && (\n              <button\n                type=\"button\"\n                onClick={() => updateTags([])}\n                className=\"text-[11px] font-medium text-neutral-400 transition-colors hover:text-black dark:hover:text-white\"\n              >\n                Clear all\n              </button>\n            )}\n            <span\n              className={cn(\n                \"font-mono text-[11px]\",\n                isAtLimit\n                  ? \"font-semibold text-amber-600 dark:text-amber-400\"\n                  : \"text-neutral-400 dark:text-neutral-500\"\n              )}\n            >\n              {selectedTags.length}/{maxTags}\n            </span>\n          </div>\n        </div>\n      )}\n\n      {/* Input & Tag Container */}\n      <div\n        onClick={() => {\n          if (!disabled) {\n            inputRef.current?.focus();\n            setOpen(true);\n          }\n        }}\n        className={cn(\n          \"flex min-h-[44px] w-full flex-wrap items-center gap-1.5 rounded-xl border bg-white p-2 transition-colors dark:bg-[#0A0A0A]\",\n          open\n            ? \"border-black ring-2 ring-black/10 dark:border-white dark:ring-white/10\"\n            : \"border-neutral-200 hover:border-neutral-300 dark:border-[#262626] dark:hover:border-neutral-700\",\n          disabled && \"cursor-not-allowed opacity-50\"\n        )}\n      >\n        <AnimatePresence mode=\"popLayout\" initial={false}>\n          {selectedTags.map((tag) => (\n            <motion.span\n              key={tag}\n              layout={!shouldReduceMotion}\n              initial={\n                shouldReduceMotion ? { opacity: 0 } : { opacity: 0, scale: 0.85 }\n              }\n              animate={{ opacity: 1, scale: 1 }}\n              exit={\n                shouldReduceMotion ? { opacity: 0 } : { opacity: 0, scale: 0.85 }\n              }\n              transition={{ type: \"spring\", stiffness: 500, damping: 30 }}\n              className=\"inline-flex items-center gap-1 rounded-lg border border-neutral-200 bg-neutral-100 px-2.5 py-1 text-xs font-medium text-black dark:border-[#262626] dark:bg-[#161616] dark:text-white\"\n            >\n              <Tag className=\"h-3 w-3 text-neutral-400 dark:text-neutral-500\" />\n              <span>{getTagLabel(tag)}</span>\n              {!disabled && (\n                <button\n                  type=\"button\"\n                  aria-label={`Remove ${getTagLabel(tag)}`}\n                  onClick={(e) => {\n                    e.stopPropagation();\n                    removeTag(tag);\n                  }}\n                  className=\"ml-0.5 rounded p-0.5 text-neutral-400 transition-colors hover:bg-neutral-200 hover:text-black dark:hover:bg-[#262626] dark:hover:text-white\"\n                >\n                  <X className=\"h-3 w-3\" />\n                </button>\n              )}\n            </motion.span>\n          ))}\n        </AnimatePresence>\n\n        <input\n          ref={inputRef}\n          type=\"text\"\n          role=\"combobox\"\n          aria-expanded={open}\n          aria-controls={listboxId}\n          aria-autocomplete=\"list\"\n          disabled={disabled || isAtLimit}\n          value={inputValue}\n          onFocus={() => setOpen(true)}\n          onChange={(e) => {\n            const val = e.target.value;\n            if (val.endsWith(\",\")) {\n              addTag(val);\n            } else {\n              setInputValue(val);\n              setOpen(true);\n            }\n          }}\n          onKeyDown={handleKeyDown}\n          placeholder={\n            isAtLimit\n              ? \"Maximum tags reached\"\n              : selectedTags.length === 0\n                ? placeholder\n                : \"Add more...\"\n          }\n          className=\"min-w-[110px] flex-1 bg-transparent px-1.5 py-0.5 text-sm text-black placeholder:text-neutral-400 focus:outline-none disabled:cursor-not-allowed dark:text-white dark:placeholder:text-neutral-600\"\n        />\n      </div>\n\n      {/* Helper hint */}\n      <p className=\"mt-1.5 text-[11px] text-neutral-400 dark:text-neutral-500\">\n        Press <kbd className=\"rounded border border-neutral-200 bg-neutral-100 px-1 py-0.5 font-mono text-[10px] dark:border-neutral-800 dark:bg-neutral-900\">Enter</kbd> or <kbd className=\"rounded border border-neutral-200 bg-neutral-100 px-1 py-0.5 font-mono text-[10px] dark:border-neutral-800 dark:bg-neutral-900\">,</kbd> to add · <kbd className=\"rounded border border-neutral-200 bg-neutral-100 px-1 py-0.5 font-mono text-[10px] dark:border-neutral-800 dark:bg-neutral-900\">Backspace</kbd> to remove\n      </p>\n\n      {/* Suggestions Dropdown */}\n      <AnimatePresence>\n        {open && !disabled && !isAtLimit && (\n          <motion.div\n            id={listboxId}\n            ref={listRef}\n            role=\"listbox\"\n            initial={\n              shouldReduceMotion ? { opacity: 0 } : { opacity: 0, y: -6, scale: 0.98 }\n            }\n            animate={{ opacity: 1, y: 0, scale: 1 }}\n            exit={\n              shouldReduceMotion ? { opacity: 0 } : { opacity: 0, y: -4, scale: 0.98 }\n            }\n            transition={{ type: \"spring\", stiffness: 420, damping: 28 }}\n            className=\"absolute left-0 right-0 z-50 mt-1 max-h-52 overflow-y-auto rounded-xl border border-neutral-200 bg-white p-1.5 shadow-xl dark:border-[#262626] dark:bg-[#0A0A0A]\"\n          >\n            {filteredSuggestions.length === 0 ? (\n              allowCustomTags && inputValue.trim() ? (\n                <button\n                  type=\"button\"\n                  onMouseDown={(e) => e.preventDefault()}\n                  onClick={() => addTag(inputValue)}\n                  className=\"flex w-full items-center justify-between rounded-lg bg-neutral-100 px-3 py-2 text-left text-xs font-medium text-black dark:bg-[#161616] dark:text-white\"\n                >\n                  <span className=\"flex items-center gap-2\">\n                    <Plus className=\"h-3.5 w-3.5\" />\n                    Create tag &ldquo;{inputValue.trim()}&rdquo;\n                  </span>\n                  <span className=\"font-mono text-[10px] text-neutral-400\">\n                    Enter\n                  </span>\n                </button>\n              ) : (\n                <div className=\"px-3 py-3 text-center text-xs text-neutral-400\">\n                  No matching suggestions available\n                </div>\n              )\n            ) : (\n              filteredSuggestions.map((item, idx) => {\n                const isActive = idx === activeIndex;\n                return (\n                  <button\n                    key={item.value}\n                    type=\"button\"\n                    role=\"option\"\n                    data-index={idx}\n                    aria-selected={isActive}\n                    onMouseDown={(e) => e.preventDefault()}\n                    onMouseEnter={() => setActiveIndex(idx)}\n                    onClick={() => addTag(item.value)}\n                    className={cn(\n                      \"flex w-full items-center justify-between rounded-lg px-3 py-2 text-left text-sm transition-colors\",\n                      isActive\n                        ? \"bg-neutral-100 text-black dark:bg-[#161616] dark:text-white\"\n                        : \"text-neutral-600 hover:bg-neutral-50 dark:text-neutral-400 dark:hover:bg-[#121212]\"\n                    )}\n                  >\n                    <span className=\"flex items-center gap-2 font-medium\">\n                      <Plus className=\"h-3.5 w-3.5 text-neutral-400\" />\n                      {item.label}\n                    </span>\n                    {item.category && (\n                      <span className=\"rounded-md border border-neutral-200 px-1.5 py-0.5 font-mono text-[10px] text-neutral-500 dark:border-neutral-800 dark:text-neutral-400\">\n                        {item.category}\n                      </span>\n                    )}\n                  </button>\n                );\n              })\n            )}\n          </motion.div>\n        )}\n      </AnimatePresence>\n    </div>\n  );\n}\n\nexport default MultiSelectTagInput;\n",
          "type": "registry:ui",
          "target": "components/ui/multi-select-tag-input.tsx"
        },
        {
          "path": "lib/utils.ts",
          "content": "import { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...inputs: ClassValue[]) {\n  return twMerge(clsx(inputs));\n}\n\nexport async function copyToClipboard(text: string): Promise<boolean> {\n  if (typeof window === \"undefined\") return false;\n\n  try {\n    if (navigator.clipboard && window.isSecureContext) {\n      await navigator.clipboard.writeText(text);\n      return true;\n    }\n\n    const textArea = document.createElement(\"textarea\");\n    textArea.value = text;\n    textArea.style.position = \"fixed\";\n    textArea.style.left = \"-999999px\";\n    textArea.style.top = \"-999999px\";\n    document.body.appendChild(textArea);\n    textArea.focus();\n    textArea.select();\n    const succeeded = document.execCommand(\"copy\");\n    textArea.remove();\n    return succeeded;\n  } catch {\n    return false;\n  }\n}\n",
          "type": "registry:lib",
          "target": "lib/utils.ts"
        }
      ]
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "multiplayer-cursors",
      "type": "registry:ui",
      "title": "Multiplayer Cursors",
      "author": "Rishabh Bose <https://theb0se.vercel.app/>",
      "description": "Figma-style real-time collaboration canvas with animated multiplayer cursor pointers, user name tags, color badges, interactive live cursor chat bubbles, and click ripple wave broadcasts.",
      "dependencies": [
        "framer-motion",
        "lucide-react",
        "clsx",
        "tailwind-merge"
      ],
      "files": [
        {
          "path": "components/ui/multiplayer-cursors.tsx",
          "content": "\"use client\";\n\nimport React, { useState, useEffect, useRef, useCallback } from \"react\";\nimport { motion, AnimatePresence } from \"framer-motion\";\nimport {\n  Users,\n  MessageSquare,\n  Plus,\n  Play,\n  Pause,\n  Sparkles,\n  MousePointer,\n  Send,\n} from \"lucide-react\";\nimport { cn } from \"@/lib/utils\";\n\nexport interface Collaborator {\n  id: string;\n  name: string;\n  color: string;\n  x: number;\n  y: number;\n  message?: string;\n  state: \"active\" | \"idle\" | \"typing\";\n}\n\nexport interface MultiplayerCursorsProps {\n  initialCollaborators?: Collaborator[];\n  showGrid?: boolean;\n  overlayOnly?: boolean;\n  className?: string;\n}\n\nconst DEFAULT_COLLABORATORS: Collaborator[] = [\n  {\n    id: \"collab-1\",\n    name: \"Elena Rostova\",\n    color: \"#ec4899\", // pink-500\n    x: 22,\n    y: 35,\n    message: \"Loving this component architecture! ✨\",\n    state: \"typing\",\n  },\n  {\n    id: \"collab-2\",\n    name: \"Marcus Chen\",\n    color: \"#3b82f6\", // blue-500\n    x: 68,\n    y: 28,\n    message: \"Checking the token contracts\",\n    state: \"active\",\n  },\n  {\n    id: \"collab-3\",\n    name: \"Sarah Jenkins\",\n    color: \"#10b981\", // emerald-500\n    x: 45,\n    y: 65,\n    message: \"Ready for review 🚀\",\n    state: \"active\",\n  },\n];\n\nconst BOT_NAMES = [\n  \"Liam Vance\",\n  \"Chloe Dupont\",\n  \"Daisuke Sato\",\n  \"Nadia Thorne\",\n  \"Amara Okafor\",\n];\n\nconst BOT_COLORS = [\"#8b5cf6\", \"#f59e0b\", \"#06b6d4\", \"#ef4444\", \"#14b8a6\"];\n\nconst BOT_PHRASES = [\n  \"LGTM! Shipping it 🚢\",\n  \"Can you inspect line 42?\",\n  \"Refactoring the hooks here\",\n  \"Looks pixel perfect! 👌\",\n  \"Updating typography scales\",\n];\n\n// Figma-style cursor arrow SVG\nfunction CursorSvg({ color }: { color: string }) {\n  return (\n    <svg\n      width=\"24\"\n      height=\"24\"\n      viewBox=\"0 0 24 24\"\n      fill=\"none\"\n      xmlns=\"http://www.w3.org/2000/svg\"\n      className=\"drop-shadow-md select-none pointer-events-none\"\n    >\n      <path\n        d=\"M5.65376 12.3673H5.46026L5.31717 12.4976L0.500002 16.8829L0.500002 1.19841L11.7841 12.3673H5.65376Z\"\n        fill={color}\n        stroke=\"#ffffff\"\n        strokeWidth=\"1.2\"\n      />\n    </svg>\n  );\n}\n\nexport function MultiplayerCursors({\n  initialCollaborators = DEFAULT_COLLABORATORS,\n  showGrid = true,\n  overlayOnly = false,\n  className,\n}: MultiplayerCursorsProps) {\n  const [collaborators, setCollaborators] =\n    useState<Collaborator[]>(initialCollaborators);\n  const [isSimulating, setIsSimulating] = useState(true);\n  const [userChatInput, setUserChatInput] = useState(\"\");\n  const [userCursorPos, setUserCursorPos] = useState<{\n    x: number;\n    y: number;\n  } | null>(null);\n  const [userMessage, setUserMessage] = useState<string | null>(\n    \"You (Type below to chat)\"\n  );\n  const [clicks, setClicks] = useState<\n    { id: number; x: number; y: number; color: string }[]\n  >([]);\n\n  const canvasRef = useRef<HTMLDivElement>(null);\n\n  // Track local user pointer\n  const handlePointerMove = useCallback(\n    (e: React.PointerEvent<HTMLDivElement>) => {\n      if (!canvasRef.current) return;\n      const rect = canvasRef.current.getBoundingClientRect();\n      const xPercent = ((e.clientX - rect.left) / rect.width) * 100;\n      const yPercent = ((e.clientY - rect.top) / rect.height) * 100;\n      setUserCursorPos({ x: xPercent, y: yPercent });\n    },\n    []\n  );\n\n  const handlePointerLeave = () => {\n    setUserCursorPos(null);\n  };\n\n  // Canvas click broadcast wave\n  const handleCanvasClick = (e: React.PointerEvent<HTMLDivElement>) => {\n    if (!canvasRef.current) return;\n    const rect = canvasRef.current.getBoundingClientRect();\n    const x = e.clientX - rect.left;\n    const y = e.clientY - rect.top;\n\n    const newClick = {\n      id: Date.now(),\n      x,\n      y,\n      color: \"#6366f1\",\n    };\n\n    setClicks((prev) => [...prev.slice(-6), newClick]);\n  };\n\n  // Automated collaborator movement simulation\n  useEffect(() => {\n    if (!isSimulating) return;\n\n    const interval = setInterval(() => {\n      setCollaborators((prev) =>\n        prev.map((c) => {\n          // Roam around slightly\n          const dx = (Math.random() - 0.5) * 12;\n          const dy = (Math.random() - 0.5) * 12;\n          const newX = Math.max(10, Math.min(90, c.x + dx));\n          const newY = Math.max(15, Math.min(85, c.y + dy));\n\n          // Occasionally change message\n          const shouldChangeMsg = Math.random() < 0.12;\n          const newMsg = shouldChangeMsg\n            ? BOT_PHRASES[Math.floor(Math.random() * BOT_PHRASES.length)]\n            : c.message;\n\n          return {\n            ...c,\n            x: newX,\n            y: newY,\n            message: newMsg,\n          };\n        })\n      );\n    }, 2400);\n\n    return () => clearInterval(interval);\n  }, [isSimulating]);\n\n  // Add a new collaborator\n  const addCollaborator = () => {\n    const nextIdx = collaborators.length;\n    const name = BOT_NAMES[nextIdx % BOT_NAMES.length];\n    const color = BOT_COLORS[nextIdx % BOT_COLORS.length];\n    const newCollab: Collaborator = {\n      id: `bot-${Date.now()}`,\n      name,\n      color,\n      x: Math.floor(Math.random() * 70) + 15,\n      y: Math.floor(Math.random() * 60) + 20,\n      message: \"Just joined the session 👋\",\n      state: \"active\",\n    };\n    setCollaborators((prev) => [...prev, newCollab]);\n  };\n\n  // Handle user bubble chat submit\n  const handleSendChat = (e: React.FormEvent) => {\n    e.preventDefault();\n    if (!userChatInput.trim()) return;\n    setUserMessage(userChatInput);\n    setUserChatInput(\"\");\n  };\n\n  if (overlayOnly) {\n    return (\n      <div className={cn(\"pointer-events-none absolute inset-0 overflow-hidden select-none\", className)}>\n        {collaborators.map((c) => (\n          <motion.div\n            key={c.id}\n            animate={{ left: `${c.x}%`, top: `${c.y}%` }}\n            transition={{\n              type: \"spring\",\n              damping: 30,\n              stiffness: 140,\n              mass: 0.5,\n            }}\n            className=\"pointer-events-none absolute z-20 -translate-x-1 -translate-y-1\"\n          >\n            <CursorSvg color={c.color} />\n            <div\n              style={{ backgroundColor: c.color }}\n              className=\"ml-4 -mt-2 inline-flex items-center gap-1 rounded-md px-2 py-0.5 text-[10px] font-semibold text-white shadow-md whitespace-nowrap\"\n            >\n              <span>{c.name}</span>\n            </div>\n            {c.message && (\n              <div className=\"mt-1 ml-4 max-w-[180px] rounded-lg border border-neutral-700/80 bg-neutral-900/95 p-1.5 text-[11px] text-neutral-100 shadow-xl backdrop-blur-md\">\n                <p className=\"leading-snug\">{c.message}</p>\n              </div>\n            )}\n          </motion.div>\n        ))}\n      </div>\n    );\n  }\n\n  return (\n    <div\n      data-fullscreen-scroll\n      className={cn(\n        \"relative w-full min-h-[520px] overflow-hidden rounded-2xl border border-neutral-200/80 bg-neutral-950 p-6 text-neutral-100 shadow-xl dark:border-neutral-800 flex flex-col justify-between select-none\",\n        className\n      )}\n    >\n      {/* Ambient background glow */}\n      <div className=\"pointer-events-none absolute -top-32 left-1/3 h-96 w-96 rounded-full bg-violet-600/10 blur-[120px]\" />\n\n      {/* Top Header & Collaborators Presence Pills */}\n      <div className=\"relative z-20 flex flex-col sm:flex-row items-start sm:items-center justify-between gap-3\">\n        <div className=\"flex items-center gap-2\">\n          <MousePointer className=\"h-4 w-4 text-neutral-400\" />\n          <span className=\"font-semibold text-sm text-white\">\n            Multiplayer Canvas\n          </span>\n          <span className=\"inline-flex items-center gap-1.5 rounded-full bg-neutral-800/80 border border-neutral-700/60 px-2.5 py-0.5 text-xs text-neutral-300\">\n            <span className=\"h-2 w-2 rounded-full bg-emerald-500 animate-pulse\" />\n            {collaborators.length + 1} live presences\n          </span>\n        </div>\n\n        {/* Action Buttons */}\n        <div className=\"flex items-center gap-2\">\n          <button\n            type=\"button\"\n            onClick={addCollaborator}\n            className=\"flex items-center gap-1 rounded-lg border border-neutral-800 bg-neutral-900 px-2.5 py-1.5 text-xs font-medium text-neutral-200 hover:bg-neutral-800 transition-colors\"\n          >\n            <Plus className=\"h-3.5 w-3.5\" />\n            <span>Add Teammate</span>\n          </button>\n          <button\n            type=\"button\"\n            onClick={() => setIsSimulating((prev) => !prev)}\n            className=\"flex items-center gap-1 rounded-lg border border-neutral-800 bg-neutral-900 px-2.5 py-1.5 text-xs font-medium text-neutral-300 hover:bg-neutral-800 transition-colors\"\n          >\n            {isSimulating ? (\n              <>\n                <Pause className=\"h-3.5 w-3.5 text-amber-400\" />\n                <span>Pause Motion</span>\n              </>\n            ) : (\n              <>\n                <Play className=\"h-3.5 w-3.5 text-emerald-400\" />\n                <span>Resume Motion</span>\n              </>\n            )}\n          </button>\n        </div>\n      </div>\n\n      {/* Interactive Canvas Board */}\n      <div\n        ref={canvasRef}\n        onPointerMove={handlePointerMove}\n        onPointerLeave={handlePointerLeave}\n        onClick={handleCanvasClick}\n        className={cn(\n          \"relative my-4 flex-1 min-h-[320px] rounded-xl border border-neutral-800/80 bg-neutral-900/40 backdrop-blur-sm cursor-crosshair overflow-hidden\",\n          showGrid &&\n            \"bg-[radial-gradient(#27272a_1.2px,transparent_1.2px)] [background-size:24px_24px]\"\n        )}\n      >\n        {/* Helper Hint */}\n        <div className=\"pointer-events-none absolute inset-0 flex items-center justify-center text-center p-6 opacity-30\">\n          <div>\n            <Sparkles className=\"mx-auto mb-2 h-7 w-7 text-neutral-400\" />\n            <p className=\"font-mono text-xs text-neutral-300\">\n              Hover to move your live pointer • Click to send waves • Type\n              cursor chat\n            </p>\n          </div>\n        </div>\n\n        {/* Click Wave Ripple Animations */}\n        <AnimatePresence>\n          {clicks.map((clk) => (\n            <motion.div\n              key={clk.id}\n              initial={{ scale: 0, opacity: 0.9 }}\n              animate={{ scale: 3.5, opacity: 0 }}\n              exit={{ opacity: 0 }}\n              transition={{ duration: 0.6, ease: \"easeOut\" }}\n              style={{ left: clk.x - 16, top: clk.y - 16 }}\n              className=\"pointer-events-none absolute h-8 w-8 rounded-full border-2 border-indigo-400\"\n            />\n          ))}\n        </AnimatePresence>\n\n        {/* Remote Collaborators Cursors */}\n        {collaborators.map((c) => (\n          <motion.div\n            key={c.id}\n            animate={{ left: `${c.x}%`, top: `${c.y}%` }}\n            transition={{\n              type: \"spring\",\n              damping: 30,\n              stiffness: 140,\n              mass: 0.5,\n            }}\n            className=\"pointer-events-none absolute z-10 -translate-x-1 -translate-y-1\"\n          >\n            {/* Pointer Arrow */}\n            <CursorSvg color={c.color} />\n\n            {/* User Name Tag Badge */}\n            <div\n              style={{ backgroundColor: c.color }}\n              className=\"ml-4 -mt-2 inline-flex items-center gap-1 rounded-md px-2 py-0.5 text-[11px] font-semibold text-white shadow-md whitespace-nowrap\"\n            >\n              <span>{c.name}</span>\n            </div>\n\n            {/* Chat Bubble Message */}\n            <AnimatePresence>\n              {c.message && (\n                <motion.div\n                  initial={{ opacity: 0, y: 4, scale: 0.9 }}\n                  animate={{ opacity: 1, y: 0, scale: 1 }}\n                  exit={{ opacity: 0, scale: 0.9 }}\n                  className=\"mt-1 ml-4 max-w-[200px] rounded-lg border border-neutral-700/80 bg-neutral-900/95 p-2 text-xs text-neutral-100 shadow-xl backdrop-blur-md\"\n                >\n                  <p className=\"leading-snug\">{c.message}</p>\n                </motion.div>\n              )}\n            </AnimatePresence>\n          </motion.div>\n        ))}\n\n        {/* Local User Cursor Indicator (when inside canvas) */}\n        {userCursorPos && (\n          <div\n            style={{\n              left: `${userCursorPos.x}%`,\n              top: `${userCursorPos.y}%`,\n            }}\n            className=\"pointer-events-none absolute z-20 -translate-x-1 -translate-y-1 transition-transform duration-75\"\n          >\n            <CursorSvg color=\"#6366f1\" />\n\n            <div className=\"ml-4 -mt-2 inline-flex items-center gap-1 rounded-md bg-indigo-600 px-2 py-0.5 text-[11px] font-semibold text-white shadow-md whitespace-nowrap\">\n              <span>You</span>\n            </div>\n\n            {userMessage && (\n              <motion.div\n                initial={{ opacity: 0, y: 4 }}\n                animate={{ opacity: 1, y: 0 }}\n                className=\"mt-1 ml-4 max-w-[220px] rounded-lg border border-indigo-500/40 bg-neutral-900/95 p-2 text-xs text-indigo-200 shadow-xl backdrop-blur-md\"\n              >\n                <p className=\"leading-snug\">{userMessage}</p>\n              </motion.div>\n            )}\n          </div>\n        )}\n      </div>\n\n      {/* Footer Cursor Chat Bar */}\n      <div className=\"relative z-20 flex flex-col sm:flex-row items-center justify-between gap-3 border-t border-neutral-800/80 pt-4 text-xs text-neutral-400\">\n        <form\n          onSubmit={handleSendChat}\n          className=\"flex w-full sm:w-auto flex-1 max-w-md items-center gap-2\"\n        >\n          <div className=\"relative flex-1\">\n            <MessageSquare className=\"absolute left-2.5 top-1/2 -translate-y-1/2 h-3.5 w-3.5 text-neutral-500\" />\n            <input\n              type=\"text\"\n              value={userChatInput}\n              onChange={(e) => setUserChatInput(e.target.value)}\n              placeholder=\"Type message to broadcast to cursor bubble...\"\n              className=\"w-full rounded-lg border border-neutral-800 bg-neutral-900 pl-8 pr-3 py-1.5 text-xs text-neutral-200 placeholder:text-neutral-500 focus:border-indigo-500 focus:outline-none\"\n            />\n          </div>\n          <button\n            type=\"submit\"\n            className=\"flex items-center gap-1 rounded-lg bg-indigo-600 px-3 py-1.5 font-medium text-white hover:bg-indigo-500 transition-colors shadow-sm\"\n          >\n            <Send className=\"h-3 w-3\" />\n            <span>Broadcast</span>\n          </button>\n        </form>\n\n        <div className=\"flex items-center gap-3 text-neutral-500 font-mono text-[11px]\">\n          <span>Figma Real-Time Protocol</span>\n          <span>•</span>\n          <span>WebRTC Presence</span>\n        </div>\n      </div>\n    </div>\n  );\n}\n\nexport default MultiplayerCursors;\n",
          "type": "registry:ui",
          "target": "components/ui/multiplayer-cursors.tsx"
        },
        {
          "path": "lib/utils.ts",
          "content": "import { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...inputs: ClassValue[]) {\n  return twMerge(clsx(inputs));\n}\n\nexport async function copyToClipboard(text: string): Promise<boolean> {\n  if (typeof window === \"undefined\") return false;\n\n  try {\n    if (navigator.clipboard && window.isSecureContext) {\n      await navigator.clipboard.writeText(text);\n      return true;\n    }\n\n    const textArea = document.createElement(\"textarea\");\n    textArea.value = text;\n    textArea.style.position = \"fixed\";\n    textArea.style.left = \"-999999px\";\n    textArea.style.top = \"-999999px\";\n    document.body.appendChild(textArea);\n    textArea.focus();\n    textArea.select();\n    const succeeded = document.execCommand(\"copy\");\n    textArea.remove();\n    return succeeded;\n  } catch {\n    return false;\n  }\n}\n",
          "type": "registry:lib",
          "target": "lib/utils.ts"
        }
      ]
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "now-playing-waveform",
      "type": "registry:ui",
      "title": "Now Playing Waveform",
      "author": "Rishabh Bose <https://theb0se.vercel.app/>",
      "description": "Spotify-style music player featuring dancing multi-octave equalizer frequency bars, spinning vinyl cover artwork, scrubbable progress bar with hover time tooltip, and playback controls.",
      "dependencies": [
        "framer-motion",
        "lucide-react",
        "clsx",
        "tailwind-merge"
      ],
      "files": [
        {
          "path": "components/ui/now-playing-waveform.tsx",
          "content": "\"use client\";\n\nimport React, { useState, useEffect, useRef } from \"react\";\nimport { motion, AnimatePresence } from \"framer-motion\";\nimport {\n  Play,\n  Pause,\n  SkipBack,\n  SkipForward,\n  Shuffle,\n  Repeat,\n  Volume2,\n  VolumeX,\n  Heart,\n  Music2,\n  Radio,\n  Sliders,\n  Sparkles,\n} from \"lucide-react\";\nimport { cn } from \"@/lib/utils\";\n\nexport interface TrackItem {\n  id: string;\n  title: string;\n  artist: string;\n  album: string;\n  duration: number; // in seconds\n  coverGradient: string;\n  accentColor: string;\n  device: string;\n}\n\nexport interface NowPlayingWaveformProps {\n  /** Array of tracks to cycle through */\n  tracks?: TrackItem[];\n  /** Default playing state */\n  initialPlaying?: boolean;\n  /** Extra container className */\n  className?: string;\n}\n\nconst DEFAULT_TRACKS: TrackItem[] = [\n  {\n    id: \"track-1\",\n    title: \"Midnight City\",\n    artist: \"M83\",\n    album: \"Hurry Up, We're Dreaming\",\n    duration: 243, // 4:03\n    coverGradient: \"from-emerald-500 via-teal-700 to-cyan-900\",\n    accentColor: \"#1DB954\", // Spotify Green\n    device: \"Sonos Era 300 · Hi-Fi Lossless\",\n  },\n  {\n    id: \"track-2\",\n    title: \"Nightcall (Synthwave Rework)\",\n    artist: \"Kavinsky\",\n    album: \"OutRun\",\n    duration: 259, // 4:19\n    coverGradient: \"from-rose-600 via-purple-800 to-indigo-950\",\n    accentColor: \"#F43F5E\",\n    device: \"AirPods Pro (2nd Gen) · Spatial Audio\",\n  },\n  {\n    id: \"track-3\",\n    title: \"Resonance\",\n    artist: \"HOME\",\n    album: \"Odyssey\",\n    duration: 212, // 3:32\n    coverGradient: \"from-amber-500 via-orange-600 to-stone-900\",\n    accentColor: \"#F59E0B\",\n    device: \"Studio Monitors · 24-bit 96kHz\",\n  },\n];\n\nconst BAR_COUNT = 32;\n\nfunction formatSeconds(secs: number): string {\n  const m = Math.floor(secs / 60);\n  const s = Math.floor(secs % 60);\n  return `${m}:${s < 10 ? \"0\" : \"\"}${s}`;\n}\n\nexport function NowPlayingWaveform({\n  tracks = DEFAULT_TRACKS,\n  initialPlaying = true,\n  className,\n}: NowPlayingWaveformProps) {\n  const [currentTrackIndex, setCurrentTrackIndex] = useState(0);\n  const [isPlaying, setIsPlaying] = useState(initialPlaying);\n  const [currentTime, setCurrentTime] = useState(64); // start at 1:04\n  const [volume, setVolume] = useState(78);\n  const [isMuted, setIsMuted] = useState(false);\n  const [isShuffle, setIsShuffle] = useState(false);\n  const [repeatMode, setRepeatMode] = useState<\"off\" | \"all\" | \"one\">(\"all\");\n  const [isLiked, setIsLiked] = useState(true);\n\n  // Scrubber hover state\n  const [hoverPosition, setHoverPosition] = useState<number | null>(null);\n  const progressBarRef = useRef<HTMLDivElement>(null);\n\n  const track = tracks[currentTrackIndex] || tracks[0];\n\n  // Playback timer simulation\n  useEffect(() => {\n    if (!isPlaying) return;\n    const interval = setInterval(() => {\n      setCurrentTime((prev) => {\n        if (prev >= track.duration) {\n          if (repeatMode === \"one\") return 0;\n          if (repeatMode === \"all\") {\n            setCurrentTrackIndex((idx) => (idx + 1) % tracks.length);\n            return 0;\n          }\n          setIsPlaying(false);\n          return track.duration;\n        }\n        return prev + 1;\n      });\n    }, 1000);\n    return () => clearInterval(interval);\n  }, [isPlaying, track.duration, repeatMode, tracks.length]);\n\n  const handleNextTrack = () => {\n    setCurrentTrackIndex((idx) => (idx + 1) % tracks.length);\n    setCurrentTime(0);\n  };\n\n  const handlePrevTrack = () => {\n    if (currentTime > 4) {\n      setCurrentTime(0);\n    } else {\n      setCurrentTrackIndex((idx) => (idx - 1 + tracks.length) % tracks.length);\n      setCurrentTime(0);\n    }\n  };\n\n  const handleSeek = (e: React.MouseEvent<HTMLDivElement>) => {\n    if (!progressBarRef.current) return;\n    const rect = progressBarRef.current.getBoundingClientRect();\n    const clickX = Math.max(0, Math.min(e.clientX - rect.left, rect.width));\n    const ratio = clickX / rect.width;\n    setCurrentTime(Math.floor(ratio * track.duration));\n  };\n\n  const handleMouseMoveScrub = (e: React.MouseEvent<HTMLDivElement>) => {\n    if (!progressBarRef.current) return;\n    const rect = progressBarRef.current.getBoundingClientRect();\n    const hoverX = Math.max(0, Math.min(e.clientX - rect.left, rect.width));\n    setHoverPosition(hoverX / rect.width);\n  };\n\n  const progressPercent = Math.min(100, (currentTime / track.duration) * 100);\n\n  return (\n    <div\n      data-fullscreen-scroll\n      className={cn(\n        \"relative flex min-h-[520px] w-full flex-col justify-between overflow-hidden rounded-2xl border border-neutral-200 bg-neutral-900 p-4 text-white sm:p-8 dark:border-neutral-800 dark:bg-[#0A0D12]\",\n        className\n      )}\n    >\n      {/* Background glow radiating track colors */}\n      <div\n        aria-hidden=\"true\"\n        className=\"pointer-events-none absolute -right-20 -top-20 h-96 w-96 rounded-full blur-[120px] transition-colors duration-1000\"\n        style={{\n          backgroundColor: track.accentColor,\n          opacity: isPlaying ? 0.22 : 0.08,\n        }}\n      />\n      <div\n        aria-hidden=\"true\"\n        className=\"pointer-events-none absolute -bottom-20 -left-20 h-96 w-96 rounded-full blur-[140px] transition-colors duration-1000\"\n        style={{\n          backgroundColor: track.accentColor,\n          opacity: isPlaying ? 0.15 : 0.05,\n        }}\n      />\n\n      {/* Header bar */}\n      <div className=\"relative z-10 flex flex-wrap items-center justify-between gap-3 pb-2\">\n        <div className=\"flex items-center gap-3\">\n          <div\n            className=\"flex h-9 w-9 items-center justify-center rounded-xl text-white shadow-lg shadow-black/40\"\n            style={{ backgroundColor: track.accentColor }}\n          >\n            <Music2 className=\"h-4 w-4\" />\n          </div>\n          <div>\n            <div className=\"flex items-center gap-2\">\n              <span className=\"text-sm font-semibold tracking-tight text-white\">\n                Spotify Now Playing Waveform\n              </span>\n              <span className=\"flex items-center gap-1 rounded-full bg-white/10 px-2 py-0.5 text-[10px] font-medium text-white/80 backdrop-blur-md\">\n                <Radio className=\"h-2.5 w-2.5 text-emerald-400\" />\n                Live Visualizer\n              </span>\n            </div>\n            <p className=\"text-xs text-neutral-400\">\n              Reactive animated frequency equalizer, scrubbable timeline, and Spotify Connect\n            </p>\n          </div>\n        </div>\n\n        <div className=\"flex items-center gap-2\">\n          <div className=\"flex items-center gap-1.5 rounded-full border border-white/10 bg-black/40 px-3 py-1 text-xs text-neutral-300 backdrop-blur-md\">\n            <span className=\"inline-block h-2 w-2 rounded-full bg-emerald-400 animate-pulse\" />\n            <span className=\"truncate max-w-[190px]\">{track.device}</span>\n          </div>\n        </div>\n      </div>\n\n      {/* Main Player Center Stage */}\n      <div className=\"relative z-10 my-auto flex flex-col items-center justify-center py-6\">\n        <div className=\"w-full max-w-2xl rounded-3xl border border-white/10 bg-neutral-950/80 p-5 shadow-2xl backdrop-blur-xl sm:p-7\">\n          {/* Top row: Album Art & Track Info */}\n          <div className=\"flex flex-col items-center gap-5 sm:flex-row sm:items-center\">\n            {/* Album Art with spinning vinyl simulation when playing */}\n            <div className=\"relative h-28 w-28 shrink-0 overflow-hidden rounded-2xl shadow-2xl ring-1 ring-white/15\">\n              <div\n                className={cn(\n                  \"h-full w-full bg-gradient-to-br transition-all duration-700\",\n                  track.coverGradient\n                )}\n              />\n              <motion.div\n                animate={isPlaying ? { rotate: 360 } : { rotate: 0 }}\n                transition={\n                  isPlaying\n                    ? { repeat: Infinity, duration: 12, ease: \"linear\" }\n                    : { duration: 0.5 }\n                }\n                className=\"absolute inset-2 flex items-center justify-center rounded-full border-2 border-dashed border-white/25 bg-black/30 backdrop-blur-xs\"\n              >\n                <div className=\"h-6 w-6 rounded-full border-2 border-white/40 bg-neutral-900\" />\n              </motion.div>\n            </div>\n\n            {/* Title, Artist, and Favorite */}\n            <div className=\"flex flex-1 flex-col justify-center text-center sm:text-left\">\n              <div className=\"flex items-center justify-center gap-2 sm:justify-start\">\n                <span className=\"rounded bg-white/10 px-1.5 py-0.5 text-[9px] font-bold uppercase tracking-wider text-neutral-300\">\n                  Master\n                </span>\n                <span className=\"text-xs text-neutral-400\">{track.album}</span>\n              </div>\n              <h2 className=\"mt-1 text-lg font-bold tracking-tight text-white sm:text-xl\">\n                {track.title}\n              </h2>\n              <p className=\"text-sm font-medium text-neutral-400\">\n                {track.artist}\n              </p>\n            </div>\n\n            {/* Favorite button */}\n            <button\n              type=\"button\"\n              onClick={() => setIsLiked(!isLiked)}\n              aria-label={isLiked ? \"Remove from favorites\" : \"Save to favorites\"}\n              className=\"flex h-10 w-10 items-center justify-center rounded-full border border-white/10 bg-white/5 transition hover:scale-105 active:scale-95\"\n            >\n              <Heart\n                className={cn(\n                  \"h-5 w-5 transition-colors\",\n                  isLiked ? \"fill-emerald-400 text-emerald-400\" : \"text-neutral-400\"\n                )}\n              />\n            </button>\n          </div>\n\n          {/* REAL-TIME DANCING FREQUENCY WAVEFORM */}\n          <div className=\"my-6 flex h-20 w-full items-end justify-between gap-1 rounded-2xl border border-white/5 bg-black/40 px-3 py-2.5 sm:gap-1.5\">\n            {Array.from({ length: BAR_COUNT }).map((_, i) => {\n              // Sine-based multi-octave initial heights\n              const baseHeight =\n                Math.sin((i / BAR_COUNT) * Math.PI) * 55 +\n                Math.sin((i / 4) * Math.PI) * 15 +\n                20;\n\n              // Generate looping animated heights when playing\n              const h1 = Math.max(12, Math.min(95, baseHeight * 0.7));\n              const h2 = Math.max(15, Math.min(100, baseHeight * 1.3));\n              const h3 = Math.max(10, Math.min(85, baseHeight * 0.4));\n              const h4 = Math.max(20, Math.min(98, baseHeight * 1.1));\n\n              const duration = 0.65 + (i % 5) * 0.12;\n\n              return (\n                <motion.div\n                  key={i}\n                  animate={\n                    isPlaying\n                      ? {\n                          height: [`${h1}%`, `${h2}%`, `${h3}%`, `${h4}%`, `${h1}%`],\n                        }\n                      : {\n                          height: `${Math.max(10, baseHeight * 0.35)}%`,\n                        }\n                  }\n                  transition={\n                    isPlaying\n                      ? {\n                          duration,\n                          repeat: Infinity,\n                          ease: \"easeInOut\",\n                          delay: (i % 7) * 0.05,\n                        }\n                      : { duration: 0.3 }\n                  }\n                  style={{\n                    backgroundColor:\n                      i / BAR_COUNT <= progressPercent / 100\n                        ? track.accentColor\n                        : \"rgba(255, 255, 255, 0.2)\",\n                  }}\n                  className=\"w-full min-w-[2px] rounded-full transition-colors duration-150\"\n                />\n              );\n            })}\n          </div>\n\n          {/* SCRUBBABLE TIMELINE PROGRESS BAR */}\n          <div className=\"relative\">\n            {/* Hover timestamp tooltip */}\n            {hoverPosition !== null && (\n              <div\n                style={{ left: `${hoverPosition * 100}%` }}\n                className=\"pointer-events-none absolute -top-7 -translate-x-1/2 rounded bg-neutral-800 px-1.5 py-0.5 font-mono text-[10px] text-white shadow-md ring-1 ring-white/10\"\n              >\n                {formatSeconds(hoverPosition * track.duration)}\n              </div>\n            )}\n\n            <div\n              ref={progressBarRef}\n              onClick={handleSeek}\n              onMouseMove={handleMouseMoveScrub}\n              onMouseLeave={() => setHoverPosition(null)}\n              className=\"group relative flex h-3 w-full cursor-pointer items-center\"\n            >\n              {/* Background Track */}\n              <div className=\"h-1 w-full rounded-full bg-white/20 transition-all group-hover:h-1.5\">\n                {/* Active Progress */}\n                <div\n                  style={{\n                    width: `${progressPercent}%`,\n                    backgroundColor: track.accentColor,\n                  }}\n                  className=\"relative h-full rounded-full\"\n                >\n                  {/* Scrubber Knob */}\n                  <div className=\"absolute right-0 top-1/2 -translate-y-1/2 h-3.5 w-3.5 scale-0 rounded-full bg-white shadow-md transition-transform group-hover:scale-100\" />\n                </div>\n              </div>\n            </div>\n\n            {/* Time labels */}\n            <div className=\"mt-1 flex items-center justify-between font-mono text-[11px] text-neutral-400\">\n              <span>{formatSeconds(currentTime)}</span>\n              <span>{formatSeconds(track.duration)}</span>\n            </div>\n          </div>\n\n          {/* PLAYBACK CONTROLS ROW */}\n          <div className=\"mt-5 flex flex-wrap items-center justify-between gap-4\">\n            {/* Shuffle */}\n            <button\n              type=\"button\"\n              onClick={() => setIsShuffle(!isShuffle)}\n              aria-label=\"Toggle shuffle\"\n              className={cn(\n                \"p-2 transition rounded-full hover:bg-white/5\",\n                isShuffle ? \"text-emerald-400\" : \"text-neutral-400 hover:text-white\"\n              )}\n            >\n              <Shuffle className=\"h-4 w-4\" />\n            </button>\n\n            {/* Core Prev / Play / Next */}\n            <div className=\"flex items-center gap-3\">\n              <button\n                type=\"button\"\n                onClick={handlePrevTrack}\n                aria-label=\"Previous track\"\n                className=\"rounded-full p-2 text-neutral-300 transition hover:bg-white/10 hover:text-white active:scale-95\"\n              >\n                <SkipBack className=\"h-5 w-5\" />\n              </button>\n\n              <motion.button\n                type=\"button\"\n                whileTap={{ scale: 0.92 }}\n                onClick={() => setIsPlaying(!isPlaying)}\n                aria-label={isPlaying ? \"Pause track\" : \"Play track\"}\n                style={{ backgroundColor: track.accentColor }}\n                className=\"flex h-12 w-12 items-center justify-center rounded-full text-black shadow-lg shadow-black/40 transition hover:scale-105\"\n              >\n                {isPlaying ? (\n                  <Pause className=\"h-5 w-5 fill-current\" />\n                ) : (\n                  <Play className=\"ml-0.5 h-5 w-5 fill-current\" />\n                )}\n              </motion.button>\n\n              <button\n                type=\"button\"\n                onClick={handleNextTrack}\n                aria-label=\"Next track\"\n                className=\"rounded-full p-2 text-neutral-300 transition hover:bg-white/10 hover:text-white active:scale-95\"\n              >\n                <SkipForward className=\"h-5 w-5\" />\n              </button>\n            </div>\n\n            {/* Repeat Mode */}\n            <button\n              type=\"button\"\n              onClick={() => {\n                if (repeatMode === \"off\") setRepeatMode(\"all\");\n                else if (repeatMode === \"all\") setRepeatMode(\"one\");\n                else setRepeatMode(\"off\");\n              }}\n              aria-label=\"Toggle repeat\"\n              className={cn(\n                \"relative p-2 transition rounded-full hover:bg-white/5\",\n                repeatMode !== \"off\" ? \"text-emerald-400\" : \"text-neutral-400 hover:text-white\"\n              )}\n            >\n              <Repeat className=\"h-4 w-4\" />\n              {repeatMode === \"one\" && (\n                <span className=\"absolute -top-0.5 right-0 text-[8px] font-bold\">1</span>\n              )}\n            </button>\n\n            {/* Volume Stepper */}\n            <div className=\"hidden items-center gap-2 sm:flex\">\n              <button\n                type=\"button\"\n                onClick={() => setIsMuted(!isMuted)}\n                className=\"text-neutral-400 transition hover:text-white\"\n              >\n                {isMuted || volume === 0 ? (\n                  <VolumeX className=\"h-4 w-4\" />\n                ) : (\n                  <Volume2 className=\"h-4 w-4\" />\n                )}\n              </button>\n              <input\n                type=\"range\"\n                min=\"0\"\n                max=\"100\"\n                value={isMuted ? 0 : volume}\n                onChange={(e) => {\n                  setVolume(Number(e.target.value));\n                  if (isMuted) setIsMuted(false);\n                }}\n                className=\"h-1 w-20 cursor-pointer accent-emerald-400\"\n              />\n            </div>\n          </div>\n        </div>\n      </div>\n\n      {/* Footer Track Switcher Controls */}\n      <div className=\"relative z-10 flex flex-wrap items-center justify-between gap-3 border-t border-white/10 pt-4 text-xs text-neutral-400\">\n        <div className=\"flex flex-wrap items-center gap-2\">\n          <span>Switch Song:</span>\n          {tracks.map((t, idx) => (\n            <button\n              key={t.id}\n              type=\"button\"\n              onClick={() => {\n                setCurrentTrackIndex(idx);\n                setCurrentTime(0);\n                setIsPlaying(true);\n              }}\n              className={cn(\n                \"rounded-md px-2.5 py-1 text-xs font-medium transition\",\n                currentTrackIndex === idx\n                  ? \"bg-white text-black font-semibold\"\n                  : \"bg-white/10 text-white/80 hover:bg-white/20\"\n              )}\n            >\n              {t.title}\n            </button>\n          ))}\n        </div>\n\n        <div className=\"font-mono text-[11px] text-neutral-400\">\n          Audio Engine: 44.1kHz PCM Synthesizer\n        </div>\n      </div>\n    </div>\n  );\n}\n\nexport default NowPlayingWaveform;\n",
          "type": "registry:ui",
          "target": "components/ui/now-playing-waveform.tsx"
        },
        {
          "path": "lib/utils.ts",
          "content": "import { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...inputs: ClassValue[]) {\n  return twMerge(clsx(inputs));\n}\n\nexport async function copyToClipboard(text: string): Promise<boolean> {\n  if (typeof window === \"undefined\") return false;\n\n  try {\n    if (navigator.clipboard && window.isSecureContext) {\n      await navigator.clipboard.writeText(text);\n      return true;\n    }\n\n    const textArea = document.createElement(\"textarea\");\n    textArea.value = text;\n    textArea.style.position = \"fixed\";\n    textArea.style.left = \"-999999px\";\n    textArea.style.top = \"-999999px\";\n    document.body.appendChild(textArea);\n    textArea.focus();\n    textArea.select();\n    const succeeded = document.execCommand(\"copy\");\n    textArea.remove();\n    return succeeded;\n  } catch {\n    return false;\n  }\n}\n",
          "type": "registry:lib",
          "target": "lib/utils.ts"
        }
      ]
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "ocean-waves",
      "type": "registry:ui",
      "title": "Ocean Waves",
      "author": "Rishabh Bose <https://theb0se.vercel.app/>",
      "description": "Multi-layered rolling ocean waves rendered on Canvas 2D using multi-harmonic trochoidal wave equations, translucent subsurface ridge scattering, and shimmering crest foam highlights.",
      "dependencies": [
        "lucide-react",
        "clsx",
        "tailwind-merge"
      ],
      "files": [
        {
          "path": "components/ui/ocean-waves.tsx",
          "content": "\"use client\";\n\nimport React, { useEffect, useRef, useState } from \"react\";\nimport { Waves, Sparkles, Sliders } from \"lucide-react\";\nimport { cn } from \"@/lib/utils\";\n\nexport interface OceanWavesProps {\n  /** Number of stacked parallax wave layers (3 to 9). Default: 5 */\n  waveCount?: number;\n  /** Peak vertical wave height in pixels. Default: 28 */\n  amplitude?: number;\n  /** Horizontal wave frequency (radians per pixel). Default: 0.008 */\n  frequency?: number;\n  /** Wave propagation speed multiplier. Default: 1.0 */\n  speed?: number;\n  /** Primary ocean water hex color. Default: \"#0284C7\" */\n  oceanColor?: string;\n  /** Render shimmering white foam highlights along wave ridges. Default: true */\n  foam?: boolean;\n  /** Optional foreground content */\n  children?: React.ReactNode;\n  className?: string;\n}\n\ninterface SprayDroplet {\n  x: number;\n  y: number;\n  vx: number;\n  vy: number;\n  size: number;\n  alpha: number;\n  life: number;\n  maxLife: number;\n}\n\nfunction hexToRgb(hex: string): [number, number, number] {\n  const clean = hex.replace(\"#\", \"\").trim();\n  if (clean.length === 3) {\n    return [\n      parseInt(clean[0] + clean[0], 16) || 2,\n      parseInt(clean[1] + clean[1], 16) || 132,\n      parseInt(clean[2] + clean[2], 16) || 199,\n    ];\n  }\n  const num = parseInt(clean, 16);\n  if (Number.isNaN(num)) return [2, 132, 199];\n  return [(num >> 16) & 255, (num >> 8) & 255, num & 255];\n}\n\nconst OCEAN_PRESETS = [\n  { name: \"Pacific\", color: \"#0284C7\", amp: 28, speed: 1.0, count: 5 },\n  { name: \"Biolume\", color: \"#0D9488\", amp: 34, speed: 0.85, count: 6 },\n  { name: \"Storm Swell\", color: \"#2563EB\", amp: 44, speed: 1.55, count: 7 },\n];\n\nexport function OceanWaves({\n  waveCount = 5,\n  amplitude = 28,\n  frequency = 0.008,\n  speed = 1.0,\n  oceanColor = \"#0284C7\",\n  foam = true,\n  children,\n  className,\n}: OceanWavesProps) {\n  const containerRef = useRef<HTMLDivElement>(null);\n  const canvasRef = useRef<HTMLCanvasElement>(null);\n\n  const [liveCount, setLiveCount] = useState(waveCount);\n  const [liveAmp, setLiveAmp] = useState(amplitude);\n  const [liveSpeed, setLiveSpeed] = useState(speed);\n  const [liveColor, setLiveColor] = useState(oceanColor);\n  const [liveFoam, setLiveFoam] = useState(foam);\n\n  useEffect(() => setLiveCount(waveCount), [waveCount]);\n  useEffect(() => setLiveAmp(amplitude), [amplitude]);\n  useEffect(() => setLiveSpeed(speed), [speed]);\n  useEffect(() => setLiveColor(oceanColor), [oceanColor]);\n  useEffect(() => setLiveFoam(foam), [foam]);\n\n  const paramsRef = useRef({\n    count: liveCount,\n    amp: liveAmp,\n    freq: frequency,\n    speed: liveSpeed,\n    color: liveColor,\n    foam: liveFoam,\n  });\n\n  useEffect(() => {\n    paramsRef.current = {\n      count: liveCount,\n      amp: liveAmp,\n      freq: frequency,\n      speed: liveSpeed,\n      color: liveColor,\n      foam: liveFoam,\n    };\n  }, [liveCount, liveAmp, frequency, liveSpeed, liveColor, liveFoam]);\n\n  useEffect(() => {\n    const container = containerRef.current;\n    const canvas = canvasRef.current;\n    if (!container || !canvas) return;\n\n    const ctx = canvas.getContext(\"2d\");\n    if (!ctx) return;\n\n    let width = 0;\n    let height = 0;\n    let dpr = 1;\n    let rafId = 0;\n    const sprayDrops: SprayDroplet[] = [];\n\n    const resize = () => {\n      const rect = container.getBoundingClientRect();\n      width = Math.max(1, rect.width);\n      height = Math.max(1, rect.height);\n      dpr = Math.min(window.devicePixelRatio || 1, 2);\n      canvas.width = Math.floor(width * dpr);\n      canvas.height = Math.floor(height * dpr);\n      ctx.setTransform(dpr, 0, 0, dpr, 0, 0);\n    };\n\n    resize();\n    const ro = new ResizeObserver(resize);\n    ro.observe(container);\n\n    let time = 0;\n\n    const render = () => {\n      const {\n        count: curCount,\n        amp: curAmp,\n        freq: curFreq,\n        speed: curSpeed,\n        color: curColor,\n        foam: curFoam,\n      } = paramsRef.current;\n\n      time += 0.018 * curSpeed;\n      const [baseR, baseG, baseB] = hexToRgb(curColor);\n      const layers = Math.max(3, Math.min(9, Math.round(curCount)));\n      const horizonY = height * 0.35;\n\n      // 1. Atmospheric twilight marine sky with low horizon celestial glow\n      const skyGrad = ctx.createLinearGradient(0, 0, 0, horizonY + 30);\n      skyGrad.addColorStop(0, \"#020613\");\n      skyGrad.addColorStop(0.55, \"#06152D\");\n      skyGrad.addColorStop(\n        0.9,\n        `rgb(${Math.min(255, Math.floor(baseR * 0.35 + 14))}, ${Math.min(255, Math.floor(baseG * 0.48 + 26))}, ${Math.min(255, Math.floor(baseB * 0.62 + 42))})`\n      );\n      skyGrad.addColorStop(1, \"#041226\");\n      ctx.fillStyle = skyGrad;\n      ctx.fillRect(0, 0, width, horizonY + 30);\n\n      // Low horizon moon/sun atmospheric bloom & light pillar\n      const sunX = width * 0.52;\n      const sunGlow = ctx.createRadialGradient(\n        sunX,\n        horizonY - 8,\n        4,\n        sunX,\n        horizonY,\n        width * 0.58\n      );\n      sunGlow.addColorStop(0, \"rgba(235, 252, 255, 0.38)\");\n      sunGlow.addColorStop(\n        0.22,\n        `rgba(${Math.min(255, baseR + 95)}, ${Math.min(255, baseG + 90)}, 255, 0.2)`\n      );\n      sunGlow.addColorStop(0.6, `rgba(${baseR}, ${baseG}, ${baseB}, 0.06)`);\n      sunGlow.addColorStop(1, \"rgba(0, 0, 0, 0)\");\n      ctx.fillStyle = sunGlow;\n      ctx.fillRect(0, 0, width, height);\n\n      // Base abyssal sea below horizon\n      ctx.fillStyle = \"#010712\";\n      ctx.fillRect(0, horizonY, width, height - horizonY);\n\n      const startY = horizonY + 14;\n      const bandSpan = height * 0.53;\n      const stepX = 5;\n\n      // 2. Render back-to-front Gerstner/Trochoidal swell layers\n      for (let i = 0; i < layers; i++) {\n        const depth = layers === 1 ? 1 : i / (layers - 1);\n        // Non-linear perspective spacing: distant swells are tighter near horizon\n        const perspDepth = Math.pow(depth, 1.28);\n        const baseY = startY + perspDepth * bandSpan;\n\n        const layerAmp = curAmp * (0.36 + perspDepth * 0.92);\n        const layerFreq = curFreq * (1.55 - depth * 0.68);\n        const dir = i % 2 === 0 ? 1 : -0.78;\n        const phase = i * 2.15 + time * (0.62 + depth * 0.88) * dir;\n\n        // Steepness factor for Gerstner trochoidal peaking (sharper crests, broad troughs)\n        const steepness = 0.38 + depth * 0.24;\n\n        const points: Array<{\n          x: number;\n          y: number;\n          slope: number;\n          crestFactor: number;\n        }> = [];\n\n        for (let x = -20; x <= width + 25; x += stepX) {\n          const theta1 = x * layerFreq + phase;\n          const theta2 = x * (layerFreq * 1.82) - time * 1.18 + i * 1.3;\n          const theta3 = x * (layerFreq * 3.15) + time * 1.75 - i * 0.7;\n\n          // Trochoidal horizontal pinching toward wave crests\n          const pinchX =\n            x - Math.cos(theta1) * layerAmp * steepness * 0.55;\n\n          // Multi-harmonic vertical displacement with trochoidal sharpening\n          const s1 = Math.sin(theta1);\n          const sharpCrest = -Math.pow(0.5 + 0.5 * s1, 2.2) * layerAmp * 1.25 + layerAmp * 0.5;\n          const h2 = Math.cos(theta2) * (layerAmp * 0.3);\n          const h3 = Math.sin(theta3) * (layerAmp * 0.13);\n\n          const yOffset = sharpCrest + h2 + h3;\n          const y = baseY + yOffset;\n\n          // Local wave slope for specular sky reflections\n          const slope = Math.cos(theta1) * layerFreq * layerAmp;\n\n          // Crest factor (0 in trough, 1 at sharp breaking ridge)\n          const crestFactor = Math.max(\n            0,\n            Math.min(1, (-yOffset / (layerAmp * 1.15) + 0.28) * 0.95)\n          );\n\n          points.push({ x: pinchX, y, slope, crestFactor });\n        }\n\n        // Draw primary wave body with subsurface scattering gradient\n        ctx.beginPath();\n        for (let p = 0; p < points.length; p++) {\n          const pt = points[p];\n          if (p === 0) ctx.moveTo(pt.x, pt.y);\n          else ctx.lineTo(pt.x, pt.y);\n        }\n        ctx.lineTo(width + 40, height + 30);\n        ctx.lineTo(-40, height + 30);\n        ctx.closePath();\n\n        // Translucent emerald/aquamarine subsurface scattering at thin wave top -> abyssal navy in trough\n        const sssR = Math.min(255, Math.round(baseR * 0.65 + 45));\n        const sssG = Math.min(255, Math.round(baseG * 1.15 + 75));\n        const sssB = Math.min(255, Math.round(baseB * 1.05 + 55));\n\n        const midR = Math.round(baseR * (0.42 + depth * 0.22));\n        const midG = Math.round(baseG * (0.5 + depth * 0.22));\n        const midB = Math.round(baseB * (0.62 + depth * 0.22));\n\n        const deepR = Math.round(baseR * 0.08);\n        const deepG = Math.round(baseG * 0.13);\n        const deepB = Math.round(baseB * 0.25 + 8);\n\n        const waveGrad = ctx.createLinearGradient(\n          0,\n          baseY - layerAmp * 1.35,\n          0,\n          baseY + layerAmp * 2.4 + 90\n        );\n        const topAlpha = 0.76 + depth * 0.2;\n        waveGrad.addColorStop(0, `rgba(${sssR}, ${sssG}, ${sssB}, ${topAlpha})`);\n        waveGrad.addColorStop(0.24, `rgba(${midR}, ${midG}, ${midB}, 0.94)`);\n        waveGrad.addColorStop(0.68, `rgba(${deepR}, ${deepG}, ${deepB}, 0.98)`);\n        waveGrad.addColorStop(1, \"#010610\");\n\n        ctx.fillStyle = waveGrad;\n        ctx.fill();\n\n        // 3. Subsurface translucent glow band & specular sky reflection ribbons\n        ctx.save();\n        ctx.globalCompositeOperation = \"lighter\";\n\n        // Subsurface inner emerald/cyan transmission band right below the ridge\n        ctx.beginPath();\n        for (let p = 0; p < points.length; p++) {\n          const pt = points[p];\n          const sssThickness = 3 + pt.crestFactor * (8 + depth * 8);\n          if (p === 0) ctx.moveTo(pt.x, pt.y + sssThickness * 0.45);\n          else ctx.lineTo(pt.x, pt.y + sssThickness * 0.45);\n        }\n        ctx.strokeStyle = `rgba(${sssR}, ${Math.min(255, sssG + 30)}, ${sssB}, ${0.18 + depth * 0.16})`;\n        ctx.lineWidth = 5 + depth * 6;\n        ctx.stroke();\n\n        // Specular water slope reflections under the sun/moon light path\n        for (let p = 1; p < points.length; p += 2) {\n          const pt = points[p];\n          const sunAlign = Math.exp(\n            -Math.pow((pt.x - sunX) / (width * 0.32), 2)\n          );\n          const facetGlint =\n            0.5 + 0.5 * Math.sin(pt.x * 0.11 + time * 4.2 + i * 1.7);\n          if (facetGlint > 0.58 && sunAlign > 0.12) {\n            const specAlpha =\n              (facetGlint - 0.55) * sunAlign * (0.28 + depth * 0.35);\n            ctx.strokeStyle = `rgba(225, 248, 255, ${specAlpha})`;\n            ctx.lineWidth = 1.2 + depth * 1.2;\n            ctx.beginPath();\n            ctx.moveTo(points[p - 1].x, points[p - 1].y + 3 + facetGlint * 5);\n            ctx.lineTo(pt.x, pt.y + 3 + facetGlint * 5);\n            ctx.stroke();\n          }\n        }\n\n        // 4. Organic laced whitecap foam filaments & wind-blown sea spray\n        if (curFoam) {\n          // Primary variable-width whitecap ridge line\n          for (let p = 1; p < points.length; p++) {\n            const prev = points[p - 1];\n            const pt = points[p];\n            if (pt.crestFactor > 0.25) {\n              const fAlpha =\n                Math.pow(pt.crestFactor, 1.5) * (0.35 + depth * 0.55);\n              ctx.strokeStyle = `rgba(242, 252, 255, ${fAlpha})`;\n              ctx.lineWidth = 0.8 + pt.crestFactor * (1.8 + depth * 2.2);\n              ctx.beginPath();\n              ctx.moveTo(prev.x, prev.y);\n              ctx.lineTo(pt.x, pt.y);\n              ctx.stroke();\n            }\n\n            // Laced foam filaments trailing down the forward wave face near high crests\n            if (pt.crestFactor > 0.58 && p % 2 === 0) {\n              const laceLen =\n                (pt.crestFactor - 0.55) * (24 + depth * 32) *\n                (0.6 + 0.4 * Math.sin(pt.x * 0.08 + i * 3.1));\n              const laceAlpha = (pt.crestFactor - 0.55) * (0.26 + depth * 0.35);\n\n              ctx.strokeStyle = `rgba(230, 249, 255, ${laceAlpha})`;\n              ctx.lineWidth = 0.9 + depth * 0.6;\n              ctx.beginPath();\n              ctx.moveTo(pt.x, pt.y + 1);\n              ctx.quadraticCurveTo(\n                pt.x - dir * laceLen * 0.35,\n                pt.y + laceLen * 0.55,\n                pt.x - dir * laceLen * 0.65,\n                pt.y + laceLen\n              );\n              ctx.stroke();\n            }\n\n            // Spawn wind-blown sea spray droplets off steep breaking crests\n            if (\n              pt.crestFactor > 0.78 &&\n              sprayDrops.length < 95 &&\n              Math.random() < 0.045 * curSpeed\n            ) {\n              sprayDrops.push({\n                x: pt.x,\n                y: pt.y - 1,\n                vx: dir * (1.2 + Math.random() * 2.4) * curSpeed,\n                vy: -(0.9 + Math.random() * 2.1),\n                size: 0.9 + Math.random() * 1.6 * (0.5 + depth * 0.6),\n                alpha: 0.45 + Math.random() * 0.45,\n                life: 0,\n                maxLife: 22 + Math.random() * 24,\n              });\n            }\n          }\n        }\n\n        ctx.restore();\n      }\n\n      // 5. Update and render wind-blown sea spray droplets\n      if (curFoam && sprayDrops.length > 0) {\n        ctx.save();\n        ctx.globalCompositeOperation = \"lighter\";\n        for (let i = sprayDrops.length - 1; i >= 0; i--) {\n          const sp = sprayDrops[i];\n          sp.x += sp.vx;\n          sp.y += sp.vy;\n          sp.vy += 0.09; // gravity\n          sp.life += 1;\n\n          const lifeRatio = 1 - sp.life / sp.maxLife;\n          if (lifeRatio <= 0) {\n            sprayDrops.splice(i, 1);\n            continue;\n          }\n\n          ctx.fillStyle = `rgba(240, 252, 255, ${sp.alpha * lifeRatio})`;\n          ctx.beginPath();\n          ctx.arc(sp.x, sp.y, sp.size, 0, Math.PI * 2);\n          ctx.fill();\n        }\n        ctx.restore();\n      }\n\n      rafId = requestAnimationFrame(render);\n    };\n\n    rafId = requestAnimationFrame(render);\n\n    return () => {\n      cancelAnimationFrame(rafId);\n      ro.disconnect();\n    };\n  }, []);\n\n  return (\n    <div\n      ref={containerRef}\n      data-fullscreen-scroll\n      className={cn(\n        \"relative flex min-h-[520px] w-full flex-col justify-between overflow-hidden rounded-2xl border border-white/10 bg-[#020614] p-6 text-white shadow-2xl\",\n        className\n      )}\n    >\n      <canvas\n        ref={canvasRef}\n        aria-hidden=\"true\"\n        className=\"pointer-events-none absolute inset-0 h-full w-full\"\n      />\n\n      {children && (\n        <div className=\"relative z-10 flex min-h-[520px] w-full flex-col\">\n          {children}\n        </div>\n      )}\n    </div>\n  );\n}\n\nexport default OceanWaves;\n",
          "type": "registry:ui",
          "target": "components/ui/ocean-waves.tsx"
        },
        {
          "path": "lib/utils.ts",
          "content": "import { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...inputs: ClassValue[]) {\n  return twMerge(clsx(inputs));\n}\n\nexport async function copyToClipboard(text: string): Promise<boolean> {\n  if (typeof window === \"undefined\") return false;\n\n  try {\n    if (navigator.clipboard && window.isSecureContext) {\n      await navigator.clipboard.writeText(text);\n      return true;\n    }\n\n    const textArea = document.createElement(\"textarea\");\n    textArea.value = text;\n    textArea.style.position = \"fixed\";\n    textArea.style.left = \"-999999px\";\n    textArea.style.top = \"-999999px\";\n    document.body.appendChild(textArea);\n    textArea.focus();\n    textArea.select();\n    const succeeded = document.execCommand(\"copy\");\n    textArea.remove();\n    return succeeded;\n  } catch {\n    return false;\n  }\n}\n",
          "type": "registry:lib",
          "target": "lib/utils.ts"
        }
      ]
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "parallax-tilt-card",
      "type": "registry:ui",
      "title": "Parallax Tilt Card",
      "author": "Rishabh Bose <https://theb0se.vercel.app/>",
      "description": "Multi-depth 3D spatial card featuring three independent Z-planes that shift at graduated parallax ratios under pointer movement.",
      "dependencies": [
        "framer-motion",
        "lucide-react",
        "clsx",
        "tailwind-merge"
      ],
      "files": [
        {
          "path": "components/ui/parallax-tilt-card.tsx",
          "content": "\"use client\";\n\nimport React, { useRef } from \"react\";\nimport {\n  motion,\n  useMotionValue,\n  useSpring,\n  useTransform,\n  useReducedMotion,\n} from \"framer-motion\";\nimport { Cpu, Layers, Sparkles } from \"lucide-react\";\nimport { cn } from \"@/lib/utils\";\n\nexport interface ParallaxTiltCardProps {\n  /** Card title heading. Default: \"Spatial Depth Plane\" */\n  title?: string;\n  /** Supporting card description. */\n  subtitle?: string;\n  /** Peak 3D rotation angle in degrees. Default: 14 */\n  maxTilt?: number;\n  /** Hooke's Law spring stiffness coefficient. Default: 240 */\n  stiffness?: number;\n  /** Spring damping coefficient. Default: 22 */\n  damping?: number;\n  className?: string;\n}\n\nexport function ParallaxTiltCard({\n  title = \"Spatial Depth Plane\",\n  subtitle = \"Three independent Z-planes translate at graduated ratios under pointer movement.\",\n  maxTilt = 14,\n  stiffness = 240,\n  damping = 22,\n  className,\n}: ParallaxTiltCardProps) {\n  const cardRef = useRef<HTMLDivElement | null>(null);\n  const shouldReduceMotion = useReducedMotion() ?? false;\n\n  const pctX = useMotionValue(0);\n  const pctY = useMotionValue(0);\n\n  const smoothX = useSpring(pctX, { stiffness, damping, mass: 0.4 });\n  const smoothY = useSpring(pctY, { stiffness, damping, mass: 0.4 });\n\n  const rotateX = useTransform(smoothY, [-1, 1], [maxTilt, -maxTilt]);\n  const rotateY = useTransform(smoothX, [-1, 1], [-maxTilt, maxTilt]);\n\n  // Graduated multi-plane parallax offsets\n  const layer1X = useTransform(smoothX, [-1, 1], [-6, 6]);\n  const layer1Y = useTransform(smoothY, [-1, 1], [-6, 6]);\n\n  const layer2X = useTransform(smoothX, [-1, 1], [-16, 16]);\n  const layer2Y = useTransform(smoothY, [-1, 1], [-16, 16]);\n\n  const layer3X = useTransform(smoothX, [-1, 1], [-26, 26]);\n  const layer3Y = useTransform(smoothY, [-1, 1], [-26, 26]);\n\n  const handleMouseMove = (e: React.MouseEvent<HTMLDivElement>) => {\n    if (shouldReduceMotion) return;\n    const el = cardRef.current;\n    if (!el) return;\n    const rect = el.getBoundingClientRect();\n    const nx = ((e.clientX - rect.left) / rect.width - 0.5) * 2;\n    const ny = ((e.clientY - rect.top) / rect.height - 0.5) * 2;\n    pctX.set(nx);\n    pctY.set(ny);\n  };\n\n  const handleMouseLeave = () => {\n    pctX.set(0);\n    pctY.set(0);\n  };\n\n  return (\n    <div\n      style={{ perspective: \"1100px\" }}\n      className={cn(\"w-full max-w-sm select-none\", className)}\n    >\n      <motion.div\n        ref={cardRef}\n        onMouseMove={handleMouseMove}\n        onMouseLeave={handleMouseLeave}\n        style={{\n          rotateX: shouldReduceMotion ? 0 : rotateX,\n          rotateY: shouldReduceMotion ? 0 : rotateY,\n          transformStyle: \"preserve-3d\",\n        }}\n        className=\"group relative overflow-hidden rounded-3xl border border-neutral-200 bg-white p-6 shadow-sm transition-colors hover:border-neutral-400 dark:border-[#222222] dark:bg-[#0A0A0A] dark:hover:border-[#383838]\"\n      >\n        {/* Depth Plane 1: Background Blueprint Grid */}\n        <motion.div\n          aria-hidden=\"true\"\n          style={{\n            x: shouldReduceMotion ? 0 : layer1X,\n            y: shouldReduceMotion ? 0 : layer1Y,\n          }}\n          className=\"pointer-events-none absolute -inset-6 bg-[radial-gradient(#d4d4d4_1px,transparent_1px)] [background-size:16px_16px] opacity-60 dark:bg-[radial-gradient(#262626_1px,transparent_1px)]\"\n        />\n\n        {/* Depth Plane 2: Floating Mid-Ground Telemetry Module */}\n        <motion.div\n          style={{\n            x: shouldReduceMotion ? 0 : layer2X,\n            y: shouldReduceMotion ? 0 : layer2Y,\n          }}\n          className=\"relative z-10 mb-5 flex items-center justify-between rounded-2xl border border-neutral-200/90 bg-neutral-50/90 p-3.5 backdrop-blur-md dark:border-[#262626] dark:bg-[#141414]/90\"\n        >\n          <div className=\"flex items-center gap-2.5\">\n            <div className=\"flex h-9 w-9 items-center justify-center rounded-xl bg-black text-white dark:bg-white dark:text-black\">\n              <Cpu className=\"h-4 w-4\" />\n            </div>\n            <div>\n              <div className=\"font-mono text-[10px] font-semibold uppercase text-neutral-400\">\n                PLANE_02 // PARALLAX\n              </div>\n              <div className=\"text-xs font-semibold text-black dark:text-white\">\n                ±{maxTilt}° Coupled Tilt\n              </div>\n            </div>\n          </div>\n\n          <Layers className=\"h-4 w-4 text-neutral-400\" />\n        </motion.div>\n\n        {/* Depth Plane 3: High-Elevation Foreground Badge & Copy */}\n        <motion.div\n          style={{\n            x: shouldReduceMotion ? 0 : layer3X,\n            y: shouldReduceMotion ? 0 : layer3Y,\n          }}\n          className=\"relative z-20\"\n        >\n          <span className=\"inline-flex items-center gap-1 rounded-full bg-black px-2.5 py-0.5 font-mono text-[10px] font-semibold text-white dark:bg-white dark:text-black\">\n            <Sparkles className=\"h-3 w-3\" />\n            Z-INDEX +26PX\n          </span>\n          <h3 className=\"mt-2.5 text-base font-semibold text-black dark:text-white\">\n            {title}\n          </h3>\n          <p className=\"mt-1 text-xs leading-relaxed text-neutral-500 dark:text-neutral-400\">\n            {subtitle}\n          </p>\n        </motion.div>\n      </motion.div>\n    </div>\n  );\n}\n\nexport default ParallaxTiltCard;\n",
          "type": "registry:ui",
          "target": "components/ui/parallax-tilt-card.tsx"
        },
        {
          "path": "lib/utils.ts",
          "content": "import { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...inputs: ClassValue[]) {\n  return twMerge(clsx(inputs));\n}\n\nexport async function copyToClipboard(text: string): Promise<boolean> {\n  if (typeof window === \"undefined\") return false;\n\n  try {\n    if (navigator.clipboard && window.isSecureContext) {\n      await navigator.clipboard.writeText(text);\n      return true;\n    }\n\n    const textArea = document.createElement(\"textarea\");\n    textArea.value = text;\n    textArea.style.position = \"fixed\";\n    textArea.style.left = \"-999999px\";\n    textArea.style.top = \"-999999px\";\n    document.body.appendChild(textArea);\n    textArea.focus();\n    textArea.select();\n    const succeeded = document.execCommand(\"copy\");\n    textArea.remove();\n    return succeeded;\n  } catch {\n    return false;\n  }\n}\n",
          "type": "registry:lib",
          "target": "lib/utils.ts"
        }
      ]
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "particle-network",
      "type": "registry:ui",
      "title": "Particle Network",
      "author": "Rishabh Bose <https://theb0se.vercel.app/>",
      "description": "Interactive Canvas 2D proximity graph where drifting nodes dynamically connect with distance-attenuated lines whenever they pass within a threshold radius.",
      "dependencies": [
        "lucide-react",
        "clsx",
        "tailwind-merge"
      ],
      "files": [
        {
          "path": "components/ui/particle-network.tsx",
          "content": "\"use client\";\n\nimport React, { useEffect, useRef } from \"react\";\nimport { Network } from \"lucide-react\";\nimport { cn } from \"@/lib/utils\";\n\nexport interface ParticleNetworkProps {\n  /** Number of drifting nodes. Default: 55 */\n  particleCount?: number;\n  /** Maximum distance in pixels to draw a connecting edge. Default: 125 */\n  connectDistance?: number;\n  /** Drift velocity multiplier. Default: 1 */\n  speed?: number;\n  /** RGB triplet (e.g. \"255, 255, 255\") for nodes and edges. Default: \"255, 255, 255\" */\n  particleColor?: string;\n  /** Connect nodes to the user's cursor when hovering. Default: true */\n  interactive?: boolean;\n  /** Optional foreground content */\n  children?: React.ReactNode;\n  className?: string;\n}\n\ninterface NodeParticle {\n  x: number;\n  y: number;\n  vx: number;\n  vy: number;\n  r: number;\n}\n\nexport function ParticleNetwork({\n  particleCount = 55,\n  connectDistance = 125,\n  speed = 1,\n  particleColor = \"255, 255, 255\",\n  interactive = true,\n  children,\n  className,\n}: ParticleNetworkProps) {\n  const canvasRef = useRef<HTMLCanvasElement>(null);\n  const mouseRef = useRef<{ x: number; y: number; active: boolean }>({\n    x: 0,\n    y: 0,\n    active: false,\n  });\n\n  useEffect(() => {\n    const canvas = canvasRef.current;\n    if (!canvas) return;\n    const ctx = canvas.getContext(\"2d\");\n    if (!ctx) return;\n\n    let rafId: number;\n    let width = (canvas.width = canvas.offsetWidth || 600);\n    let height = (canvas.height = canvas.offsetHeight || 360);\n\n    const nodes: NodeParticle[] = Array.from({ length: particleCount }, () => {\n      const angle = Math.random() * Math.PI * 2;\n      const v = (18 + Math.random() * 28) * speed;\n      return {\n        x: Math.random() * width,\n        y: Math.random() * height,\n        vx: Math.cos(angle) * v,\n        vy: Math.sin(angle) * v,\n        r: 1.5 + Math.random() * 1.5,\n      };\n    });\n\n    const handleResize = () => {\n      if (!canvas) return;\n      width = canvas.width = canvas.offsetWidth || 600;\n      height = canvas.height = canvas.offsetHeight || 360;\n    };\n\n    window.addEventListener(\"resize\", handleResize);\n\n    let last = performance.now();\n    const render = (now: number) => {\n      const dt = Math.min(0.05, (now - last) / 1000);\n      last = now;\n\n      ctx.clearRect(0, 0, width, height);\n\n      for (let i = 0; i < nodes.length; i++) {\n        const n = nodes[i];\n        n.x += n.vx * dt;\n        n.y += n.vy * dt;\n\n        if (n.x < 0 || n.x > width) n.vx *= -1;\n        if (n.y < 0 || n.y > height) n.vy *= -1;\n\n        // Draw node dot\n        ctx.beginPath();\n        ctx.arc(n.x, n.y, n.r, 0, Math.PI * 2);\n        ctx.fillStyle = `rgba(${particleColor}, 0.75)`;\n        ctx.fill();\n\n        // Connect to neighbor nodes within threshold distance\n        for (let j = i + 1; j < nodes.length; j++) {\n          const m = nodes[j];\n          const dx = n.x - m.x;\n          const dy = n.y - m.y;\n          const dist = Math.hypot(dx, dy);\n\n          if (dist < connectDistance) {\n            const alpha = (1 - dist / connectDistance) * 0.42;\n            ctx.strokeStyle = `rgba(${particleColor}, ${alpha.toFixed(3)})`;\n            ctx.lineWidth = 1;\n            ctx.beginPath();\n            ctx.moveTo(n.x, n.y);\n            ctx.lineTo(m.x, m.y);\n            ctx.stroke();\n          }\n        }\n\n        // Connect to cursor if active\n        if (interactive && mouseRef.current.active) {\n          const mdx = n.x - mouseRef.current.x;\n          const mdy = n.y - mouseRef.current.y;\n          const mDist = Math.hypot(mdx, mdy);\n          const cursorThreshold = connectDistance * 1.25;\n          if (mDist < cursorThreshold) {\n            const alpha = (1 - mDist / cursorThreshold) * 0.65;\n            ctx.strokeStyle = `rgba(${particleColor}, ${alpha.toFixed(3)})`;\n            ctx.lineWidth = 1.2;\n            ctx.beginPath();\n            ctx.moveTo(n.x, n.y);\n            ctx.lineTo(mouseRef.current.x, mouseRef.current.y);\n            ctx.stroke();\n          }\n        }\n      }\n\n      rafId = requestAnimationFrame(render);\n    };\n\n    rafId = requestAnimationFrame(render);\n    return () => {\n      cancelAnimationFrame(rafId);\n      window.removeEventListener(\"resize\", handleResize);\n    };\n  }, [particleCount, connectDistance, speed, particleColor, interactive]);\n\n  return (\n    <div\n      data-fullscreen-scroll\n      onMouseMove={(e) => {\n        const rect = e.currentTarget.getBoundingClientRect();\n        mouseRef.current.x = e.clientX - rect.left;\n        mouseRef.current.y = e.clientY - rect.top;\n        mouseRef.current.active = true;\n      }}\n      onMouseLeave={() => {\n        mouseRef.current.active = false;\n      }}\n      className={cn(\n        \"relative flex min-h-[360px] w-full flex-col justify-between overflow-hidden rounded-3xl border border-neutral-800 bg-[#05070B] p-6 text-white shadow-sm\",\n        className\n      )}\n    >\n      <canvas\n        ref={canvasRef}\n        aria-hidden=\"true\"\n        className=\"pointer-events-none absolute inset-0 h-full w-full\"\n      />\n\n      <div className=\"relative z-10 flex flex-1 flex-col justify-between\">\n        {children ?? (\n          <>\n            <div className=\"flex items-center justify-between gap-2\">\n              <span className=\"inline-flex items-center gap-1.5 rounded-full border border-white/15 bg-white/10 px-3 py-1 font-mono text-[11px] font-medium text-white backdrop-blur-md\">\n                <Network className=\"h-3.5 w-3.5 text-neutral-300\" />\n                Particle Network · {particleCount} Nodes\n              </span>\n              <span className=\"font-mono text-[11px] text-white/50\">\n                Radius: {connectDistance}px\n              </span>\n            </div>\n\n            <div className=\"my-auto max-w-md py-8\">\n              <h3 className=\"text-2xl font-bold tracking-tight text-white sm:text-3xl\">\n                Proximity Graph Topology\n              </h3>\n              <p className=\"mt-2 text-xs leading-relaxed text-white/75 sm:text-sm\">\n                Drifting nodes dynamically form edges whenever their Euclidean\n                distance falls below {connectDistance}px, with line opacity\n                scaling inversely with distance.\n              </p>\n            </div>\n\n            <div className=\"font-mono text-[11px] text-white/50\">\n              Hover anywhere to attract proximity edges\n            </div>\n          </>\n        )}\n      </div>\n    </div>\n  );\n}\n\nexport default ParticleNetwork;\n",
          "type": "registry:ui",
          "target": "components/ui/particle-network.tsx"
        },
        {
          "path": "lib/utils.ts",
          "content": "import { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...inputs: ClassValue[]) {\n  return twMerge(clsx(inputs));\n}\n\nexport async function copyToClipboard(text: string): Promise<boolean> {\n  if (typeof window === \"undefined\") return false;\n\n  try {\n    if (navigator.clipboard && window.isSecureContext) {\n      await navigator.clipboard.writeText(text);\n      return true;\n    }\n\n    const textArea = document.createElement(\"textarea\");\n    textArea.value = text;\n    textArea.style.position = \"fixed\";\n    textArea.style.left = \"-999999px\";\n    textArea.style.top = \"-999999px\";\n    document.body.appendChild(textArea);\n    textArea.focus();\n    textArea.select();\n    const succeeded = document.execCommand(\"copy\");\n    textArea.remove();\n    return succeeded;\n  } catch {\n    return false;\n  }\n}\n",
          "type": "registry:lib",
          "target": "lib/utils.ts"
        }
      ]
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "peel-reveal-card",
      "type": "registry:ui",
      "title": "Peel Reveal Card",
      "author": "Rishabh Bose <https://theb0se.vercel.app/>",
      "description": "Dual-layer vault card with a spring-hinged top cover that peels upward on hover or keyboard activation to reveal sensitive credentials.",
      "dependencies": [
        "framer-motion",
        "lucide-react",
        "clsx",
        "tailwind-merge"
      ],
      "files": [
        {
          "path": "components/ui/peel-reveal-card.tsx",
          "content": "\"use client\";\n\nimport React, { useState } from \"react\";\nimport { motion, useReducedMotion } from \"framer-motion\";\nimport { Eye, KeyRound, Copy, Check } from \"lucide-react\";\nimport { cn } from \"@/lib/utils\";\n\nexport interface PeelRevealCardProps {\n  /** Cover layer title. Default: \"Production Secret Key\" */\n  title?: string;\n  /** Secret payload revealed underneath the peel cover. Default: \"bose_live_98f72a41c09e3b1d\" */\n  secretValue?: string;\n  /** Hooke's Law spring stiffness coefficient for curtain peel. Default: 300 */\n  stiffness?: number;\n  /** Spring damping coefficient for curtain peel. Default: 24 */\n  damping?: number;\n  className?: string;\n}\n\nexport function PeelRevealCard({\n  title = \"Production Secret Key\",\n  secretValue = \"bose_live_98f72a41c09e3b1d\",\n  stiffness = 300,\n  damping = 24,\n  className,\n}: PeelRevealCardProps) {\n  const shouldReduceMotion = useReducedMotion() ?? false;\n  const [isPeeled, setIsPeeled] = useState(false);\n  const [copied, setCopied] = useState(false);\n\n  const handleCopy = (e: React.MouseEvent<HTMLButtonElement>) => {\n    e.stopPropagation();\n    if (typeof navigator !== \"undefined\" && navigator.clipboard) {\n      navigator.clipboard.writeText(secretValue).catch(() => {});\n    }\n    setCopied(true);\n    setTimeout(() => setCopied(false), 1500);\n  };\n\n  return (\n    <div\n      onMouseEnter={() => setIsPeeled(true)}\n      onMouseLeave={() => setIsPeeled(false)}\n      className={cn(\n        \"relative h-[168px] w-full max-w-sm select-none overflow-hidden rounded-3xl border border-neutral-200 bg-neutral-950 p-6 text-white shadow-sm dark:border-[#262626] dark:bg-white dark:text-black\",\n        className\n      )}\n    >\n      {/* Underlying Vault Layer */}\n      <div className=\"flex h-full flex-col justify-between\">\n        <div className=\"flex items-center justify-between text-xs\">\n          <span className=\"inline-flex items-center gap-1.5 font-mono text-[10px] uppercase tracking-wider text-neutral-400 dark:text-neutral-500\">\n            <KeyRound className=\"h-3.5 w-3.5\" />\n            VAULT_DECRYPTED\n          </span>\n          <button\n            type=\"button\"\n            onClick={handleCopy}\n            className=\"inline-flex items-center gap-1 rounded-lg bg-white/15 px-2.5 py-1 font-mono text-[10px] font-semibold text-white transition-colors hover:bg-white/25 dark:bg-black/10 dark:text-black dark:hover:bg-black/20\"\n          >\n            {copied ? (\n              <>\n                <Check className=\"h-3 w-3\" />\n                Copied\n              </>\n            ) : (\n              <>\n                <Copy className=\"h-3 w-3\" />\n                Copy Key\n              </>\n            )}\n          </button>\n        </div>\n\n        <div>\n          <div className=\"font-mono text-sm font-bold tracking-tight\">\n            {secretValue}\n          </div>\n          <p className=\"mt-1 text-[11px] text-neutral-400 dark:text-neutral-500\">\n            Move cursor away or press button to re-seal cover\n          </p>\n        </div>\n      </div>\n\n      {/* Spring-Hinged Frosted Peel Cover */}\n      <motion.div\n        role=\"button\"\n        tabIndex={0}\n        aria-expanded={isPeeled}\n        aria-label={`${title}. Activate or hover to peel back cover and reveal secret key.`}\n        onClick={() => setIsPeeled((prev) => !prev)}\n        onKeyDown={(e) => {\n          if (e.key === \"Enter\" || e.key === \" \") {\n            e.preventDefault();\n            setIsPeeled((prev) => !prev);\n          }\n        }}\n        animate={{\n          y: isPeeled ? \"-76%\" : \"0%\",\n          rotateX: isPeeled && !shouldReduceMotion ? 14 : 0,\n        }}\n        transition={\n          shouldReduceMotion\n            ? { duration: 0.01 }\n            : { type: \"spring\", stiffness, damping }\n        }\n        className=\"absolute inset-0 z-10 flex cursor-pointer flex-col justify-between rounded-3xl border border-neutral-200 bg-white p-6 text-black shadow-lg focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-black dark:border-[#262626] dark:bg-[#0D0D0D] dark:text-white dark:focus-visible:ring-white\"\n      >\n        <div className=\"flex items-center justify-between\">\n          <span className=\"inline-flex items-center gap-1.5 rounded-full border border-neutral-200 bg-neutral-50 px-2.5 py-1 font-mono text-[10px] font-semibold text-black dark:border-[#262626] dark:bg-[#141414] dark:text-white\">\n            <Eye className=\"h-3 w-3\" />\n            Hover or Click to Peel\n          </span>\n          <span className=\"font-mono text-[10px] text-neutral-400\">\n            SHA-256\n          </span>\n        </div>\n\n        <div>\n          <h3 className=\"text-base font-semibold\">{title}</h3>\n          <p className=\"mt-0.5 font-mono text-xs tracking-widest text-neutral-400\">\n            ••••••••••••••••••••••••\n          </p>\n        </div>\n      </motion.div>\n    </div>\n  );\n}\n\nexport default PeelRevealCard;\n",
          "type": "registry:ui",
          "target": "components/ui/peel-reveal-card.tsx"
        },
        {
          "path": "lib/utils.ts",
          "content": "import { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...inputs: ClassValue[]) {\n  return twMerge(clsx(inputs));\n}\n\nexport async function copyToClipboard(text: string): Promise<boolean> {\n  if (typeof window === \"undefined\") return false;\n\n  try {\n    if (navigator.clipboard && window.isSecureContext) {\n      await navigator.clipboard.writeText(text);\n      return true;\n    }\n\n    const textArea = document.createElement(\"textarea\");\n    textArea.value = text;\n    textArea.style.position = \"fixed\";\n    textArea.style.left = \"-999999px\";\n    textArea.style.top = \"-999999px\";\n    document.body.appendChild(textArea);\n    textArea.focus();\n    textArea.select();\n    const succeeded = document.execCommand(\"copy\");\n    textArea.remove();\n    return succeeded;\n  } catch {\n    return false;\n  }\n}\n",
          "type": "registry:lib",
          "target": "lib/utils.ts"
        }
      ]
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "picker-wheel",
      "type": "registry:ui",
      "title": "Picker Wheel",
      "author": "Rishabh Bose <https://theb0se.vercel.app/>",
      "description": "iOS-inspired 3D cylindrical scrolling drum picker for dates, times, and custom option columns with wheel, drag, and click-to-snap physics.",
      "dependencies": [
        "framer-motion",
        "lucide-react",
        "clsx",
        "tailwind-merge"
      ],
      "files": [
        {
          "path": "components/ui/picker-wheel.tsx",
          "content": "\"use client\";\n\nimport React, { useState } from \"react\";\nimport { motion, useReducedMotion, type PanInfo } from \"framer-motion\";\nimport { Calendar, Clock } from \"lucide-react\";\nimport { cn } from \"@/lib/utils\";\n\nexport interface PickerColumn {\n  id: string;\n  label?: string;\n  options: string[];\n  defaultIndex?: number;\n}\n\nexport interface PickerWheelProps {\n  /** Columns rendered side-by-side inside the drum wheel */\n  columns?: PickerColumn[];\n  /** Callback fired whenever any column selection changes */\n  onChange?: (selectedValues: Record<string, string>) => void;\n  /** Title shown in the header bar */\n  title?: string;\n  className?: string;\n}\n\nconst DEFAULT_COLUMNS: PickerColumn[] = [\n  {\n    id: \"day\",\n    options: [\n      \"Mon, Oct 5\",\n      \"Tue, Oct 6\",\n      \"Wed, Oct 7\",\n      \"Today\",\n      \"Fri, Oct 9\",\n      \"Sat, Oct 10\",\n      \"Sun, Oct 11\",\n    ],\n    defaultIndex: 3,\n  },\n  {\n    id: \"hour\",\n    options: [\"07\", \"08\", \"09\", \"10\", \"11\", \"12\", \"01\", \"02\", \"03\"],\n    defaultIndex: 2,\n  },\n  {\n    id: \"minute\",\n    options: [\"00\", \"15\", \"30\", \"45\"],\n    defaultIndex: 2,\n  },\n  {\n    id: \"period\",\n    options: [\"AM\", \"PM\"],\n    defaultIndex: 0,\n  },\n];\n\nconst ITEM_HEIGHT = 36;\n\nexport function PickerWheel({\n  columns = DEFAULT_COLUMNS,\n  onChange,\n  title = \"Schedule Deployment\",\n  className,\n}: PickerWheelProps) {\n  const shouldReduceMotion = useReducedMotion() ?? false;\n\n  const [selectedIndices, setSelectedIndices] = useState<Record<string, number>>(\n    () => {\n      const initial: Record<string, number> = {};\n      columns.forEach((col) => {\n        initial[col.id] = col.defaultIndex ?? 0;\n      });\n      return initial;\n    }\n  );\n\n  const selectOption = (colId: string, nextIdx: number, maxLen: number) => {\n    const clamped = Math.max(0, Math.min(maxLen - 1, nextIdx));\n    setSelectedIndices((prev) => {\n      const next = { ...prev, [colId]: clamped };\n      if (onChange) {\n        const result: Record<string, string> = {};\n        columns.forEach((c) => {\n          result[c.id] = c.options[next[c.id] ?? 0] ?? \"\";\n        });\n        onChange(result);\n      }\n      return next;\n    });\n  };\n\n  const formattedSummary = columns\n    .map((col) => col.options[selectedIndices[col.id] ?? 0])\n    .join(\" · \");\n\n  return (\n    <div\n      className={cn(\n        \"w-full max-w-md overflow-hidden rounded-3xl border border-neutral-200 bg-white p-5 shadow-sm dark:border-neutral-800 dark:bg-[#0A0A0A]\",\n        className\n      )}\n    >\n      {/* Top Header */}\n      <div className=\"mb-3 flex items-center justify-between\">\n        <span className=\"inline-flex items-center gap-1.5 text-xs font-semibold text-neutral-950 dark:text-white\">\n          <Clock className=\"h-3.5 w-3.5 text-neutral-400\" />\n          {title}\n        </span>\n        <span className=\"rounded-lg border border-neutral-200 bg-neutral-50 px-2.5 py-0.5 font-mono text-[11px] font-medium text-neutral-700 dark:border-neutral-800 dark:bg-neutral-900 dark:text-neutral-300\">\n          {formattedSummary}\n        </span>\n      </div>\n\n      {/* Drum Wheel Container */}\n      <div className=\"relative flex h-[180px] select-none items-center justify-center overflow-hidden rounded-2xl border border-neutral-200/80 bg-neutral-50/60 px-3 dark:border-neutral-800/80 dark:bg-[#111111]\">\n        {/* Top & Bottom Fade Masks */}\n        <div\n          aria-hidden=\"true\"\n          className=\"pointer-events-none absolute inset-x-0 top-0 z-20 h-14 bg-gradient-to-b from-neutral-50 via-neutral-50/80 to-transparent dark:from-[#111111] dark:via-[#111111]/80\"\n        />\n        <div\n          aria-hidden=\"true\"\n          className=\"pointer-events-none absolute inset-x-0 bottom-0 z-20 h-14 bg-gradient-to-t from-neutral-50 via-neutral-50/80 to-transparent dark:from-[#111111] dark:via-[#111111]/80\"\n        />\n\n        {/* Center Highlight Selection Bar */}\n        <div\n          aria-hidden=\"true\"\n          className=\"pointer-events-none absolute inset-x-2.5 top-1/2 z-10 h-9 -translate-y-1/2 rounded-xl border border-neutral-300/80 bg-white/90 shadow-2xs dark:border-neutral-700/80 dark:bg-neutral-900/90\"\n        />\n\n        {/* Columns */}\n        <div className=\"relative z-20 flex w-full items-center justify-around\">\n          {columns.map((col) => {\n            const activeIdx = selectedIndices[col.id] ?? 0;\n            const offsetY = (2 - activeIdx) * ITEM_HEIGHT;\n\n            return (\n              <div\n                key={col.id}\n                role=\"listbox\"\n                tabIndex={0}\n                aria-label={col.label ?? col.id}\n                onWheel={(e) => {\n                  e.preventDefault();\n                  const delta = e.deltaY > 0 ? 1 : -1;\n                  selectOption(col.id, activeIdx + delta, col.options.length);\n                }}\n                onKeyDown={(e) => {\n                  if (e.key === \"ArrowDown\") {\n                    e.preventDefault();\n                    selectOption(col.id, activeIdx + 1, col.options.length);\n                  } else if (e.key === \"ArrowUp\") {\n                    e.preventDefault();\n                    selectOption(col.id, activeIdx - 1, col.options.length);\n                  }\n                }}\n                className=\"relative h-[180px] flex-1 overflow-hidden focus-visible:outline-none\"\n              >\n                <motion.div\n                  drag=\"y\"\n                  dragConstraints={{ top: 0, bottom: 0 }}\n                  dragElastic={0.2}\n                  onDragEnd={(\n                    _: MouseEvent | TouchEvent | PointerEvent,\n                    info: PanInfo\n                  ) => {\n                    const stepsMoved = Math.round(\n                      -info.offset.y / (ITEM_HEIGHT * 0.75)\n                    );\n                    if (stepsMoved !== 0) {\n                      selectOption(\n                        col.id,\n                        activeIdx + stepsMoved,\n                        col.options.length\n                      );\n                    }\n                  }}\n                  animate={{ y: offsetY }}\n                  transition={\n                    shouldReduceMotion\n                      ? { duration: 0 }\n                      : { type: \"spring\", stiffness: 380, damping: 32 }\n                  }\n                  className=\"cursor-grab active:cursor-grabbing\"\n                >\n                  {col.options.map((opt, idx) => {\n                    const distance = idx - activeIdx;\n                    const absDist = Math.abs(distance);\n                    const isSelected = distance === 0;\n\n                    return (\n                      <button\n                        key={opt}\n                        type=\"button\"\n                        role=\"option\"\n                        aria-selected={isSelected}\n                        onClick={() =>\n                          selectOption(col.id, idx, col.options.length)\n                        }\n                        style={{\n                          height: ITEM_HEIGHT,\n                          transform: shouldReduceMotion\n                            ? undefined\n                            : `perspective(300px) rotateX(${distance * -18}deg) scale(${Math.max(0.82, 1 - absDist * 0.08)})`,\n                        }}\n                        className={cn(\n                          \"flex w-full items-center justify-center px-1 text-center font-mono text-xs transition-opacity\",\n                          isSelected\n                            ? \"font-bold text-neutral-950 opacity-100 dark:text-white\"\n                            : absDist === 1\n                              ? \"font-medium text-neutral-500 opacity-70 dark:text-neutral-400\"\n                              : \"text-neutral-400 opacity-35 dark:text-neutral-600\"\n                        )}\n                      >\n                        <span className=\"truncate\">{opt}</span>\n                      </button>\n                    );\n                  })}\n                </motion.div>\n              </div>\n            );\n          })}\n        </div>\n      </div>\n\n      <p className=\"mt-2.5 text-center text-[11px] text-neutral-400 dark:text-neutral-500\">\n        Scroll wheel, drag vertically, or click any row to snap\n      </p>\n    </div>\n  );\n}\n\nexport default PickerWheel;\n",
          "type": "registry:ui",
          "target": "components/ui/picker-wheel.tsx"
        },
        {
          "path": "lib/utils.ts",
          "content": "import { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...inputs: ClassValue[]) {\n  return twMerge(clsx(inputs));\n}\n\nexport async function copyToClipboard(text: string): Promise<boolean> {\n  if (typeof window === \"undefined\") return false;\n\n  try {\n    if (navigator.clipboard && window.isSecureContext) {\n      await navigator.clipboard.writeText(text);\n      return true;\n    }\n\n    const textArea = document.createElement(\"textarea\");\n    textArea.value = text;\n    textArea.style.position = \"fixed\";\n    textArea.style.left = \"-999999px\";\n    textArea.style.top = \"-999999px\";\n    document.body.appendChild(textArea);\n    textArea.focus();\n    textArea.select();\n    const succeeded = document.execCommand(\"copy\");\n    textArea.remove();\n    return succeeded;\n  } catch {\n    return false;\n  }\n}\n",
          "type": "registry:lib",
          "target": "lib/utils.ts"
        }
      ]
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "planet-horizon",
      "type": "registry:ui",
      "title": "Planet Horizon",
      "author": "Rishabh Bose <https://theb0se.vercel.app/>",
      "description": "Orbital sunrise-from-space hero background featuring a twinkling starfield, a giant curved planetary sphere with a multi-layered glowing atmospheric limb, and an animated anamorphic solar flare cresting along the terminator.",
      "dependencies": [
        "lucide-react",
        "clsx",
        "tailwind-merge"
      ],
      "files": [
        {
          "path": "components/ui/planet-horizon.tsx",
          "content": "\"use client\";\n\nimport React, { useEffect, useRef, useState } from \"react\";\nimport { Globe, Sun, Play, Pause, Sliders } from \"lucide-react\";\nimport { cn } from \"@/lib/utils\";\n\nexport interface PlanetHorizonProps {\n  /** Primary glow color of the planetary atmospheric limb (default: \"#38BDF8\") */\n  atmosphereColor?: string;\n  /** Core highlight color of the cresting orbital sun flare (default: \"#FDE047\") */\n  flareColor?: string;\n  /** Normalized position of the solar flare along the horizon arc from 0 to 1 (default: 0.5) */\n  flarePosition?: number;\n  /** Whether the solar flare automatically orbits along the planetary limb (default: true) */\n  autoplay?: boolean;\n  /** Number of twinkling background stars in upper space (default: 140) */\n  starDensity?: number;\n  /** Optional foreground content rendered over the horizon scene */\n  children?: React.ReactNode;\n  /** Additional CSS classes for the root container */\n  className?: string;\n}\n\ninterface Star {\n  x: number;\n  y: number;\n  radius: number;\n  baseAlpha: number;\n  speed: number;\n  phase: number;\n  tint: string;\n}\n\ninterface CityHub {\n  /** Angle offset from top of planet sphere (-0.38 to +0.38 rad) */\n  angle: number;\n  /** Radial depth inward from the planetary horizon limb (0.015 to 0.22 of planetRadius) */\n  depthFrac: number;\n  size: number;\n  intensity: number;\n  satellites: Array<{ dx: number; dy: number; r: number; alpha: number }>;\n  links: number[];\n}\n\ninterface CloudBand {\n  angle: number;\n  depthFrac: number;\n  arcSpan: number;\n  thickness: number;\n  alpha: number;\n  speed: number;\n}\n\nfunction hexToRgb(hex: string): { r: number; g: number; b: number } {\n  const cleaned = hex.replace(\"#\", \"\").trim();\n  const full =\n    cleaned.length === 3\n      ? cleaned\n          .split(\"\")\n          .map((c) => c + c)\n          .join(\"\")\n      : cleaned.padEnd(6, \"0\").slice(0, 6);\n  const num = parseInt(full, 16);\n  if (Number.isNaN(num)) return { r: 56, g: 189, b: 248 };\n  return {\n    r: (num >> 16) & 255,\n    g: (num >> 8) & 255,\n    b: num & 255,\n  };\n}\n\nconst HORIZON_PRESETS = [\n  {\n    name: \"ISS Terra Dawn\",\n    atmosphereColor: \"#38BDF8\",\n    flareColor: \"#FDE047\",\n  },\n  {\n    name: \"Exoplanet Violet\",\n    atmosphereColor: \"#A855F7\",\n    flareColor: \"#F472B6\",\n  },\n  {\n    name: \"Martian Amber\",\n    atmosphereColor: \"#F97316\",\n    flareColor: \"#FEF08A\",\n  },\n] as const;\n\nexport function PlanetHorizon({\n  atmosphereColor = \"#38BDF8\",\n  flareColor = \"#FDE047\",\n  flarePosition = 0.5,\n  autoplay = true,\n  starDensity = 140,\n  children,\n  className,\n}: PlanetHorizonProps) {\n  const containerRef = useRef<HTMLDivElement>(null);\n  const canvasRef = useRef<HTMLCanvasElement>(null);\n\n  const [activeAtmoColor, setActiveAtmoColor] = useState(atmosphereColor);\n  const [activeFlareColor, setActiveFlareColor] = useState(flareColor);\n  const [activeFlarePos, setActiveFlarePos] = useState(flarePosition);\n  const [isAutoplay, setIsAutoplay] = useState(autoplay);\n  useEffect(() => {\n    setActiveAtmoColor(atmosphereColor);\n  }, [atmosphereColor]);\n  useEffect(() => {\n    setActiveFlareColor(flareColor);\n  }, [flareColor]);\n  useEffect(() => {\n    setActiveFlarePos(flarePosition);\n  }, [flarePosition]);\n  useEffect(() => {\n    setIsAutoplay(autoplay);\n  }, [autoplay]);\n\n  useEffect(() => {\n    const container = containerRef.current;\n    const canvas = canvasRef.current;\n    if (!container || !canvas) return;\n\n    const ctx = canvas.getContext(\"2d\");\n    if (!ctx) return;\n\n    let width = container.clientWidth || 800;\n    let height = container.clientHeight || 520;\n    let dpr = Math.min(window.devicePixelRatio || 1, 2);\n\n    const resize = () => {\n      if (!container || !canvas) return;\n      width = container.clientWidth || 800;\n      height = container.clientHeight || 520;\n      dpr = Math.min(window.devicePixelRatio || 1, 2);\n      canvas.width = Math.floor(width * dpr);\n      canvas.height = Math.floor(height * dpr);\n      ctx.setTransform(dpr, 0, 0, dpr, 0, 0);\n    };\n\n    resize();\n    const observer = new ResizeObserver(resize);\n    observer.observe(container);\n\n    const tints = [\"#FFFFFF\", \"#E0F2FE\", \"#FEF3C7\", \"#DDD6FE\", \"#BAE6FD\"];\n    const count = Math.max(20, Math.min(400, starDensity));\n    const stars: Star[] = Array.from({ length: count }, () => ({\n      x: Math.random(),\n      y: Math.random() * 0.84,\n      radius: 0.35 + Math.random() * 1.35,\n      baseAlpha: 0.25 + Math.random() * 0.75,\n      speed: 0.6 + Math.random() * 2.2,\n      phase: Math.random() * Math.PI * 2,\n      tint: tints[Math.floor(Math.random() * tints.length)],\n    }));\n\n    // Generate realistic night-side metropolitan hubs & spiderweb highway corridors\n    const hubCount = 26;\n    const cityHubs: CityHub[] = Array.from({ length: hubCount }, (_, i) => {\n      const spread = (i / (hubCount - 1) - 0.5) * 0.66 + (Math.random() - 0.5) * 0.04;\n      const depthFrac = 0.014 + Math.pow(Math.random(), 1.35) * 0.16;\n      const satCount = 8 + Math.floor(Math.random() * 12);\n      const satellites = Array.from({ length: satCount }, () => {\n        const a = Math.random() * Math.PI * 2;\n        const dist = Math.pow(Math.random(), 1.6) * 28;\n        return {\n          dx: Math.cos(a) * dist * 1.35,\n          dy: Math.sin(a) * dist * 0.65,\n          r: 0.5 + Math.random() * 1.15,\n          alpha: 0.3 + Math.random() * 0.7,\n        };\n      });\n      return {\n        angle: -Math.PI / 2 + spread,\n        depthFrac,\n        size: 1.6 + Math.random() * 2.2,\n        intensity: 0.55 + Math.random() * 0.45,\n        satellites,\n        links: [],\n      };\n    });\n\n    // Connect nearby metropolitan hubs into realistic highway/rail spiderwebs\n    for (let i = 0; i < cityHubs.length; i++) {\n      for (let j = i + 1; j < cityHubs.length; j++) {\n        const dAngle = Math.abs(cityHubs[i].angle - cityHubs[j].angle);\n        const dDepth = Math.abs(cityHubs[i].depthFrac - cityHubs[j].depthFrac);\n        if (dAngle < 0.085 && dDepth < 0.065 && cityHubs[i].links.length < 3) {\n          cityHubs[i].links.push(j);\n        }\n      }\n    }\n\n    // Generate atmospheric cloud wisps drifting over the planetary curvature\n    const cloudBands: CloudBand[] = Array.from({ length: 18 }, () => ({\n      angle: -Math.PI / 2 + (Math.random() - 0.5) * 0.72,\n      depthFrac: 0.004 + Math.random() * 0.14,\n      arcSpan: 0.03 + Math.random() * 0.065,\n      thickness: 6 + Math.random() * 16,\n      alpha: 0.08 + Math.random() * 0.14,\n      speed: 0.002 + Math.random() * 0.004,\n    }));\n\n    // Hexagonal camera aperture vertices\n    const drawHexagon = (\n      cx: number,\n      cy: number,\n      radius: number,\n      rot: number,\n      fill: string | CanvasGradient,\n      stroke?: string\n    ) => {\n      ctx.save();\n      ctx.translate(cx, cy);\n      ctx.rotate(rot);\n      ctx.beginPath();\n      for (let s = 0; s < 6; s++) {\n        const a = (s / 6) * Math.PI * 2;\n        const hx = Math.cos(a) * radius;\n        const hy = Math.sin(a) * radius;\n        if (s === 0) ctx.moveTo(hx, hy);\n        else ctx.lineTo(hx, hy);\n      }\n      ctx.closePath();\n      ctx.fillStyle = fill;\n      ctx.fill();\n      if (stroke) {\n        ctx.strokeStyle = stroke;\n        ctx.lineWidth = 1;\n        ctx.stroke();\n      }\n      ctx.restore();\n    };\n\n    let rafId = 0;\n    let time = 0;\n\n    const render = () => {\n      time += 0.012;\n      const atmoRgb = hexToRgb(activeAtmoColor);\n      const sunRgb = hexToRgb(activeFlareColor);\n\n      // Deep orbital space background\n      const bgGrad = ctx.createLinearGradient(0, 0, 0, height);\n      bgGrad.addColorStop(0, \"#010206\");\n      bgGrad.addColorStop(0.5, \"#030610\");\n      bgGrad.addColorStop(1, \"#060B18\");\n      ctx.fillStyle = bgGrad;\n      ctx.fillRect(0, 0, width, height);\n\n      // Planetary sphere geometry (giant curved Earth limb anchored below viewport)\n      const planetRadius = Math.max(width, height) * 1.58;\n      const planetCx = width * 0.5;\n      const horizonApexY = height * 0.6;\n      const planetCy = horizonApexY + planetRadius;\n\n      // Compute solar flare angle along the visible upper arc of the planet\n      const halfSpanAngle = Math.asin(\n        Math.min(0.95, (width * 0.46) / planetRadius)\n      );\n      const normalizedPos = isAutoplay\n        ? 0.5 + 0.36 * Math.sin(time * 0.42)\n        : Math.max(0, Math.min(1, activeFlarePos));\n\n      const sunAngle =\n        -Math.PI / 2 + (normalizedPos - 0.5) * 2 * halfSpanAngle;\n      // Subtle vertical cresting oscillation so the sun peeks slightly above the limb at zenith\n      const crestElevation = Math.cos((normalizedPos - 0.5) * Math.PI) * 5;\n      const sunX = planetCx + Math.cos(sunAngle) * (planetRadius + crestElevation);\n      const sunY = planetCy + Math.sin(sunAngle) * (planetRadius + crestElevation);\n      const crestIntensity = 0.78 + 0.22 * Math.cos((normalizedPos - 0.5) * Math.PI);\n\n      // Draw twinkling starfield above the planet limb (fading near solar glare)\n      for (let i = 0; i < stars.length; i++) {\n        const s = stars[i];\n        const sx = s.x * width;\n        const sy = s.y * height;\n\n        const distToCenter = Math.hypot(sx - planetCx, sy - planetCy);\n        if (distToCenter < planetRadius - 2) continue;\n\n        const distToSun = Math.hypot(sx - sunX, sy - sunY);\n        const glareSuppression = Math.min(1, distToSun / 240);\n        const twinkle = 0.6 + 0.4 * Math.sin(time * s.speed + s.phase);\n\n        ctx.globalAlpha = s.baseAlpha * twinkle * glareSuppression;\n        ctx.fillStyle = s.tint;\n        ctx.beginPath();\n        ctx.arc(sx, sy, s.radius, 0, Math.PI * 2);\n        ctx.fill();\n      }\n      ctx.globalAlpha = 1;\n\n      // 1. Multi-Wavelength Rayleigh Atmospheric Scattering (Exosphere -> Mesosphere -> Stratosphere -> Troposphere)\n      ctx.save();\n      ctx.globalCompositeOperation = \"screen\";\n\n      // Deep Cobalt Upper Mesosphere & Thermosphere Halo\n      const mesosphereGrad = ctx.createRadialGradient(\n        planetCx,\n        planetCy,\n        planetRadius * 0.985,\n        planetCx,\n        planetCy,\n        planetRadius * 1.095\n      );\n      mesosphereGrad.addColorStop(0, \"rgba(0, 0, 0, 0)\");\n      mesosphereGrad.addColorStop(\n        0.14,\n        `rgba(${atmoRgb.r}, ${atmoRgb.g}, ${atmoRgb.b}, 0.72)`\n      );\n      mesosphereGrad.addColorStop(\n        0.38,\n        `rgba(${Math.round(atmoRgb.r * 0.35)}, ${Math.round(\n          atmoRgb.g * 0.55\n        )}, 245, 0.38)`\n      );\n      mesosphereGrad.addColorStop(0.72, \"rgba(15, 40, 120, 0.12)\");\n      mesosphereGrad.addColorStop(1, \"rgba(0, 0, 0, 0)\");\n\n      ctx.fillStyle = mesosphereGrad;\n      ctx.beginPath();\n      ctx.arc(planetCx, planetCy, planetRadius * 1.095, 0, Math.PI * 2);\n      ctx.fill();\n\n      // Localized Solar Terminator Rayleigh Spectrum (Warm Amber/Gold Troposphere -> Cyan Stratosphere -> Cobalt)\n      const terminatorRadius = Math.max(width, height) * 0.62;\n      const terminatorScatter = ctx.createRadialGradient(\n        sunX,\n        sunY,\n        4,\n        sunX,\n        sunY,\n        terminatorRadius\n      );\n      terminatorScatter.addColorStop(\n        0,\n        `rgba(255, 250, 230, ${(0.75 * crestIntensity).toFixed(3)})`\n      );\n      terminatorScatter.addColorStop(\n        0.12,\n        `rgba(${sunRgb.r}, ${sunRgb.g}, ${sunRgb.b}, ${(0.58 * crestIntensity).toFixed(3)})`\n      );\n      terminatorScatter.addColorStop(\n        0.28,\n        `rgba(249, 115, 22, ${(0.32 * crestIntensity).toFixed(3)})`\n      );\n      terminatorScatter.addColorStop(\n        0.52,\n        `rgba(${atmoRgb.r}, ${atmoRgb.g}, ${atmoRgb.b}, 0.24)`\n      );\n      terminatorScatter.addColorStop(1, \"rgba(0, 0, 0, 0)\");\n\n      ctx.fillStyle = terminatorScatter;\n      ctx.fillRect(0, 0, width, height);\n      ctx.restore();\n\n      // 2. Planetary Sphere Body, Night-Side City Networks & Terminator Cloud Wisps\n      ctx.save();\n      ctx.beginPath();\n      ctx.arc(planetCx, planetCy, planetRadius, 0, Math.PI * 2);\n      ctx.clip();\n\n      // Base planetary surface gradient (sunlit terminator twilight vs deep night side)\n      const bodyGrad = ctx.createRadialGradient(\n        sunX,\n        sunY + 30,\n        planetRadius * 0.02,\n        planetCx,\n        planetCy,\n        planetRadius\n      );\n      bodyGrad.addColorStop(\n        0,\n        `rgba(${Math.round(atmoRgb.r * 0.35 + sunRgb.r * 0.15)}, ${Math.round(\n          atmoRgb.g * 0.38 + sunRgb.g * 0.12\n        )}, ${Math.round(atmoRgb.b * 0.45)}, 1)`\n      );\n      bodyGrad.addColorStop(0.18, \"#09152B\");\n      bodyGrad.addColorStop(0.45, \"#040814\");\n      bodyGrad.addColorStop(1, \"#020308\");\n\n      ctx.fillStyle = bodyGrad;\n      ctx.fillRect(0, horizonApexY - 10, width, height - horizonApexY + 20);\n\n      // Compute screen positions for night-side city hubs & render spiderweb highways\n      const hubPositions = cityHubs.map((hub) => {\n        const r = planetRadius * (1 - hub.depthFrac);\n        const rotAngle = hub.angle + Math.sin(time * 0.08) * 0.02;\n        const hx = planetCx + Math.cos(rotAngle) * r;\n        const hy = planetCy + Math.sin(rotAngle) * r;\n        // Fade out city lights where sunlight illuminates the terminator\n        const distFromSun = Math.hypot(hx - sunX, hy - sunY);\n        const nightFactor = Math.max(\n          0,\n          Math.min(1, (distFromSun - 110) / 210)\n        );\n        // Perspective foreshortening near the curved limb\n        const limbForeshorten = Math.min(1, hub.depthFrac * 18);\n        return { hx, hy, nightFactor, limbForeshorten, hub };\n      });\n\n      ctx.save();\n      ctx.globalCompositeOperation = \"lighter\";\n\n      // Draw interconnecting spiderweb highway tendrils\n      for (let i = 0; i < hubPositions.length; i++) {\n        const p1 = hubPositions[i];\n        if (p1.nightFactor <= 0.05) continue;\n\n        for (const targetIdx of p1.hub.links) {\n          const p2 = hubPositions[targetIdx];\n          const linkAlpha =\n            Math.min(p1.nightFactor, p2.nightFactor) * 0.24 * p1.hub.intensity;\n          if (linkAlpha <= 0.02) continue;\n\n          ctx.strokeStyle = `rgba(251, 191, 36, ${linkAlpha.toFixed(3)})`;\n          ctx.lineWidth = 0.75;\n          ctx.beginPath();\n          const midX = (p1.hx + p2.hx) * 0.5;\n          const midY = (p1.hy + p2.hy) * 0.5 - 4;\n          ctx.moveTo(p1.hx, p1.hy);\n          ctx.quadraticCurveTo(midX, midY, p2.hx, p2.hy);\n          ctx.stroke();\n        }\n      }\n\n      // Draw metropolitan sodium-vapor golden cores & suburban sprawl clusters\n      for (let i = 0; i < hubPositions.length; i++) {\n        const { hx, hy, nightFactor, limbForeshorten, hub } = hubPositions[i];\n        if (nightFactor <= 0.04) continue;\n\n        const baseAlpha = nightFactor * hub.intensity;\n\n        // Warm sodium-vapor atmospheric glow around major metro hub\n        const cityGlow = ctx.createRadialGradient(\n          hx,\n          hy,\n          0,\n          hx,\n          hy,\n          hub.size * 9\n        );\n        cityGlow.addColorStop(0, `rgba(254, 240, 138, ${(baseAlpha * 0.55).toFixed(3)})`);\n        cityGlow.addColorStop(0.35, `rgba(245, 158, 11, ${(baseAlpha * 0.25).toFixed(3)})`);\n        cityGlow.addColorStop(1, \"rgba(0, 0, 0, 0)\");\n\n        ctx.fillStyle = cityGlow;\n        ctx.beginPath();\n        ctx.ellipse(\n          hx,\n          hy,\n          hub.size * 9,\n          hub.size * 9 * (0.38 + 0.45 * limbForeshorten),\n          0,\n          0,\n          Math.PI * 2\n        );\n        ctx.fill();\n\n        // Crisp metropolitan core\n        ctx.fillStyle = `rgba(255, 251, 235, ${(baseAlpha * 0.9).toFixed(3)})`;\n        ctx.beginPath();\n        ctx.arc(hx, hy, hub.size * 0.65, 0, Math.PI * 2);\n        ctx.fill();\n\n        // Satellite towns & arterial nodes\n        for (let s = 0; s < hub.satellites.length; s++) {\n          const sat = hub.satellites[s];\n          const sx = hx + sat.dx;\n          const sy = hy + sat.dy * (0.4 + 0.5 * limbForeshorten);\n          ctx.fillStyle = `rgba(253, 186, 116, ${(\n            baseAlpha *\n            sat.alpha *\n            0.75\n          ).toFixed(3)})`;\n          ctx.beginPath();\n          ctx.arc(sx, sy, sat.r, 0, Math.PI * 2);\n          ctx.fill();\n        }\n      }\n      ctx.restore();\n\n      // Atmospheric Cloud Wisps illuminated near the terminator & diffusing night lights\n      ctx.save();\n      for (let i = 0; i < cloudBands.length; i++) {\n        const c = cloudBands[i];\n        const r = planetRadius * (1 - c.depthFrac);\n        const startA = c.angle - c.arcSpan * 0.5 + Math.sin(time * c.speed) * 0.02;\n        const endA = startA + c.arcSpan;\n        const midA = (startA + endA) * 0.5;\n        const cx = planetCx + Math.cos(midA) * r;\n        const cy = planetCy + Math.sin(midA) * r;\n        const distSun = Math.hypot(cx - sunX, cy - sunY);\n        const sunLit = Math.max(0, 1 - distSun / 340);\n\n        ctx.strokeStyle =\n          sunLit > 0.25\n            ? `rgba(${sunRgb.r}, ${sunRgb.g}, ${sunRgb.b}, ${(\n                c.alpha *\n                (0.5 + sunLit * 1.2)\n              ).toFixed(3)})`\n            : `rgba(${atmoRgb.r}, ${atmoRgb.g}, ${atmoRgb.b}, ${(\n                c.alpha * 0.55\n              ).toFixed(3)})`;\n        ctx.lineWidth = c.thickness;\n        ctx.lineCap = \"round\";\n        ctx.beginPath();\n        ctx.arc(planetCx, planetCy, r, startA, endA);\n        ctx.stroke();\n      }\n      ctx.restore();\n\n      // Inner atmospheric horizon haze along the curved planetary rim\n      const innerRimGrad = ctx.createRadialGradient(\n        planetCx,\n        planetCy,\n        planetRadius * 0.982,\n        planetCx,\n        planetCy,\n        planetRadius\n      );\n      innerRimGrad.addColorStop(0, \"rgba(0, 0, 0, 0)\");\n      innerRimGrad.addColorStop(\n        0.65,\n        `rgba(${atmoRgb.r}, ${atmoRgb.g}, ${atmoRgb.b}, 0.22)`\n      );\n      innerRimGrad.addColorStop(\n        0.92,\n        `rgba(${atmoRgb.r}, ${atmoRgb.g}, ${atmoRgb.b}, 0.62)`\n      );\n      innerRimGrad.addColorStop(\n        1,\n        `rgba(224, 242, 254, 0.85)`\n      );\n      ctx.fillStyle = innerRimGrad;\n      ctx.fillRect(0, horizonApexY - 20, width, height);\n      ctx.restore();\n\n      // 3. Multi-Band Atmospheric Limb Rim (Troposphere Gold -> Stratosphere Cyan -> Mesosphere Blue)\n      ctx.save();\n      ctx.globalCompositeOperation = \"lighter\";\n\n      // Stratospheric cyan-blue glow band\n      ctx.strokeStyle = `rgba(${atmoRgb.r}, ${atmoRgb.g}, ${atmoRgb.b}, 0.72)`;\n      ctx.lineWidth = 6.5;\n      ctx.beginPath();\n      ctx.arc(\n        planetCx,\n        planetCy,\n        planetRadius + 1.5,\n        -Math.PI * 0.85,\n        -Math.PI * 0.15\n      );\n      ctx.stroke();\n\n      // Warm golden-amber tropospheric refraction band near the sun\n      const spanNearSun = 0.16;\n      ctx.strokeStyle = `rgba(251, 146, 60, ${(0.75 * crestIntensity).toFixed(3)})`;\n      ctx.lineWidth = 4.2;\n      ctx.beginPath();\n      ctx.arc(\n        planetCx,\n        planetCy,\n        planetRadius - 0.5,\n        sunAngle - spanNearSun,\n        sunAngle + spanNearSun\n      );\n      ctx.stroke();\n\n      // Razor-sharp incandescent airglow limb edge\n      ctx.strokeStyle = \"rgba(240, 249, 255, 0.95)\";\n      ctx.lineWidth = 1.6;\n      ctx.beginPath();\n      ctx.arc(\n        planetCx,\n        planetCy,\n        planetRadius,\n        -Math.PI * 0.82,\n        -Math.PI * 0.18\n      );\n      ctx.stroke();\n\n      // 4. Physical Solar Corona, Starburst & Anamorphic Hexagonal Lens Flare\n      const bloomRadius = 185 * crestIntensity;\n      const flareBloom = ctx.createRadialGradient(\n        sunX,\n        sunY,\n        0,\n        sunX,\n        sunY,\n        bloomRadius\n      );\n      flareBloom.addColorStop(0, \"rgba(255, 255, 255, 1)\");\n      flareBloom.addColorStop(0.09, \"rgba(255, 253, 240, 0.98)\");\n      flareBloom.addColorStop(\n        0.22,\n        `rgba(${sunRgb.r}, ${sunRgb.g}, ${sunRgb.b}, 0.85)`\n      );\n      flareBloom.addColorStop(\n        0.48,\n        `rgba(${atmoRgb.r}, ${atmoRgb.g}, ${atmoRgb.b}, 0.35)`\n      );\n      flareBloom.addColorStop(1, \"rgba(0, 0, 0, 0)\");\n\n      ctx.fillStyle = flareBloom;\n      ctx.beginPath();\n      ctx.arc(sunX, sunY, bloomRadius, 0, Math.PI * 2);\n      ctx.fill();\n\n      // Primary & secondary anamorphic horizontal lens streaks\n      const streakWidth = Math.min(width * 0.82, 580) * crestIntensity;\n      const streakGrad = ctx.createLinearGradient(\n        sunX - streakWidth,\n        sunY,\n        sunX + streakWidth,\n        sunY\n      );\n      streakGrad.addColorStop(0, \"rgba(0, 0, 0, 0)\");\n      streakGrad.addColorStop(\n        0.2,\n        `rgba(${atmoRgb.r}, ${atmoRgb.g}, ${atmoRgb.b}, 0.18)`\n      );\n      streakGrad.addColorStop(\n        0.42,\n        `rgba(${atmoRgb.r}, ${atmoRgb.g}, ${atmoRgb.b}, 0.58)`\n      );\n      streakGrad.addColorStop(0.5, \"rgba(255, 255, 255, 1)\");\n      streakGrad.addColorStop(\n        0.58,\n        `rgba(${atmoRgb.r}, ${atmoRgb.g}, ${atmoRgb.b}, 0.58)`\n      );\n      streakGrad.addColorStop(\n        0.8,\n        `rgba(${atmoRgb.r}, ${atmoRgb.g}, ${atmoRgb.b}, 0.18)`\n      );\n      streakGrad.addColorStop(1, \"rgba(0, 0, 0, 0)\");\n\n      ctx.fillStyle = streakGrad;\n      ctx.beginPath();\n      ctx.ellipse(sunX, sunY, streakWidth, 2.8, 0, 0, Math.PI * 2);\n      ctx.fill();\n\n      ctx.beginPath();\n      ctx.ellipse(sunX, sunY - 3.5, streakWidth * 0.55, 1.1, 0, 0, Math.PI * 2);\n      ctx.fill();\n\n      // 6-Blade Aperture Diffraction Starburst Spikes\n      const bladeAngles = [-0.52, 0.52, -1.05, 1.05, Math.PI / 2];\n      for (const rayAngle of bladeAngles) {\n        ctx.save();\n        ctx.translate(sunX, sunY);\n        ctx.rotate(rayAngle);\n        const rayLen =\n          (rayAngle === Math.PI / 2 ? 115 : 165) * crestIntensity;\n        const rayGrad = ctx.createLinearGradient(-rayLen, 0, rayLen, 0);\n        rayGrad.addColorStop(0, \"rgba(0, 0, 0, 0)\");\n        rayGrad.addColorStop(\n          0.5,\n          `rgba(${sunRgb.r}, ${sunRgb.g}, ${sunRgb.b}, 0.55)`\n        );\n        rayGrad.addColorStop(1, \"rgba(0, 0, 0, 0)\");\n        ctx.fillStyle = rayGrad;\n        ctx.beginPath();\n        ctx.ellipse(0, 0, rayLen, 1.35, 0, 0, Math.PI * 2);\n        ctx.fill();\n        ctx.restore();\n      }\n\n      // Hexagonal Camera Aperture Ghost Reflections along optical axis\n      const vecX = width * 0.5 - sunX;\n      const vecY = height * 0.44 - sunY;\n      const hexGhosts = [\n        { t: 0.35, r: 16, alpha: 0.16, tint: \"cyan\" },\n        { t: 0.65, r: 28, alpha: 0.11, tint: \"gold\" },\n        { t: 0.95, r: 12, alpha: 0.22, tint: \"cyan\" },\n        { t: 1.28, r: 42, alpha: 0.09, tint: \"violet\" },\n        { t: 1.58, r: 22, alpha: 0.14, tint: \"gold\" },\n        { t: 1.85, r: 58, alpha: 0.07, tint: \"cyan\" },\n      ] as const;\n\n      for (const g of hexGhosts) {\n        const gx = sunX + vecX * g.t;\n        const gy = sunY + vecY * g.t;\n        const a = g.alpha * crestIntensity;\n        const gGrad = ctx.createRadialGradient(gx, gy, g.r * 0.15, gx, gy, g.r);\n\n        if (g.tint === \"gold\") {\n          gGrad.addColorStop(0, `rgba(${sunRgb.r}, ${sunRgb.g}, ${sunRgb.b}, ${(a * 0.35).toFixed(3)})`);\n          gGrad.addColorStop(0.82, `rgba(251, 191, 36, ${a.toFixed(3)})`);\n        } else if (g.tint === \"violet\") {\n          gGrad.addColorStop(0, `rgba(168, 85, 247, ${(a * 0.3).toFixed(3)})`);\n          gGrad.addColorStop(0.82, `rgba(236, 72, 153, ${a.toFixed(3)})`);\n        } else {\n          gGrad.addColorStop(0, `rgba(${atmoRgb.r}, ${atmoRgb.g}, ${atmoRgb.b}, ${(a * 0.35).toFixed(3)})`);\n          gGrad.addColorStop(0.82, `rgba(125, 211, 252, ${a.toFixed(3)})`);\n        }\n        gGrad.addColorStop(1, \"rgba(0, 0, 0, 0)\");\n\n        drawHexagon(\n          gx,\n          gy,\n          g.r,\n          0.25 + g.t * 0.3,\n          gGrad,\n          `rgba(255, 255, 255, ${(a * 0.45).toFixed(3)})`\n        );\n      }\n\n      ctx.restore();\n\n      rafId = requestAnimationFrame(render);\n    };\n\n    rafId = requestAnimationFrame(render);\n\n    return () => {\n      cancelAnimationFrame(rafId);\n      observer.disconnect();\n    };\n  }, [activeAtmoColor, activeFlareColor, activeFlarePos, isAutoplay, starDensity]);\n\n  return (\n    <div\n      ref={containerRef}\n      data-fullscreen-scroll\n      className={cn(\n        \"relative w-full min-h-[520px] overflow-hidden rounded-2xl bg-[#010206] text-white select-none\",\n        className\n      )}\n    >\n      <canvas\n        ref={canvasRef}\n        aria-hidden=\"true\"\n        className=\"pointer-events-none absolute inset-0 h-full w-full\"\n      />\n\n      {children && (\n        <div className=\"relative z-10 flex min-h-[520px] w-full flex-col\">\n          {children}\n        </div>\n      )}\n    </div>\n  );\n}\n\nexport default PlanetHorizon;\n",
          "type": "registry:ui",
          "target": "components/ui/planet-horizon.tsx"
        },
        {
          "path": "lib/utils.ts",
          "content": "import { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...inputs: ClassValue[]) {\n  return twMerge(clsx(inputs));\n}\n\nexport async function copyToClipboard(text: string): Promise<boolean> {\n  if (typeof window === \"undefined\") return false;\n\n  try {\n    if (navigator.clipboard && window.isSecureContext) {\n      await navigator.clipboard.writeText(text);\n      return true;\n    }\n\n    const textArea = document.createElement(\"textarea\");\n    textArea.value = text;\n    textArea.style.position = \"fixed\";\n    textArea.style.left = \"-999999px\";\n    textArea.style.top = \"-999999px\";\n    document.body.appendChild(textArea);\n    textArea.focus();\n    textArea.select();\n    const succeeded = document.execCommand(\"copy\");\n    textArea.remove();\n    return succeeded;\n  } catch {\n    return false;\n  }\n}\n",
          "type": "registry:lib",
          "target": "lib/utils.ts"
        }
      ]
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "plus-grid-border",
      "type": "registry:ui",
      "title": "Plus Grid Border",
      "author": "Rishabh Bose <https://theb0se.vercel.app/>",
      "description": "Vercel-inspired blueprint grid architecture with precision hairline section borders and interactive corner plus markers that illuminate on pointer proximity.",
      "dependencies": [
        "framer-motion",
        "lucide-react",
        "clsx",
        "tailwind-merge"
      ],
      "files": [
        {
          "path": "components/ui/plus-grid-border.tsx",
          "content": "\"use client\";\n\nimport React, { useState, useRef, useCallback } from \"react\";\nimport { motion } from \"framer-motion\";\nimport {\n  Sparkles,\n  Layers,\n  Cpu,\n  GitBranch,\n  ShieldCheck,\n  Zap,\n  ArrowUpRight,\n  Maximize2,\n  Sliders,\n  Compass,\n} from \"lucide-react\";\nimport { cn } from \"@/lib/utils\";\n\nexport interface GridCardItem {\n  id: string;\n  tag: string;\n  title: string;\n  description: string;\n  metric?: string;\n  icon?: React.ReactNode;\n}\n\nexport interface PlusGridBorderProps {\n  items?: GridCardItem[];\n  glowColor?: \"cyan\" | \"violet\" | \"emerald\" | \"amber\";\n  interactiveProximity?: boolean;\n  className?: string;\n}\n\nconst DEFAULT_CARDS: GridCardItem[] = [\n  {\n    id: \"edge-compute\",\n    tag: \"01 // COMPUTE\",\n    title: \"Edge Runtime Execution\",\n    description: \"Zero-cold-start V8 isolates executing sub-millisecond payloads at 310 global edge nodes.\",\n    metric: \"0.4ms TTFB\",\n  },\n  {\n    id: \"turborepo\",\n    tag: \"02 // PIPELINE\",\n    title: \"Remote Cache Artifacts\",\n    description: \"Multi-tenant build hashes cached across continuous CI runners with bit-level reproducibility.\",\n    metric: \"98.2% Cache Hit\",\n  },\n  {\n    id: \"ddos-guard\",\n    tag: \"03 // SECURITY\",\n    title: \"Layer 7 Anomaly Shield\",\n    description: \"Automated eBPF packet mitigation absorbing volumetric SYN floods and synthetic bot scrapers.\",\n    metric: \"40Tbps Capacity\",\n  },\n  {\n    id: \"instant-rollback\",\n    tag: \"04 // ORCHESTRATION\",\n    title: \"Atomic Deployment Slugs\",\n    description: \"Zero-downtime DNS pointer swaps allowing instantaneous rollback to any previous immutable release.\",\n    metric: \"1-Click Rollback\",\n  },\n];\n\nconst GLOW_THEMES = {\n  cyan: {\n    accent: \"text-cyan-400\",\n    bgAccent: \"bg-cyan-500/10\",\n    borderAccent: \"border-cyan-500/40\",\n    glow: \"rgba(6, 182, 212, 0.4)\",\n    crossColor: \"text-cyan-400 drop-shadow-[0_0_8px_rgba(6,182,212,0.8)]\",\n    pill: \"border-cyan-500/30 text-cyan-400 bg-cyan-950/40\",\n  },\n  violet: {\n    accent: \"text-violet-400\",\n    bgAccent: \"bg-violet-500/10\",\n    borderAccent: \"border-violet-500/40\",\n    glow: \"rgba(139, 92, 246, 0.4)\",\n    crossColor: \"text-violet-400 drop-shadow-[0_0_8px_rgba(139,92,246,0.8)]\",\n    pill: \"border-violet-500/30 text-violet-400 bg-violet-950/40\",\n  },\n  emerald: {\n    accent: \"text-emerald-400\",\n    bgAccent: \"bg-emerald-500/10\",\n    borderAccent: \"border-emerald-500/40\",\n    glow: \"rgba(16, 185, 129, 0.4)\",\n    crossColor: \"text-emerald-400 drop-shadow-[0_0_8px_rgba(16,185,129,0.8)]\",\n    pill: \"border-emerald-500/30 text-emerald-400 bg-emerald-950/40\",\n  },\n  amber: {\n    accent: \"text-amber-400\",\n    bgAccent: \"bg-amber-500/10\",\n    borderAccent: \"border-amber-500/40\",\n    glow: \"rgba(245, 158, 11, 0.4)\",\n    crossColor: \"text-amber-400 drop-shadow-[0_0_8px_rgba(245,158,11,0.8)]\",\n    pill: \"border-amber-500/30 text-amber-400 bg-amber-950/40\",\n  },\n};\n\nexport function PlusGridBorder({\n  items = DEFAULT_CARDS,\n  glowColor = \"cyan\",\n  interactiveProximity = true,\n  className,\n}: PlusGridBorderProps) {\n  const containerRef = useRef<HTMLDivElement>(null);\n  const [activeTheme, setActiveTheme] = useState<\"cyan\" | \"violet\" | \"emerald\" | \"amber\">(glowColor);\n  const [crossSize, setCrossSize] = useState<\"sm\" | \"md\" | \"lg\">(\"md\");\n  const [proximityActive, setProximityActive] = useState<boolean>(interactiveProximity);\n  const [mousePos, setMousePos] = useState<{ x: number; y: number } | null>(null);\n  const [activeCardId, setActiveCardId] = useState<string | null>(null);\n\n  const theme = GLOW_THEMES[activeTheme];\n\n  const handleMouseMove = useCallback((e: React.MouseEvent<HTMLDivElement>) => {\n    if (!containerRef.current) return;\n    const rect = containerRef.current.getBoundingClientRect();\n    setMousePos({\n      x: e.clientX - rect.left,\n      y: e.clientY - rect.top,\n    });\n  }, []);\n\n  const handleMouseLeave = useCallback(() => {\n    setMousePos(null);\n  }, []);\n\n  // Cross marker renderer\n  const renderCross = (positionClasses: string, keyId: string) => {\n    return (\n      <div\n        key={keyId}\n        aria-hidden=\"true\"\n        className={cn(\n          \"pointer-events-none absolute z-20 flex items-center justify-center -translate-x-1/2 -translate-y-1/2 select-none font-mono transition-colors duration-300\",\n          positionClasses,\n          crossSize === \"sm\" && \"text-xs h-3 w-3\",\n          crossSize === \"md\" && \"text-sm h-4 w-4\",\n          crossSize === \"lg\" && \"text-base h-5 w-5\",\n          mousePos && proximityActive\n            ? theme.crossColor\n            : \"text-neutral-600 dark:text-neutral-500\"\n        )}\n      >\n        <span className=\"font-semibold leading-none\">+</span>\n      </div>\n    );\n  };\n\n  const getCardIcon = (index: number) => {\n    switch (index) {\n      case 0:\n        return <Zap className=\"h-4 w-4 text-neutral-400 group-hover:text-cyan-400 transition-colors\" />;\n      case 1:\n        return <GitBranch className=\"h-4 w-4 text-neutral-400 group-hover:text-cyan-400 transition-colors\" />;\n      case 2:\n        return <ShieldCheck className=\"h-4 w-4 text-neutral-400 group-hover:text-cyan-400 transition-colors\" />;\n      default:\n        return <Cpu className=\"h-4 w-4 text-neutral-400 group-hover:text-cyan-400 transition-colors\" />;\n    }\n  };\n\n  return (\n    <div\n      data-fullscreen-scroll\n      ref={containerRef}\n      onMouseMove={handleMouseMove}\n      onMouseLeave={handleMouseLeave}\n      className={cn(\n        \"relative w-full min-h-[520px] overflow-hidden rounded-2xl border border-neutral-800 bg-[#07090E] p-6 text-white shadow-2xl flex flex-col justify-between selection:bg-cyan-500/30\",\n        className\n      )}\n    >\n      {/* Background blueprint dotted grid */}\n      <div\n        className=\"pointer-events-none absolute inset-0 opacity-20\"\n        style={{\n          backgroundImage:\n            \"radial-gradient(circle at 1px 1px, rgba(255,255,255,0.15) 1px, transparent 0)\",\n          backgroundSize: \"24px 24px\",\n        }}\n      />\n\n      {/* Dynamic radial glow following pointer */}\n      {mousePos && proximityActive && (\n        <div\n          className=\"pointer-events-none absolute rounded-full blur-3xl transition-opacity duration-300 -translate-x-1/2 -translate-y-1/2\"\n          style={{\n            left: `${mousePos.x}px`,\n            top: `${mousePos.y}px`,\n            width: \"320px\",\n            height: \"320px\",\n            background: `radial-gradient(circle, ${theme.glow} 0%, transparent 70%)`,\n          }}\n        />\n      )}\n\n      {/* Header bar */}\n      <div className=\"relative z-10 flex flex-wrap items-center justify-between gap-4 border-b border-neutral-800/80 pb-4\">\n        <div className=\"flex items-center gap-2.5\">\n          <div className=\"flex h-8 w-8 items-center justify-center rounded-lg border border-neutral-700 bg-neutral-900/80 font-mono text-xs font-bold text-neutral-200\">\n            [+]\n          </div>\n          <div>\n            <h3 className=\"text-sm font-semibold tracking-tight text-white flex items-center gap-2\">\n              Blueprint Plus Grid\n              <span className={cn(\"text-[10px] uppercase font-mono px-2 py-0.5 rounded-full border\", theme.pill)}>\n                {activeTheme}\n              </span>\n            </h3>\n            <p className=\"text-xs text-neutral-400 font-mono\">\n              Vercel-style architectural frame with proximity corner crosses\n            </p>\n          </div>\n        </div>\n\n        {/* Live Controls */}\n        <div className=\"flex flex-wrap items-center gap-2\">\n          {/* Theme selector */}\n          <div className=\"flex items-center rounded-lg border border-neutral-800 bg-neutral-900/90 p-1\">\n            {([\"cyan\", \"violet\", \"emerald\", \"amber\"] as const).map((t) => (\n              <button\n                key={t}\n                onClick={() => setActiveTheme(t)}\n                className={cn(\n                  \"px-2.5 py-1 text-[11px] font-mono rounded capitalize transition-all\",\n                  activeTheme === t\n                    ? \"bg-neutral-800 text-white shadow-sm font-bold\"\n                    : \"text-neutral-400 hover:text-neutral-200\"\n                )}\n              >\n                {t}\n              </button>\n            ))}\n          </div>\n\n          {/* Cross size selector */}\n          <div className=\"flex items-center rounded-lg border border-neutral-800 bg-neutral-900/90 p-1\">\n            {([\"sm\", \"md\", \"lg\"] as const).map((s) => (\n              <button\n                key={s}\n                onClick={() => setCrossSize(s)}\n                className={cn(\n                  \"px-2 py-1 text-[10px] font-mono rounded uppercase transition-all\",\n                  crossSize === s\n                    ? \"bg-neutral-800 text-white font-bold\"\n                    : \"text-neutral-400 hover:text-neutral-200\"\n                )}\n              >\n                +{s}\n              </button>\n            ))}\n          </div>\n\n          {/* Proximity Toggle */}\n          <button\n            onClick={() => setProximityActive(!proximityActive)}\n            className={cn(\n              \"flex items-center gap-1.5 px-2.5 py-1 text-xs font-mono rounded-lg border transition-all\",\n              proximityActive\n                ? \"border-neutral-700 bg-neutral-800 text-white font-medium\"\n                : \"border-neutral-800 bg-neutral-900 text-neutral-500 hover:text-neutral-300\"\n            )}\n          >\n            <Compass className=\"h-3 w-3\" />\n            <span>{proximityActive ? \"Glow On\" : \"Glow Off\"}</span>\n          </button>\n        </div>\n      </div>\n\n      {/* Main Grid Section with Junction Crosses */}\n      <div className=\"relative my-6 grid grid-cols-1 md:grid-cols-2 gap-0 border border-neutral-800/90 bg-neutral-950/40 rounded-xl overflow-visible backdrop-blur-sm\">\n        {/* Perimeter & Intersection Plus Crosses */}\n        {renderCross(\"left-0 top-0\", \"cross-tl\")}\n        {renderCross(\"left-1/2 top-0 hidden md:flex\", \"cross-tc\")}\n        {renderCross(\"right-0 top-0\", \"cross-tr\")}\n        {renderCross(\"left-0 top-1/2 hidden md:flex\", \"cross-ml\")}\n        {renderCross(\"left-1/2 top-1/2 hidden md:flex\", \"cross-mc\")}\n        {renderCross(\"right-0 top-1/2 hidden md:flex\", \"cross-mr\")}\n        {renderCross(\"left-0 bottom-0\", \"cross-bl\")}\n        {renderCross(\"left-1/2 bottom-0 hidden md:flex\", \"cross-bc\")}\n        {renderCross(\"right-0 bottom-0\", \"cross-br\")}\n\n        {items.map((card, idx) => {\n          const isSelected = activeCardId === card.id;\n          return (\n            <motion.div\n              key={card.id}\n              tabIndex={0}\n              role=\"button\"\n              onClick={() => setActiveCardId(isSelected ? null : card.id)}\n              onKeyDown={(e) => {\n                if (e.key === \"Enter\" || e.key === \" \") {\n                  e.preventDefault();\n                  setActiveCardId(isSelected ? null : card.id);\n                }\n              }}\n              whileHover={{ backgroundColor: \"rgba(255, 255, 255, 0.02)\" }}\n              className={cn(\n                \"group relative p-6 cursor-pointer outline-none transition-all duration-200 border-neutral-800/80\",\n                // Grid cell dividing borders\n                idx % 2 === 0 ? \"md:border-r border-b\" : \"border-b\",\n                idx >= items.length - 2 && \"md:border-b-0\",\n                isSelected && \"bg-white/[0.04] ring-1 ring-neutral-600\"\n              )}\n            >\n              <div className=\"flex items-center justify-between\">\n                <span className=\"font-mono text-[11px] font-semibold uppercase tracking-wider text-neutral-400 group-hover:text-neutral-200 flex items-center gap-1.5 transition-colors\">\n                  {getCardIcon(idx)}\n                  {card.tag}\n                </span>\n\n                {card.metric && (\n                  <span\n                    className={cn(\n                      \"inline-flex items-center gap-1 font-mono text-[11px] px-2 py-0.5 rounded border border-neutral-800 bg-neutral-900/80 font-bold transition-all\",\n                      isSelected ? theme.pill : \"text-neutral-300 group-hover:border-neutral-700\"\n                    )}\n                  >\n                    {card.metric}\n                    <ArrowUpRight className=\"h-3 w-3 text-neutral-400 group-hover:text-white transition-colors\" />\n                  </span>\n                )}\n              </div>\n\n              <div className=\"mt-4\">\n                <h4 className=\"text-base font-semibold text-white tracking-tight group-hover:text-white transition-colors\">\n                  {card.title}\n                </h4>\n                <p className=\"mt-1.5 text-xs leading-relaxed text-neutral-400 group-hover:text-neutral-300 transition-colors\">\n                  {card.description}\n                </p>\n              </div>\n\n              {/* Bottom detail pill */}\n              <div className=\"mt-5 flex items-center justify-between text-[11px] font-mono text-neutral-500\">\n                <span>STAGE: ACTIVE</span>\n                <span className=\"group-hover:translate-x-1 transition-transform inline-flex items-center gap-1 text-neutral-400 group-hover:text-white\">\n                  Inspect Spec &rarr;\n                </span>\n              </div>\n            </motion.div>\n          );\n        })}\n      </div>\n\n      {/* Footer status / telemetry */}\n      <div className=\"relative z-10 flex flex-wrap items-center justify-between gap-2 border-t border-neutral-800/80 pt-3 text-[11px] font-mono text-neutral-400\">\n        <div className=\"flex items-center gap-2\">\n          <span className=\"inline-block h-2 w-2 rounded-full bg-emerald-400 animate-pulse\" />\n          <span>BLUEPRINT MESH: 4 QUADRANTS CONNECTED</span>\n        </div>\n        <div className=\"flex items-center gap-4\">\n          <span>CURSOR POS: {mousePos ? `${Math.round(mousePos.x)}px, ${Math.round(mousePos.y)}px` : \"OFF GRID\"}</span>\n          <span>INTERSECTIONS: 9 NODES</span>\n        </div>\n      </div>\n    </div>\n  );\n}\n\nexport default PlusGridBorder;\n",
          "type": "registry:ui",
          "target": "components/ui/plus-grid-border.tsx"
        },
        {
          "path": "lib/utils.ts",
          "content": "import { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...inputs: ClassValue[]) {\n  return twMerge(clsx(inputs));\n}\n\nexport async function copyToClipboard(text: string): Promise<boolean> {\n  if (typeof window === \"undefined\") return false;\n\n  try {\n    if (navigator.clipboard && window.isSecureContext) {\n      await navigator.clipboard.writeText(text);\n      return true;\n    }\n\n    const textArea = document.createElement(\"textarea\");\n    textArea.value = text;\n    textArea.style.position = \"fixed\";\n    textArea.style.left = \"-999999px\";\n    textArea.style.top = \"-999999px\";\n    document.body.appendChild(textArea);\n    textArea.focus();\n    textArea.select();\n    const succeeded = document.execCommand(\"copy\");\n    textArea.remove();\n    return succeeded;\n  } catch {\n    return false;\n  }\n}\n",
          "type": "registry:lib",
          "target": "lib/utils.ts"
        }
      ]
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "popover-card",
      "type": "registry:ui",
      "title": "Popover Card",
      "author": "Rishabh Bose <https://theb0se.vercel.app/>",
      "description": "Floating anchored popover card with configurable side and alignment, spring scale-in physics, outside-click dismissal, and interactive toggle controls.",
      "dependencies": [
        "framer-motion",
        "lucide-react",
        "clsx",
        "tailwind-merge"
      ],
      "files": [
        {
          "path": "components/ui/popover-card.tsx",
          "content": "\"use client\";\n\nimport React, { useState, useRef, useEffect, useId } from \"react\";\nimport { AnimatePresence, motion, useReducedMotion } from \"framer-motion\";\nimport { SlidersHorizontal, Bell, ShieldCheck, Sparkles, X } from \"lucide-react\";\nimport { cn } from \"@/lib/utils\";\n\nexport type PopoverSide = \"top\" | \"bottom\" | \"left\" | \"right\";\nexport type PopoverAlign = \"start\" | \"center\" | \"end\";\n\nexport interface PopoverCardProps {\n  /** Label shown on the default trigger button */\n  triggerLabel?: string;\n  /** Header title inside the popover */\n  title?: string;\n  /** Subtitle inside the popover header */\n  description?: string;\n  /** Preferred side relative to trigger. Default: \"bottom\" */\n  side?: PopoverSide;\n  /** Alignment along the chosen side. Default: \"center\" */\n  align?: PopoverAlign;\n  /** Controlled open state */\n  open?: boolean;\n  /** Callback fired when open state changes */\n  onOpenChange?: (open: boolean) => void;\n  /** Custom body content inside the popover */\n  children?: React.ReactNode;\n  className?: string;\n}\n\nexport function PopoverCard({\n  triggerLabel = \"Display Settings\",\n  title = \"Workspace Preferences\",\n  description = \"Adjust real-time notification and layout behavior.\",\n  side = \"bottom\",\n  align = \"center\",\n  open: controlledOpen,\n  onOpenChange,\n  children,\n  className,\n}: PopoverCardProps) {\n  const shouldReduceMotion = useReducedMotion() ?? false;\n  const popoverId = useId();\n  const containerRef = useRef<HTMLDivElement>(null);\n\n  const isControlled = controlledOpen !== undefined;\n  const [internalOpen, setInternalOpen] = useState(false);\n  const isOpen = isControlled ? controlledOpen : internalOpen;\n\n  // Interactive demo state when default children are used\n  const [compactMode, setCompactMode] = useState(false);\n  const [instantAlerts, setInstantAlerts] = useState(true);\n  const [strictTypes, setStrictTypes] = useState(true);\n\n  const setOpen = (next: boolean) => {\n    if (!isControlled) {\n      setInternalOpen(next);\n    }\n    onOpenChange?.(next);\n  };\n\n  useEffect(() => {\n    if (!isOpen) return;\n    const handleOutside = (e: MouseEvent) => {\n      if (\n        containerRef.current &&\n        !containerRef.current.contains(e.target as Node)\n      ) {\n        setOpen(false);\n      }\n    };\n    const handleKey = (e: KeyboardEvent) => {\n      if (e.key === \"Escape\") {\n        setOpen(false);\n      }\n    };\n    document.addEventListener(\"mousedown\", handleOutside);\n    window.addEventListener(\"keydown\", handleKey);\n    return () => {\n      document.removeEventListener(\"mousedown\", handleOutside);\n      window.removeEventListener(\"keydown\", handleKey);\n    };\n  }, [isOpen]);\n\n  const sideClasses: Record<PopoverSide, string> = {\n    bottom: \"top-[calc(100%+10px)]\",\n    top: \"bottom-[calc(100%+10px)]\",\n    left: \"right-[calc(100%+10px)] top-0\",\n    right: \"left-[calc(100%+10px)] top-0\",\n  };\n\n  const alignClasses: Record<PopoverAlign, string> = {\n    start: side === \"top\" || side === \"bottom\" ? \"left-0\" : \"top-0\",\n    center:\n      side === \"top\" || side === \"bottom\"\n        ? \"left-1/2 -translate-x-1/2\"\n        : \"top-1/2 -translate-y-1/2\",\n    end: side === \"top\" || side === \"bottom\" ? \"right-0\" : \"bottom-0\",\n  };\n\n  const initialOffset = {\n    bottom: { y: -6, x: 0 },\n    top: { y: 6, x: 0 },\n    left: { x: 6, y: 0 },\n    right: { x: -6, y: 0 },\n  }[side];\n\n  return (\n    <div ref={containerRef} className={cn(\"relative inline-block\", className)}>\n      <button\n        type=\"button\"\n        aria-expanded={isOpen}\n        aria-controls={popoverId}\n        aria-haspopup=\"dialog\"\n        onClick={() => setOpen(!isOpen)}\n        className={cn(\n          \"inline-flex h-10 items-center gap-2 rounded-xl border px-4 text-xs font-semibold transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-black dark:focus-visible:ring-white\",\n          isOpen\n            ? \"border-black bg-black text-white dark:border-white dark:bg-white dark:text-black\"\n            : \"border-neutral-200 bg-white text-black hover:border-black dark:border-[#262626] dark:bg-[#0A0A0A] dark:text-white dark:hover:border-white\"\n        )}\n      >\n        <SlidersHorizontal className=\"h-3.5 w-3.5\" />\n        <span>{triggerLabel}</span>\n      </button>\n\n      <AnimatePresence>\n        {isOpen && (\n          <motion.div\n            id={popoverId}\n            role=\"dialog\"\n            aria-label={title}\n            initial={\n              shouldReduceMotion\n                ? { opacity: 0 }\n                : { opacity: 0, scale: 0.95, ...initialOffset }\n            }\n            animate={{ opacity: 1, scale: 1, x: 0, y: 0 }}\n            exit={\n              shouldReduceMotion\n                ? { opacity: 0 }\n                : { opacity: 0, scale: 0.96, ...initialOffset }\n            }\n            transition={{ type: \"spring\", stiffness: 420, damping: 28 }}\n            className={cn(\n              \"absolute z-50 w-72 rounded-2xl border border-neutral-200 bg-white p-4 shadow-2xl dark:border-[#262626] dark:bg-[#0A0A0A]\",\n              sideClasses[side],\n              alignClasses[align]\n            )}\n          >\n            {/* Header */}\n            <div className=\"mb-3 flex items-start justify-between gap-2 border-b border-neutral-100 pb-2.5 dark:border-[#1A1A1A]\">\n              <div>\n                <h4 className=\"text-xs font-semibold text-black dark:text-white\">\n                  {title}\n                </h4>\n                {description && (\n                  <p className=\"mt-0.5 text-[11px] leading-relaxed text-neutral-500 dark:text-neutral-400\">\n                    {description}\n                  </p>\n                )}\n              </div>\n              <button\n                type=\"button\"\n                aria-label=\"Close popover\"\n                onClick={() => setOpen(false)}\n                className=\"rounded-lg p-1 text-neutral-400 transition-colors hover:bg-neutral-100 hover:text-black dark:hover:bg-[#161616] dark:hover:text-white\"\n              >\n                <X className=\"h-3.5 w-3.5\" />\n              </button>\n            </div>\n\n            {/* Body */}\n            {children ?? (\n              <div className=\"space-y-2.5\">\n                {[\n                  {\n                    id: \"alerts\",\n                    label: \"Instant Build Alerts\",\n                    icon: <Bell className=\"h-3.5 w-3.5\" />,\n                    checked: instantAlerts,\n                    onToggle: () => setInstantAlerts((v) => !v),\n                  },\n                  {\n                    id: \"strict\",\n                    label: \"Strict Type Checking\",\n                    icon: <ShieldCheck className=\"h-3.5 w-3.5\" />,\n                    checked: strictTypes,\n                    onToggle: () => setStrictTypes((v) => !v),\n                  },\n                  {\n                    id: \"compact\",\n                    label: \"Compact Grid Density\",\n                    icon: <Sparkles className=\"h-3.5 w-3.5\" />,\n                    checked: compactMode,\n                    onToggle: () => setCompactMode((v) => !v),\n                  },\n                ].map((setting) => (\n                  <button\n                    key={setting.id}\n                    type=\"button\"\n                    role=\"switch\"\n                    aria-checked={setting.checked}\n                    onClick={setting.onToggle}\n                    className=\"flex w-full items-center justify-between rounded-xl border border-neutral-200/70 bg-neutral-50/60 px-3 py-2 text-left text-xs transition-colors hover:border-neutral-300 dark:border-[#1F1F1F] dark:bg-[#121212] dark:hover:border-neutral-700\"\n                  >\n                    <span className=\"flex items-center gap-2 font-medium text-neutral-800 dark:text-neutral-200\">\n                      <span className=\"text-neutral-400\">{setting.icon}</span>\n                      {setting.label}\n                    </span>\n                    <span\n                      className={cn(\n                        \"relative inline-flex h-5 w-9 shrink-0 items-center rounded-full p-0.5 transition-colors\",\n                        setting.checked\n                          ? \"bg-black dark:bg-white\"\n                          : \"bg-neutral-300 dark:bg-neutral-700\"\n                      )}\n                    >\n                      <motion.span\n                        layout\n                        transition={{\n                          type: \"spring\",\n                          stiffness: 500,\n                          damping: 32,\n                        }}\n                        className={cn(\n                          \"h-4 w-4 rounded-full bg-white shadow-xs dark:bg-black\",\n                          setting.checked ? \"ml-auto\" : \"ml-0\"\n                        )}\n                      />\n                    </span>\n                  </button>\n                ))}\n              </div>\n            )}\n          </motion.div>\n        )}\n      </AnimatePresence>\n    </div>\n  );\n}\n\nexport default PopoverCard;\n",
          "type": "registry:ui",
          "target": "components/ui/popover-card.tsx"
        },
        {
          "path": "lib/utils.ts",
          "content": "import { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...inputs: ClassValue[]) {\n  return twMerge(clsx(inputs));\n}\n\nexport async function copyToClipboard(text: string): Promise<boolean> {\n  if (typeof window === \"undefined\") return false;\n\n  try {\n    if (navigator.clipboard && window.isSecureContext) {\n      await navigator.clipboard.writeText(text);\n      return true;\n    }\n\n    const textArea = document.createElement(\"textarea\");\n    textArea.value = text;\n    textArea.style.position = \"fixed\";\n    textArea.style.left = \"-999999px\";\n    textArea.style.top = \"-999999px\";\n    document.body.appendChild(textArea);\n    textArea.focus();\n    textArea.select();\n    const succeeded = document.execCommand(\"copy\");\n    textArea.remove();\n    return succeeded;\n  } catch {\n    return false;\n  }\n}\n",
          "type": "registry:lib",
          "target": "lib/utils.ts"
        }
      ]
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "pricing-calculator",
      "type": "registry:ui",
      "title": "Pricing Calculator",
      "author": "Rishabh Bose <https://theb0se.vercel.app/>",
      "description": "Interactive Stripe-style pricing calculator featuring an API usage volume slider, automatic plan tier recommendation highlights, multi-currency conversion, and an annual billing toggle with 20% discount.",
      "dependencies": [
        "framer-motion",
        "lucide-react",
        "clsx",
        "tailwind-merge"
      ],
      "files": [
        {
          "path": "components/ui/pricing-calculator.tsx",
          "content": "\"use client\";\n\nimport React, { useState } from \"react\";\nimport { motion, AnimatePresence } from \"framer-motion\";\nimport {\n  Check,\n  Zap,\n  Sparkles,\n  Sliders,\n  ArrowRight,\n  TrendingUp,\n  ShieldCheck,\n  HelpCircle,\n  Building,\n} from \"lucide-react\";\nimport { cn } from \"@/lib/utils\";\n\ninterface TierPlan {\n  id: string;\n  name: string;\n  tagline: string;\n  minVolume: number;\n  maxVolume: number;\n  basePriceMonthly: number;\n  perExtraUnitRate: number; // cost per 1,000 calls above base\n  popular?: boolean;\n  features: string[];\n}\n\nconst PLANS: TierPlan[] = [\n  {\n    id: \"starter\",\n    name: \"Starter\",\n    tagline: \"For early stage builders & side-projects\",\n    minVolume: 0,\n    maxVolume: 50_000,\n    basePriceMonthly: 29,\n    perExtraUnitRate: 0.5,\n    features: [\n      \"Up to 50,000 API requests/mo\",\n      \"3 team member seats\",\n      \"Standard Webhook dispatch\",\n      \"Community Discord & Email support\",\n    ],\n  },\n  {\n    id: \"growth\",\n    name: \"Growth\",\n    tagline: \"For fast growing SaaS & ecommerce platforms\",\n    minVolume: 50_000,\n    maxVolume: 500_000,\n    basePriceMonthly: 99,\n    perExtraUnitRate: 0.35,\n    popular: true,\n    features: [\n      \"Up to 500,000 API requests/mo\",\n      \"15 team member seats\",\n      \"Automated ML Dunning & Retries\",\n      \"99.99% Uptime SLA commitment\",\n      \"Priority 24/7 ticketing queue\",\n    ],\n  },\n  {\n    id: \"scale\",\n    name: \"Scale\",\n    tagline: \"For mature products handling heavy transactional throughput\",\n    minVolume: 500_000,\n    maxVolume: 2_500_000,\n    basePriceMonthly: 299,\n    perExtraUnitRate: 0.2,\n    features: [\n      \"Up to 2,500,000 API requests/mo\",\n      \"Unlimited team seats\",\n      \"Dedicated Slack Connect channel\",\n      \"Multi-region VPC peering\",\n      \"Custom rate limit overrides\",\n    ],\n  },\n  {\n    id: \"enterprise\",\n    name: \"Enterprise\",\n    tagline: \"Institutional financial rails & bespoke compliance\",\n    minVolume: 2_500_000,\n    maxVolume: 10_000_000,\n    basePriceMonthly: 899,\n    perExtraUnitRate: 0.12,\n    features: [\n      \"High volume unlimited transactions\",\n      \"99.999% Zero-downtime SLA\",\n      \"Dedicated Solutions Architect\",\n      \"Custom contract & SOC2 type II audit\",\n      \"Private on-prem telemetry broker\",\n    ],\n  },\n];\n\nconst CURRENCIES = [\n  { code: \"USD\", symbol: \"$\", rate: 1.0 },\n  { code: \"EUR\", symbol: \"€\", rate: 0.92 },\n  { code: \"GBP\", symbol: \"£\", rate: 0.79 },\n];\n\nconst PRESET_VOLUMES = [25_000, 150_000, 850_000, 3_500_000];\n\nexport interface PricingCalculatorProps {\n  className?: string;\n  defaultVolume?: number;\n  defaultAnnual?: boolean;\n}\n\nexport function PricingCalculator({\n  className,\n  defaultVolume = 150_000,\n  defaultAnnual = true,\n}: PricingCalculatorProps) {\n  const [volume, setVolume] = useState<number>(defaultVolume);\n  const [isAnnual, setIsAnnual] = useState<boolean>(defaultAnnual);\n  const [currencyIndex, setCurrencyIndex] = useState<number>(0);\n\n  const currentCurrency = CURRENCIES[currencyIndex];\n\n  // Find active plan based on volume\n  const activePlan =\n    PLANS.find((p) => volume >= p.minVolume && volume < p.maxVolume) ||\n    PLANS[PLANS.length - 1];\n\n  // Calculate price with volume discount & annual 20% discount\n  const calculatePrice = (plan: TierPlan) => {\n    let raw = plan.basePriceMonthly;\n    if (volume > plan.minVolume) {\n      const extraVolume = Math.max(0, volume - plan.minVolume);\n      raw += (extraVolume / 1000) * plan.perExtraUnitRate;\n    }\n    if (isAnnual) {\n      raw *= 0.8; // 20% discount\n    }\n    return Math.round(raw * currentCurrency.rate);\n  };\n\n  const calculatedCost = calculatePrice(activePlan);\n\n  return (\n    <div\n      data-fullscreen-scroll\n      className={cn(\n        \"relative w-full min-h-[520px] overflow-hidden rounded-2xl border border-neutral-800 bg-[#070913] p-6 text-white flex flex-col justify-between shadow-2xl selection:bg-indigo-500/30\",\n        className\n      )}\n    >\n      {/* Background ambient gradient */}\n      <div className=\"pointer-events-none absolute inset-0 overflow-hidden\">\n        <div className=\"absolute top-0 left-1/3 h-96 w-[500px] rounded-full bg-indigo-600/10 blur-[130px]\" />\n        <div className=\"absolute bottom-0 right-1/4 h-80 w-80 rounded-full bg-emerald-500/10 blur-[120px]\" />\n      </div>\n\n      {/* Top Header */}\n      <div className=\"relative z-10 max-w-3xl mx-auto text-center pt-2 pb-6\">\n        <div className=\"inline-flex items-center gap-2 px-3 py-1 rounded-full bg-indigo-500/10 border border-indigo-500/20 text-indigo-300 text-xs font-medium mb-3\">\n          <Sparkles className=\"h-3.5 w-3.5\" />\n          <span>Tiered Volume Calculator</span>\n        </div>\n\n        <h2 className=\"text-3xl sm:text-4xl font-extrabold tracking-tight text-white\">\n          Predictable pricing that scales with you\n        </h2>\n        <p className=\"mt-2 text-xs sm:text-sm text-neutral-400 max-w-xl mx-auto\">\n          Drag the volume slider to estimate your monthly API costs. Volume discounts apply automatically as your traffic expands.\n        </p>\n\n        {/* Monthly vs Annual Toggle */}\n        <div className=\"mt-6 inline-flex items-center gap-3 bg-neutral-900/90 border border-neutral-800 p-1 rounded-xl backdrop-blur-md\">\n          <button\n            onClick={() => setIsAnnual(false)}\n            className={cn(\n              \"px-3.5 py-1.5 rounded-lg text-xs font-medium transition-all\",\n              !isAnnual\n                ? \"bg-neutral-800 text-white shadow\"\n                : \"text-neutral-400 hover:text-white\"\n            )}\n          >\n            Monthly billing\n          </button>\n          <button\n            onClick={() => setIsAnnual(true)}\n            className={cn(\n              \"px-3.5 py-1.5 rounded-lg text-xs font-medium transition-all flex items-center gap-1.5\",\n              isAnnual\n                ? \"bg-indigo-600 text-white shadow shadow-indigo-600/30 font-semibold\"\n                : \"text-neutral-400 hover:text-white\"\n            )}\n          >\n            <span>Annual billing</span>\n            <span className=\"text-[10px] bg-emerald-400/20 text-emerald-300 px-1.5 py-0.5 rounded font-mono\">\n              Save 20%\n            </span>\n          </button>\n        </div>\n      </div>\n\n      {/* Interactive Usage Slider Box */}\n      <div className=\"relative z-10 max-w-4xl mx-auto w-full bg-neutral-900/70 border border-neutral-800/90 rounded-2xl p-6 backdrop-blur-xl mb-8 shadow-xl\">\n        <div className=\"flex flex-wrap items-center justify-between gap-4 mb-4\">\n          <div>\n            <span className=\"text-xs uppercase tracking-wider text-neutral-400 font-semibold\">\n              Monthly Transactions / API Requests\n            </span>\n            <div className=\"flex items-baseline gap-2 mt-0.5\">\n              <span className=\"text-3xl font-extrabold text-white font-mono tracking-tight\">\n                {volume.toLocaleString()}\n              </span>\n              <span className=\"text-xs text-neutral-400\">requests / month</span>\n            </div>\n          </div>\n\n          {/* Estimated Monthly Total Display */}\n          <div className=\"text-right\">\n            <span className=\"text-xs text-neutral-400 font-medium\">\n              Estimated Investment\n            </span>\n            <div className=\"flex items-baseline justify-end gap-1 mt-0.5\">\n              <span className=\"text-3xl font-black text-indigo-400 tracking-tight font-mono\">\n                {currentCurrency.symbol}\n                {calculatedCost.toLocaleString()}\n              </span>\n              <span className=\"text-xs text-neutral-400\">/ mo</span>\n            </div>\n            {isAnnual && (\n              <span className=\"text-[10px] text-emerald-400 font-mono\">\n                Billed annually ({currentCurrency.symbol}\n                {(calculatedCost * 12).toLocaleString()}/yr)\n              </span>\n            )}\n          </div>\n        </div>\n\n        {/* Custom Slider Input */}\n        <div className=\"relative my-6\">\n          <input\n            type=\"range\"\n            min={10_000}\n            max={5_000_000}\n            step={10_000}\n            value={volume}\n            onChange={(e) => setVolume(Number(e.target.value))}\n            className=\"w-full h-2.5 bg-neutral-800 rounded-lg appearance-none cursor-pointer accent-indigo-500\"\n          />\n\n          {/* Volume tick labels */}\n          <div className=\"flex justify-between text-[11px] font-mono text-neutral-500 mt-2\">\n            <span>10K</span>\n            <span>250K</span>\n            <span>1M</span>\n            <span>2.5M</span>\n            <span>5M+</span>\n          </div>\n        </div>\n\n        {/* Preset Volume Quick Buttons */}\n        <div className=\"flex flex-wrap items-center justify-between gap-2 pt-2 border-t border-neutral-800/60 text-xs\">\n          <span className=\"text-neutral-400\">Preset Volume Jumps:</span>\n          <div className=\"flex flex-wrap gap-2\">\n            {PRESET_VOLUMES.map((pv) => (\n              <button\n                key={pv}\n                onClick={() => setVolume(pv)}\n                className={cn(\n                  \"px-2.5 py-1 rounded font-mono text-[11px] transition-colors\",\n                  volume === pv\n                    ? \"bg-indigo-600 text-white font-semibold\"\n                    : \"bg-neutral-800 hover:bg-neutral-700 text-neutral-300\"\n                )}\n              >\n                {(pv / 1000).toFixed(0)}k req\n              </button>\n            ))}\n          </div>\n        </div>\n      </div>\n\n      {/* Pricing Plans Grid */}\n      <div className=\"relative z-10 grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-4 max-w-6xl mx-auto w-full mb-6\">\n        {PLANS.map((plan) => {\n          const isCurrent = activePlan.id === plan.id;\n          const planCost = calculatePrice(plan);\n\n          return (\n            <div\n              key={plan.id}\n              className={cn(\n                \"relative rounded-2xl p-5 flex flex-col justify-between transition-all duration-300 border\",\n                isCurrent\n                  ? \"bg-neutral-900/95 border-indigo-500 shadow-2xl shadow-indigo-500/20 ring-1 ring-indigo-500\"\n                  : \"bg-neutral-900/40 border-neutral-800 hover:border-neutral-700\"\n              )}\n            >\n              {/* Highlight badge if active */}\n              {isCurrent && (\n                <div className=\"absolute -top-3 left-1/2 -translate-x-1/2 px-2.5 py-0.5 rounded-full bg-gradient-to-r from-indigo-500 to-violet-600 text-white text-[10px] font-bold tracking-wide uppercase shadow-md\">\n                  Active Match\n                </div>\n              )}\n\n              <div>\n                <div className=\"flex items-center justify-between\">\n                  <h3 className=\"font-bold text-white text-base\">{plan.name}</h3>\n                  {plan.popular && !isCurrent && (\n                    <span className=\"text-[10px] font-semibold text-neutral-400 bg-neutral-800 px-2 py-0.5 rounded\">\n                      Popular\n                    </span>\n                  )}\n                </div>\n\n                <p className=\"mt-1 text-[11px] text-neutral-400 leading-snug min-h-[30px]\">\n                  {plan.tagline}\n                </p>\n\n                <div className=\"mt-4 pt-3 border-t border-neutral-800\">\n                  <div className=\"flex items-baseline gap-1\">\n                    <span className=\"text-2xl font-black text-white font-mono\">\n                      {currentCurrency.symbol}\n                      {planCost}\n                    </span>\n                    <span className=\"text-xs text-neutral-400\">/mo</span>\n                  </div>\n                  <span className=\"text-[10px] text-neutral-500 font-mono block\">\n                    {plan.maxVolume >= 10_000_000\n                      ? \"Custom enterprise tier\"\n                      : `Up to ${(plan.maxVolume / 1000).toLocaleString()}k req/mo`}\n                  </span>\n                </div>\n\n                {/* Features list */}\n                <div className=\"mt-4 space-y-2\">\n                  {plan.features.map((feat, idx) => (\n                    <div key={idx} className=\"flex items-start gap-2 text-xs text-neutral-300\">\n                      <Check className=\"h-3.5 w-3.5 text-emerald-400 shrink-0 mt-0.5\" />\n                      <span className=\"leading-tight text-[11px]\">{feat}</span>\n                    </div>\n                  ))}\n                </div>\n              </div>\n\n              {/* Action Button */}\n              <button\n                className={cn(\n                  \"mt-6 w-full py-2 px-3 rounded-xl text-xs font-semibold transition-all flex items-center justify-center gap-1.5\",\n                  isCurrent\n                    ? \"bg-indigo-600 hover:bg-indigo-500 text-white shadow-lg shadow-indigo-600/30\"\n                    : \"bg-neutral-800 hover:bg-neutral-700 text-neutral-200\"\n                )}\n              >\n                <span>Select {plan.name}</span>\n                <ArrowRight className=\"h-3 w-3\" />\n              </button>\n            </div>\n          );\n        })}\n      </div>\n\n      {/* Interactive Controls Stage Footer */}\n      <div className=\"relative z-20 mt-4 pt-4 border-t border-neutral-800/80 bg-neutral-950/80 backdrop-blur-md -mx-6 -mb-6 px-6 py-4 flex flex-wrap items-center justify-between gap-4 text-xs\">\n        <div className=\"flex items-center gap-2\">\n          <span className=\"text-neutral-400 font-medium\">Currency:</span>\n          {CURRENCIES.map((c, idx) => (\n            <button\n              key={c.code}\n              onClick={() => setCurrencyIndex(idx)}\n              className={cn(\n                \"px-2.5 py-1 rounded font-mono text-xs transition-colors\",\n                currencyIndex === idx\n                  ? \"bg-indigo-600 text-white font-semibold\"\n                  : \"bg-neutral-800/80 text-neutral-400 hover:text-white\"\n              )}\n            >\n              {c.code} ({c.symbol})\n            </button>\n          ))}\n        </div>\n\n        <div className=\"flex items-center gap-3 text-neutral-400 text-xs\">\n          <span className=\"flex items-center gap-1.5 text-emerald-400\">\n            <ShieldCheck className=\"h-4 w-4\" />\n            No hidden setup fees\n          </span>\n          <span>&bull;</span>\n          <span>Cancel anytime</span>\n        </div>\n      </div>\n    </div>\n  );\n}\n\nexport default PricingCalculator;\n",
          "type": "registry:ui",
          "target": "components/ui/pricing-calculator.tsx"
        },
        {
          "path": "lib/utils.ts",
          "content": "import { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...inputs: ClassValue[]) {\n  return twMerge(clsx(inputs));\n}\n\nexport async function copyToClipboard(text: string): Promise<boolean> {\n  if (typeof window === \"undefined\") return false;\n\n  try {\n    if (navigator.clipboard && window.isSecureContext) {\n      await navigator.clipboard.writeText(text);\n      return true;\n    }\n\n    const textArea = document.createElement(\"textarea\");\n    textArea.value = text;\n    textArea.style.position = \"fixed\";\n    textArea.style.left = \"-999999px\";\n    textArea.style.top = \"-999999px\";\n    document.body.appendChild(textArea);\n    textArea.focus();\n    textArea.select();\n    const succeeded = document.execCommand(\"copy\");\n    textArea.remove();\n    return succeeded;\n  } catch {\n    return false;\n  }\n}\n",
          "type": "registry:lib",
          "target": "lib/utils.ts"
        }
      ]
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "product-compare-table",
      "type": "registry:ui",
      "title": "Product Compare Table",
      "author": "Rishabh Bose <https://theb0se.vercel.app/>",
      "description": "Aligned multi-tier product comparison matrix with sticky frosted headers, check and dash indicators, highlighted tier column, and a live 'Show differences only' switch.",
      "dependencies": [
        "framer-motion",
        "lucide-react",
        "clsx",
        "tailwind-merge"
      ],
      "files": [
        {
          "path": "components/ui/product-compare-table.tsx",
          "content": "\"use client\";\n\nimport React, { useState, useMemo } from \"react\";\nimport { motion } from \"framer-motion\";\nimport { Check, Minus, Sparkles } from \"lucide-react\";\nimport { cn } from \"@/lib/utils\";\n\nexport interface CompareTier {\n  id: string;\n  name: string;\n  price: string;\n  badge?: string;\n  highlighted?: boolean;\n}\n\nexport interface CompareSpecRow {\n  feature: string;\n  category?: string;\n  values: Record<string, boolean | string>;\n}\n\nexport interface ProductCompareTableProps {\n  /** Columns / product tiers to compare */\n  tiers?: CompareTier[];\n  /** Specification rows with boolean (Check/Dash) or string values per tier id */\n  rows?: CompareSpecRow[];\n  /** Show toggle to filter only rows where tiers differ. Default: true */\n  allowDiffFilter?: boolean;\n  className?: string;\n}\n\nconst DEFAULT_TIERS: CompareTier[] = [\n  { id: \"core\", name: \"Core\", price: \"$0\" },\n  { id: \"pro\", name: \"Pro\", price: \"$29\", badge: \"Popular\", highlighted: true },\n  { id: \"enterprise\", name: \"Scale\", price: \"$99\" },\n];\n\nconst DEFAULT_ROWS: CompareSpecRow[] = [\n  {\n    feature: \"Framer Motion Spring Primitives\",\n    values: { core: true, pro: true, enterprise: true },\n  },\n  {\n    feature: \"CLI Registry Installation\",\n    values: { core: true, pro: true, enterprise: true },\n  },\n  {\n    feature: \"Dark & Light Theme Tokens\",\n    values: { core: true, pro: true, enterprise: true },\n  },\n  {\n    feature: \"Multi-Step Wizard & Command Menu\",\n    values: { core: false, pro: true, enterprise: true },\n  },\n  {\n    feature: \"Custom Figma Design Kit\",\n    values: { core: false, pro: true, enterprise: true },\n  },\n  {\n    feature: \"Dedicated SLA & Architecture Review\",\n    values: { core: false, pro: false, enterprise: true },\n  },\n  {\n    feature: \"Concurrent Team Seats\",\n    values: { core: \"1 seat\", pro: \"Up to 10\", enterprise: \"Unlimited\" },\n  },\n];\n\nexport function ProductCompareTable({\n  tiers = DEFAULT_TIERS,\n  rows = DEFAULT_ROWS,\n  allowDiffFilter = true,\n  className,\n}: ProductCompareTableProps) {\n  const [onlyDifferences, setOnlyDifferences] = useState(false);\n\n  const visibleRows = useMemo(() => {\n    if (!onlyDifferences) return rows;\n    return rows.filter((row) => {\n      const vals = tiers.map((t) => row.values[t.id]);\n      return new Set(vals).size > 1;\n    });\n  }, [rows, tiers, onlyDifferences]);\n\n  return (\n    <div\n      className={cn(\n        \"w-full max-w-2xl overflow-hidden rounded-3xl border border-neutral-200 bg-white shadow-sm dark:border-neutral-800 dark:bg-[#0A0A0A]\",\n        className\n      )}\n    >\n      {/* Top Filter Header */}\n      {allowDiffFilter && (\n        <div className=\"flex items-center justify-between border-b border-neutral-200 bg-neutral-50/70 px-5 py-3 dark:border-neutral-800 dark:bg-neutral-900/50\">\n          <span className=\"text-xs font-semibold text-neutral-900 dark:text-white\">\n            Compare Specifications\n          </span>\n\n          <button\n            type=\"button\"\n            role=\"switch\"\n            aria-checked={onlyDifferences}\n            onClick={() => setOnlyDifferences((v) => !v)}\n            className=\"inline-flex items-center gap-2 text-xs font-medium text-neutral-600 dark:text-neutral-300\"\n          >\n            <span>Show differences only</span>\n            <span\n              className={cn(\n                \"relative inline-flex h-5 w-9 items-center rounded-full p-0.5 transition-colors\",\n                onlyDifferences\n                  ? \"bg-neutral-900 dark:bg-white\"\n                  : \"bg-neutral-300 dark:bg-neutral-700\"\n              )}\n            >\n              <motion.span\n                layout\n                transition={{ type: \"spring\", stiffness: 500, damping: 32 }}\n                className={cn(\n                  \"h-4 w-4 rounded-full bg-white shadow-2xs dark:bg-black\",\n                  onlyDifferences ? \"ml-auto\" : \"ml-0\"\n                )}\n              />\n            </span>\n          </button>\n        </div>\n      )}\n\n      {/* Scrollable Table Container with Sticky Header */}\n      <div data-fullscreen-scroll className=\"max-h-[340px] overflow-auto\">\n        <table className=\"w-full border-collapse text-left text-xs\">\n          <thead className=\"sticky top-0 z-20 border-b border-neutral-200 bg-white/95 backdrop-blur-md dark:border-neutral-800 dark:bg-[#0A0A0A]/95\">\n            <tr>\n              <th className=\"min-w-[160px] px-5 py-4 font-mono text-[11px] font-semibold uppercase tracking-wider text-neutral-400\">\n                Feature\n              </th>\n              {tiers.map((tier) => (\n                <th\n                  key={tier.id}\n                  className={cn(\n                    \"min-w-[100px] px-4 py-3.5 text-center\",\n                    tier.highlighted &&\n                      \"bg-neutral-50/90 dark:bg-neutral-900/60\"\n                  )}\n                >\n                  <div className=\"flex flex-col items-center gap-0.5\">\n                    {tier.badge && (\n                      <span className=\"mb-0.5 inline-flex items-center gap-1 rounded-full bg-neutral-900 px-2 py-0.2 font-mono text-[9px] font-semibold uppercase text-white dark:bg-white dark:text-black\">\n                        <Sparkles className=\"h-2.5 w-2.5\" />\n                        {tier.badge}\n                      </span>\n                    )}\n                    <span className=\"text-xs font-bold text-neutral-950 dark:text-white\">\n                      {tier.name}\n                    </span>\n                    <span className=\"font-mono text-[11px] text-neutral-500 dark:text-neutral-400\">\n                      {tier.price}\n                    </span>\n                  </div>\n                </th>\n              ))}\n            </tr>\n          </thead>\n\n          <tbody className=\"divide-y divide-neutral-200/80 dark:divide-neutral-800/80\">\n            {visibleRows.map((row) => (\n              <tr\n                key={row.feature}\n                className=\"transition-colors hover:bg-neutral-50/60 dark:hover:bg-neutral-900/30\"\n              >\n                <td className=\"px-5 py-3.5 font-medium text-neutral-800 dark:text-neutral-200\">\n                  {row.feature}\n                </td>\n                {tiers.map((tier) => {\n                  const val = row.values[tier.id];\n                  return (\n                    <td\n                      key={tier.id}\n                      className={cn(\n                        \"px-4 py-3.5 text-center\",\n                        tier.highlighted &&\n                          \"bg-neutral-50/50 dark:bg-neutral-900/30\"\n                      )}\n                    >\n                      {typeof val === \"boolean\" ? (\n                        val ? (\n                          <span\n                            aria-label=\"Included\"\n                            className=\"mx-auto inline-flex h-5 w-5 items-center justify-center rounded-full bg-neutral-900 text-white dark:bg-white dark:text-black\"\n                          >\n                            <Check className=\"h-3 w-3 stroke-[2.5]\" />\n                          </span>\n                        ) : (\n                          <span\n                            aria-label=\"Not included\"\n                            className=\"mx-auto inline-flex h-5 w-5 items-center justify-center text-neutral-300 dark:text-neutral-700\"\n                          >\n                            <Minus className=\"h-3.5 w-3.5\" />\n                          </span>\n                        )\n                      ) : (\n                        <span className=\"font-mono text-[11px] font-semibold text-neutral-900 dark:text-white\">\n                          {val ?? \"—\"}\n                        </span>\n                      )}\n                    </td>\n                  );\n                })}\n              </tr>\n            ))}\n          </tbody>\n        </table>\n      </div>\n    </div>\n  );\n}\n\nexport default ProductCompareTable;\n",
          "type": "registry:ui",
          "target": "components/ui/product-compare-table.tsx"
        },
        {
          "path": "lib/utils.ts",
          "content": "import { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...inputs: ClassValue[]) {\n  return twMerge(clsx(inputs));\n}\n\nexport async function copyToClipboard(text: string): Promise<boolean> {\n  if (typeof window === \"undefined\") return false;\n\n  try {\n    if (navigator.clipboard && window.isSecureContext) {\n      await navigator.clipboard.writeText(text);\n      return true;\n    }\n\n    const textArea = document.createElement(\"textarea\");\n    textArea.value = text;\n    textArea.style.position = \"fixed\";\n    textArea.style.left = \"-999999px\";\n    textArea.style.top = \"-999999px\";\n    document.body.appendChild(textArea);\n    textArea.focus();\n    textArea.select();\n    const succeeded = document.execCommand(\"copy\");\n    textArea.remove();\n    return succeeded;\n  } catch {\n    return false;\n  }\n}\n",
          "type": "registry:lib",
          "target": "lib/utils.ts"
        }
      ]
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "product-sequence-scrubber",
      "type": "registry:ui",
      "title": "Product Sequence Scrubber",
      "author": "Rishabh Bose <https://theb0se.vercel.app/>",
      "description": "Apple-inspired interactive 360° hardware sequence scrubber with vector frame rotation, multi-layer explosion disassembly view, and angle-synchronized feature callouts.",
      "dependencies": [
        "framer-motion",
        "lucide-react",
        "clsx",
        "tailwind-merge"
      ],
      "files": [
        {
          "path": "components/ui/product-sequence-scrubber.tsx",
          "content": "\"use client\";\n\nimport React, { useState, useEffect, useRef, useMemo } from \"react\";\nimport { motion, AnimatePresence } from \"framer-motion\";\nimport { Play, Pause, RotateCw, Layers, Sparkles, ChevronRight, Check } from \"lucide-react\";\nimport { cn } from \"@/lib/utils\";\n\nexport interface FeatureCallout {\n  frameRange: [number, number];\n  title: string;\n  subtitle: string;\n  tag: string;\n  position: { x: number; y: number };\n}\n\nexport interface ProductSequenceScrubberProps {\n  /** Total sequence steps / frames around 360 degrees */\n  totalFrames?: number;\n  /** Initial frame index */\n  defaultFrame?: number;\n  /** Auto rotate on mount */\n  defaultAutoPlay?: boolean;\n  /** Initial explosion / disassemble view */\n  defaultExploded?: boolean;\n  /** Custom callout items synchronized with sequence angles */\n  callouts?: FeatureCallout[];\n  /** Whether to show the top header and controls bar */\n  showHeader?: boolean;\n  /** Optional custom class names */\n  className?: string;\n}\n\nconst DEFAULT_CALLOUTS: FeatureCallout[] = [\n  {\n    frameRange: [3, 9],\n    title: \"Grade 5 Titanium Band\",\n    subtitle: \"Precision PVD-coated aerospace alloy with sub-micron brushed finish\",\n    tag: \"Chassis\",\n    position: { x: 74, y: 32 },\n  },\n  {\n    frameRange: [10, 16],\n    title: \"Dynamic Action Button\",\n    subtitle: \"Haptic piezo-actuated key with instant customizable trigger shortcuts\",\n    tag: \"Interface\",\n    position: { x: 26, y: 38 },\n  },\n  {\n    frameRange: [17, 25],\n    title: \"A18 Pro Silicon Substrate\",\n    subtitle: \"Second-gen 3nm architecture with 16-core Neural Engine & hardware RT\",\n    tag: \"Silicon\",\n    position: { x: 50, y: 52 },\n  },\n  {\n    frameRange: [27, 34],\n    title: \"Next-Gen Ceramic Shield\",\n    subtitle: \"Nano-crystal formulation with 4x improved drop resilience and oleophobic seal\",\n    tag: \"Display\",\n    position: { x: 68, y: 64 },\n  },\n];\n\nexport function ProductSequenceScrubber({\n  totalFrames = 36,\n  defaultFrame = 6,\n  defaultAutoPlay = false,\n  defaultExploded = false,\n  callouts = DEFAULT_CALLOUTS,\n  showHeader = true,\n  className,\n}: ProductSequenceScrubberProps) {\n  const [currentFrame, setCurrentFrame] = useState(defaultFrame);\n  const [isPlaying, setIsPlaying] = useState(defaultAutoPlay);\n  const [isExploded, setIsExploded] = useState(defaultExploded);\n  const [activePreset, setActivePreset] = useState<string | null>(null);\n\n  // Playback timer\n  useEffect(() => {\n    if (!isPlaying) return;\n    const interval = setInterval(() => {\n      setCurrentFrame((prev) => (prev + 1) % totalFrames);\n    }, 85);\n    return () => clearInterval(interval);\n  }, [isPlaying, totalFrames]);\n\n  // Derive angle & rotation properties\n  const rotationAngle = (currentFrame / totalFrames) * 360;\n  const rad = (rotationAngle * Math.PI) / 180;\n  const sin = Math.sin(rad);\n  const cos = Math.cos(rad);\n\n  // Active callout matching frame\n  const activeCallout = useMemo(() => {\n    return callouts.find(\n      (c) => currentFrame >= c.frameRange[0] && currentFrame <= c.frameRange[1]\n    );\n  }, [callouts, currentFrame]);\n\n  // Angle presets\n  const presets = [\n    { label: \"Front 0°\", frame: 0 },\n    { label: \"Action 90°\", frame: Math.round(totalFrames * 0.25) },\n    { label: \"Rear 180°\", frame: Math.round(totalFrames * 0.5) },\n    { label: \"Profile 270°\", frame: Math.round(totalFrames * 0.75) },\n  ];\n\n  const handleSeek = (frame: number) => {\n    setCurrentFrame(frame);\n    setIsPlaying(false);\n  };\n\n  // Exploded layer offsets\n  const explodeZ = isExploded ? 1 : 0;\n\n  return (\n    <div\n      data-fullscreen-scroll\n      className={cn(\n        \"relative w-full min-h-[520px] overflow-hidden rounded-2xl border border-neutral-200/80 bg-neutral-950 p-6 text-neutral-100 shadow-2xl transition-all dark:border-neutral-800\",\n        className\n      )}\n    >\n      {/* Background ambient radial glow */}\n      <div\n        className=\"pointer-events-none absolute inset-0 transition-opacity duration-1000\"\n        style={{\n          background: `radial-gradient(circle 600px at 50% 45%, rgba(60, 100, 160, 0.18), transparent 70%),\n                       radial-gradient(circle 400px at 80% 80%, rgba(210, 140, 70, 0.08), transparent 70%)`,\n        }}\n      />\n\n      {/* Top Header & Metadata */}\n      {showHeader && (\n        <div className=\"relative z-10 flex flex-wrap items-center justify-between gap-4 border-b border-neutral-800/80 pb-4\">\n          <div>\n            <div className=\"inline-flex items-center gap-2 rounded-full border border-neutral-800 bg-neutral-900/90 px-3 py-1 text-xs font-medium text-neutral-300 backdrop-blur-md\">\n              <span className=\"h-1.5 w-1.5 rounded-full bg-blue-500 animate-pulse\" />\n              360° Hardware Sequence Scrubber\n            </div>\n            <h2 className=\"mt-2 text-xl font-semibold tracking-tight text-white\">\n              Pro Titanium Design Sequence\n            </h2>\n            <p className=\"text-xs text-neutral-400\">\n              Scrub continuous multi-angle inspection • Disassemble layer architecture\n            </p>\n          </div>\n\n          {/* Top Controls: Play/Pause, Explode */}\n          <div className=\"flex items-center gap-2\">\n            <button\n              type=\"button\"\n              onClick={() => setIsPlaying(!isPlaying)}\n              className=\"inline-flex items-center gap-1.5 rounded-xl border border-neutral-800 bg-neutral-900 px-3 py-1.5 text-xs font-medium text-neutral-200 shadow-sm transition hover:bg-neutral-800 active:scale-95\"\n              aria-label={isPlaying ? \"Pause rotation\" : \"Play rotation\"}\n            >\n              {isPlaying ? (\n                <>\n                  <Pause className=\"h-3.5 w-3.5 text-blue-400\" />\n                  <span>Pause</span>\n                </>\n              ) : (\n                <>\n                  <Play className=\"h-3.5 w-3.5 text-emerald-400\" />\n                  <span>Spin 360°</span>\n                </>\n              )}\n            </button>\n\n            <button\n              type=\"button\"\n              onClick={() => setIsExploded(!isExploded)}\n              className={cn(\n                \"inline-flex items-center gap-1.5 rounded-xl border px-3 py-1.5 text-xs font-medium transition active:scale-95\",\n                isExploded\n                  ? \"border-blue-500/60 bg-blue-500/20 text-blue-300 shadow-[0_0_15px_rgba(59,130,246,0.25)]\"\n                  : \"border-neutral-800 bg-neutral-900 text-neutral-300 hover:bg-neutral-800\"\n              )}\n            >\n              <Layers className=\"h-3.5 w-3.5\" />\n              <span>{isExploded ? \"Assembled\" : \"Explode Layers\"}</span>\n            </button>\n          </div>\n        </div>\n      )}\n\n      {/* Center 3D Interactive Vector Stage */}\n      <div className=\"relative flex min-h-[340px] items-center justify-center py-6 select-none\">\n        {/* Synchronized Callout Badge */}\n        <AnimatePresence mode=\"wait\">\n          {activeCallout && (\n            <motion.div\n              key={activeCallout.title}\n              initial={{ opacity: 0, y: 10, scale: 0.95 }}\n              animate={{ opacity: 1, y: 0, scale: 1 }}\n              exit={{ opacity: 0, y: -10, scale: 0.95 }}\n              transition={{ duration: 0.25 }}\n              style={{\n                top: `${activeCallout.position.y}%`,\n                left: `${activeCallout.position.x}%`,\n              }}\n              className=\"pointer-events-none absolute z-30 -translate-x-1/2 -translate-y-1/2 rounded-2xl border border-blue-500/30 bg-neutral-900/95 p-3.5 shadow-2xl backdrop-blur-xl max-w-[240px] ring-1 ring-white/10\"\n            >\n              <div className=\"flex items-center gap-1.5 text-[10px] font-semibold uppercase tracking-wider text-blue-400\">\n                <Sparkles className=\"h-3 w-3\" />\n                {activeCallout.tag}\n              </div>\n              <div className=\"mt-1 text-xs font-semibold text-white\">\n                {activeCallout.title}\n              </div>\n              <div className=\"mt-0.5 text-[11px] leading-tight text-neutral-400\">\n                {activeCallout.subtitle}\n              </div>\n            </motion.div>\n          )}\n        </AnimatePresence>\n\n        {/* Vector 3D Phone Model rendered with perspective projection */}\n        <div\n          className=\"relative flex items-center justify-center transition-transform duration-200\"\n          style={{\n            perspective: 1200,\n            transformStyle: \"preserve-3d\",\n          }}\n        >\n          {/* Main SVG assembly */}\n          <svg\n            width=\"320\"\n            height=\"340\"\n            viewBox=\"0 0 320 340\"\n            className=\"overflow-visible filter drop-shadow-[0_25px_35px_rgba(0,0,0,0.85)]\"\n          >\n            <defs>\n              {/* Titanium frame gradient */}\n              <linearGradient id=\"titaniumGradient\" x1=\"0%\" y1=\"0%\" x2=\"100%\" y2=\"100%\">\n                <stop offset=\"0%\" stopColor=\"#7E7F85\" />\n                <stop offset=\"35%\" stopColor=\"#A8A9AF\" />\n                <stop offset=\"55%\" stopColor=\"#5B5C60\" />\n                <stop offset=\"85%\" stopColor=\"#9C9DA3\" />\n                <stop offset=\"100%\" stopColor=\"#3C3D42\" />\n              </linearGradient>\n\n              {/* Glass screen reflection gradient */}\n              <linearGradient id=\"screenReflection\" x1=\"0%\" y1=\"0%\" x2=\"100%\" y2=\"100%\">\n                <stop offset=\"0%\" stopColor=\"rgba(255,255,255,0.22)\" />\n                <stop offset=\"45%\" stopColor=\"rgba(255,255,255,0.03)\" />\n                <stop offset=\"100%\" stopColor=\"rgba(100,180,255,0.08)\" />\n              </linearGradient>\n\n              {/* Silicon chip gradient */}\n              <linearGradient id=\"chipGradient\" x1=\"0%\" y1=\"0%\" x2=\"100%\" y2=\"100%\">\n                <stop offset=\"0%\" stopColor=\"#0B132B\" />\n                <stop offset=\"50%\" stopColor=\"#1C2541\" />\n                <stop offset=\"100%\" stopColor=\"#3A506B\" />\n              </linearGradient>\n\n              {/* Battery gradient */}\n              <linearGradient id=\"batteryGrad\" x1=\"0%\" y1=\"0%\" x2=\"0%\" y2=\"100%\">\n                <stop offset=\"0%\" stopColor=\"#1a1c23\" />\n                <stop offset=\"100%\" stopColor=\"#0d0e12\" />\n              </linearGradient>\n            </defs>\n\n            {/* Compute geometric projections */}\n            {(() => {\n              const cx = 160;\n              const cy = 170;\n              const w = 130 * Math.max(0.18, Math.abs(cos));\n              const h = 260;\n              const r = 32 * Math.max(0.2, Math.abs(cos));\n              const sideFacing = cos > 0 ? 1 : -1;\n              const depthOffset = sin * 28;\n\n              // Explosion offsets for each layer\n              const dispOffset = explodeZ * -45;\n              const chassisOffset = explodeZ * -15;\n              const boardOffset = explodeZ * 15;\n              const battOffset = explodeZ * 40;\n              const backOffset = explodeZ * 65;\n\n              return (\n                <g transform={`translate(${cx}, ${cy})`}>\n                  {/* Layer 5: Back Matte Glass & Triple Camera Bump */}\n                  <g\n                    transform={`translate(${depthOffset * 0.4 + (sideFacing === -1 ? 0 : backOffset)}, ${backOffset * 0.3})`}\n                    opacity={isExploded ? 0.9 : cos < 0 ? 1 : 0.25}\n                    className=\"transition-all duration-500 ease-out\"\n                  >\n                    <rect\n                      x={-w / 2}\n                      y={-h / 2}\n                      width={w}\n                      height={h}\n                      rx={r}\n                      fill=\"#1E1F24\"\n                      stroke=\"#42434A\"\n                      strokeWidth=\"1.5\"\n                    />\n                    {/* Camera Island */}\n                    {Math.abs(cos) > 0.3 && (\n                      <g transform={`translate(${sideFacing > 0 ? -w * 0.25 : w * 0.25}, ${-h * 0.28})`}>\n                        <rect\n                          x={-24 * Math.abs(cos)}\n                          y={-28}\n                          width={48 * Math.abs(cos)}\n                          height={56}\n                          rx={12 * Math.abs(cos)}\n                          fill=\"#15161A\"\n                          stroke=\"#38393F\"\n                          strokeWidth=\"1.5\"\n                        />\n                        {/* Lenses */}\n                        <circle cx={-8 * cos} cy={-12} r={7 * Math.abs(cos)} fill=\"#0A0B0E\" stroke=\"#5E606B\" strokeWidth=\"1\" />\n                        <circle cx={-8 * cos} cy={12} r={7 * Math.abs(cos)} fill=\"#0A0B0E\" stroke=\"#5E606B\" strokeWidth=\"1\" />\n                        <circle cx={10 * cos} cy={0} r={6 * Math.abs(cos)} fill=\"#0A0B0E\" stroke=\"#5E606B\" strokeWidth=\"1\" />\n                      </g>\n                    )}\n                  </g>\n\n                  {/* Layer 4: High-density Battery pack (Exploded view) */}\n                  {isExploded && (\n                    <g\n                      transform={`translate(${battOffset * 0.7}, ${battOffset * 0.2})`}\n                      className=\"transition-all duration-500 ease-out\"\n                    >\n                      <rect\n                        x={-w * 0.42}\n                        y={-h * 0.1}\n                        width={w * 0.84}\n                        height={h * 0.52}\n                        rx={12 * Math.abs(cos)}\n                        fill=\"url(#batteryGrad)\"\n                        stroke=\"#333842\"\n                        strokeWidth=\"1.2\"\n                      />\n                      <text\n                        x=\"0\"\n                        y={h * 0.16}\n                        fill=\"#7A808C\"\n                        fontSize=\"9\"\n                        textAnchor=\"middle\"\n                        fontFamily=\"monospace\"\n                      >\n                        4,422 mAh Li-Ion\n                      </text>\n                    </g>\n                  )}\n\n                  {/* Layer 3: Logic Board & A18 Pro Chip (Exploded view) */}\n                  {isExploded && (\n                    <g\n                      transform={`translate(${boardOffset * 0.6}, ${boardOffset * 0.15})`}\n                      className=\"transition-all duration-500 ease-out\"\n                    >\n                      <rect\n                        x={-w * 0.4}\n                        y={-h * 0.45}\n                        width={w * 0.8}\n                        height={h * 0.32}\n                        rx={8 * Math.abs(cos)}\n                        fill=\"url(#chipGradient)\"\n                        stroke=\"#4F7CAC\"\n                        strokeWidth=\"1.5\"\n                      />\n                      {/* Apple Silicon Logo / A18 Pro core */}\n                      <rect\n                        x={-14 * Math.abs(cos)}\n                        y={-h * 0.32}\n                        width={28 * Math.abs(cos)}\n                        height={28}\n                        rx={4}\n                        fill=\"#0A0F1D\"\n                        stroke=\"#60A5FA\"\n                        strokeWidth=\"1.2\"\n                      />\n                      <text\n                        x=\"0\"\n                        y={-h * 0.32 + 18}\n                        fill=\"#93C5FD\"\n                        fontSize=\"8\"\n                        textAnchor=\"middle\"\n                        fontWeight=\"bold\"\n                      >\n                        A18 Pro\n                      </text>\n                    </g>\n                  )}\n\n                  {/* Layer 2: Grade 5 Titanium Chassis Frame */}\n                  <g\n                    transform={`translate(${chassisOffset * 0.5}, ${chassisOffset * 0.1})`}\n                    className=\"transition-all duration-500 ease-out\"\n                  >\n                    <rect\n                      x={-w / 2}\n                      y={-h / 2}\n                      width={w}\n                      height={h}\n                      rx={r}\n                      fill=\"none\"\n                      stroke=\"url(#titaniumGradient)\"\n                      strokeWidth={isExploded ? \"3.5\" : \"4.5\"}\n                    />\n                    {/* Action button notch & Volume indicators on side */}\n                    {Math.abs(cos) < 0.85 && (\n                      <g>\n                        <rect\n                          x={sideFacing > 0 ? w / 2 - 2 : -w / 2}\n                          y={-60}\n                          width={4}\n                          height={16}\n                          rx={2}\n                          fill=\"#FF9F0A\"\n                          opacity={activeCallout?.tag === \"Interface\" ? 1 : 0.7}\n                        />\n                        <rect\n                          x={sideFacing > 0 ? w / 2 - 2 : -w / 2}\n                          y={-32}\n                          width={4}\n                          height={28}\n                          rx={2}\n                          fill=\"#A8A9AF\"\n                        />\n                      </g>\n                    )}\n                  </g>\n\n                  {/* Layer 1: Front Ceramic Shield & Super Retina XDR */}\n                  <g\n                    transform={`translate(${dispOffset * 0.6}, ${dispOffset * 0.2})`}\n                    opacity={isExploded ? 0.88 : cos >= 0 ? 1 : 0.35}\n                    className=\"transition-all duration-500 ease-out\"\n                  >\n                    {/* Screen Body */}\n                    <rect\n                      x={-w / 2 + 3}\n                      y={-h / 2 + 3}\n                      width={Math.max(1, w - 6)}\n                      height={h - 6}\n                      rx={Math.max(2, r - 3)}\n                      fill=\"#030407\"\n                      stroke=\"#22252B\"\n                      strokeWidth=\"1.5\"\n                    />\n\n                    {/* Dynamic Island Pill */}\n                    {Math.abs(cos) > 0.25 && (\n                      <rect\n                        x={-18 * Math.abs(cos)}\n                        y={-h / 2 + 14}\n                        width={36 * Math.abs(cos)}\n                        height={10}\n                        rx={5}\n                        fill=\"#000000\"\n                        stroke=\"#1C1D22\"\n                        strokeWidth=\"1\"\n                      />\n                    )}\n\n                    {/* Display reflection shine */}\n                    <path\n                      d={`M ${-w / 2 + 4} ${-h / 2 + 4} L ${w / 2 - 4} ${h / 2 - 4} L ${-w / 2 + 4} ${h / 2 - 4} Z`}\n                      fill=\"url(#screenReflection)\"\n                      clipPath=\"url(#screenClip)\"\n                      opacity={Math.abs(cos) * 0.8}\n                    />\n\n                    {/* UI Clock & lockscreen preview when front-facing */}\n                    {cos > 0.6 && !isExploded && (\n                      <g opacity={cos}>\n                        <text\n                          x=\"0\"\n                          y={-h / 2 + 65}\n                          fill=\"#FFFFFF\"\n                          fontSize=\"22\"\n                          fontWeight=\"600\"\n                          textAnchor=\"middle\"\n                          fontFamily=\"sans-serif\"\n                        >\n                          9:41\n                        </text>\n                        <text\n                          x=\"0\"\n                          y={-h / 2 + 82}\n                          fill=\"#9CA3AF\"\n                          fontSize=\"9\"\n                          fontWeight=\"500\"\n                          textAnchor=\"middle\"\n                        >\n                          Friday, October 9\n                        </text>\n                      </g>\n                    )}\n                  </g>\n                </g>\n              );\n            })()}\n          </svg>\n        </div>\n      </div>\n\n      {/* Bottom Timeline Scrubber Controls */}\n      <div className=\"relative z-10 mt-2 space-y-3 rounded-xl border border-neutral-800/80 bg-neutral-900/80 p-3.5 backdrop-blur-md\">\n        {/* Scrub Slider Bar */}\n        <div className=\"space-y-1.5\">\n          <div className=\"flex items-center justify-between text-xs\">\n            <span className=\"font-medium text-neutral-300\">\n              Scrub Sequence Timeline\n            </span>\n            <span className=\"font-mono text-neutral-400\">\n              Angle: <strong className=\"text-white\">{Math.round(rotationAngle)}°</strong> ({currentFrame + 1}/{totalFrames})\n            </span>\n          </div>\n\n          <div className=\"relative flex items-center\">\n            <input\n              type=\"range\"\n              min={0}\n              max={totalFrames - 1}\n              value={currentFrame}\n              onChange={(e) => handleSeek(Number(e.target.value))}\n              aria-label=\"360 Product angle scrubber slider\"\n              className=\"h-2 w-full cursor-pointer appearance-none rounded-lg bg-neutral-800 accent-blue-500 transition-all hover:bg-neutral-700\"\n            />\n          </div>\n\n          {/* Timeline markers */}\n          <div className=\"flex justify-between px-1 text-[10px] text-neutral-500 font-mono\">\n            <span>0° (Face)</span>\n            <span>90° (Left)</span>\n            <span>180° (Back)</span>\n            <span>270° (Right)</span>\n            <span>360°</span>\n          </div>\n        </div>\n\n        {/* Preset Angle Buttons */}\n        <div className=\"flex flex-wrap items-center justify-between gap-2 pt-1 border-t border-neutral-800/60\">\n          <div className=\"flex items-center gap-1.5\">\n            <span className=\"text-[11px] text-neutral-400 mr-1\">Jump to:</span>\n            {presets.map((preset) => (\n              <button\n                key={preset.label}\n                type=\"button\"\n                onClick={() => handleSeek(preset.frame)}\n                className={cn(\n                  \"rounded-lg px-2.5 py-1 text-xs font-medium transition\",\n                  currentFrame === preset.frame\n                    ? \"bg-blue-600 text-white shadow-sm\"\n                    : \"bg-neutral-800 text-neutral-300 hover:bg-neutral-700 hover:text-white\"\n                )}\n              >\n                {preset.label}\n              </button>\n            ))}\n          </div>\n\n          <div className=\"text-[11px] text-neutral-400\">\n            {isExploded ? (\n              <span className=\"text-blue-400 font-medium\">⚡ 5 Disassembled Hardware Layers</span>\n            ) : (\n              <span>Drag slider or click presets to inspect angles</span>\n            )}\n          </div>\n        </div>\n      </div>\n    </div>\n  );\n}\n\nexport default ProductSequenceScrubber;\n",
          "type": "registry:ui",
          "target": "components/ui/product-sequence-scrubber.tsx"
        },
        {
          "path": "lib/utils.ts",
          "content": "import { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...inputs: ClassValue[]) {\n  return twMerge(clsx(inputs));\n}\n\nexport async function copyToClipboard(text: string): Promise<boolean> {\n  if (typeof window === \"undefined\") return false;\n\n  try {\n    if (navigator.clipboard && window.isSecureContext) {\n      await navigator.clipboard.writeText(text);\n      return true;\n    }\n\n    const textArea = document.createElement(\"textarea\");\n    textArea.value = text;\n    textArea.style.position = \"fixed\";\n    textArea.style.left = \"-999999px\";\n    textArea.style.top = \"-999999px\";\n    document.body.appendChild(textArea);\n    textArea.focus();\n    textArea.select();\n    const succeeded = document.execCommand(\"copy\");\n    textArea.remove();\n    return succeeded;\n  } catch {\n    return false;\n  }\n}\n",
          "type": "registry:lib",
          "target": "lib/utils.ts"
        }
      ]
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "radial-menu-orb",
      "type": "registry:ui",
      "title": "Radial Menu Orb",
      "author": "Rishabh Bose <https://theb0se.vercel.app/>",
      "description": "Floating command orb that blossoms into a 360-degree polar-coordinate action ring with staggered Hooke's Law spring trajectories.",
      "dependencies": [
        "framer-motion",
        "lucide-react",
        "clsx",
        "tailwind-merge"
      ],
      "files": [
        {
          "path": "components/ui/radial-menu-orb.tsx",
          "content": "\"use client\";\n\nimport React, { useEffect, useState } from \"react\";\nimport { AnimatePresence, motion, useReducedMotion } from \"framer-motion\";\nimport {\n  Plus,\n  Sparkles,\n  Copy,\n  Share2,\n  Bookmark,\n  Terminal,\n} from \"lucide-react\";\nimport { cn } from \"@/lib/utils\";\n\nexport interface RadialOrbAction {\n  id: string;\n  label: string;\n  icon: React.ReactNode;\n  onClick?: () => void;\n}\n\nexport interface RadialMenuOrbProps {\n  /** Array of satellite actions distributed along the polar ring. */\n  actions?: RadialOrbAction[];\n  /** Orbit radius in pixels from center trigger to satellite buttons. Default: 78 */\n  radius?: number;\n  /** Hooke's Law spring stiffness for radial blossom. Default: 340 */\n  stiffness?: number;\n  /** Spring damping coefficient for radial blossom. Default: 22 */\n  damping?: number;\n  /** Callback fired when an action is selected */\n  onSelect?: (id: string) => void;\n  className?: string;\n}\n\nconst DEFAULT_ACTIONS: RadialOrbAction[] = [\n  { id: \"inspect\", label: \"Inspect\", icon: <Sparkles className=\"h-4 w-4\" /> },\n  { id: \"cli\", label: \"Copy CLI\", icon: <Terminal className=\"h-4 w-4\" /> },\n  { id: \"duplicate\", label: \"Clone\", icon: <Copy className=\"h-4 w-4\" /> },\n  { id: \"bookmark\", label: \"Save\", icon: <Bookmark className=\"h-4 w-4\" /> },\n  { id: \"share\", label: \"Share\", icon: <Share2 className=\"h-4 w-4\" /> },\n];\n\nexport function RadialMenuOrb({\n  actions = DEFAULT_ACTIONS,\n  radius = 78,\n  stiffness = 340,\n  damping = 22,\n  onSelect,\n  className,\n}: RadialMenuOrbProps) {\n  const shouldReduceMotion = useReducedMotion() ?? false;\n  const [isOpen, setIsOpen] = useState(false);\n  const [lastSelected, setLastSelected] = useState<string>(\"Ready\");\n\n  useEffect(() => {\n    if (!isOpen) return;\n    const onKeyDown = (e: KeyboardEvent) => {\n      if (e.key === \"Escape\") {\n        setIsOpen(false);\n      }\n    };\n    window.addEventListener(\"keydown\", onKeyDown);\n    return () => window.removeEventListener(\"keydown\", onKeyDown);\n  }, [isOpen]);\n\n  return (\n    <div\n      className={cn(\n        \"relative flex min-h-[230px] w-full max-w-xs flex-col items-center justify-center\",\n        className\n      )}\n    >\n      {/* Orbital Ring Guide */}\n      <AnimatePresence>\n        {isOpen && (\n          <motion.div\n            aria-hidden=\"true\"\n            initial={{ scale: 0.4, opacity: 0 }}\n            animate={{ scale: 1, opacity: 1 }}\n            exit={{ scale: 0.4, opacity: 0 }}\n            transition={\n              shouldReduceMotion\n                ? { duration: 0 }\n                : { type: \"spring\", stiffness, damping }\n            }\n            style={{ width: radius * 2, height: radius * 2 }}\n            className=\"pointer-events-none absolute rounded-full border border-dashed border-neutral-300 dark:border-[#2A2A2A]\"\n          />\n        )}\n      </AnimatePresence>\n\n      {/* Polar Satellite Action Buttons */}\n      <AnimatePresence>\n        {isOpen &&\n          actions.map((action, index) => {\n            const angleDeg = (360 / actions.length) * index - 90;\n            const angleRad = (angleDeg * Math.PI) / 180;\n            const targetX = Math.cos(angleRad) * radius;\n            const targetY = Math.sin(angleRad) * radius;\n\n            return (\n              <motion.button\n                key={action.id}\n                type=\"button\"\n                aria-label={action.label}\n                initial={\n                  shouldReduceMotion\n                    ? { x: targetX, y: targetY, opacity: 1 }\n                    : { x: 0, y: 0, scale: 0.3, opacity: 0 }\n                }\n                animate={{ x: targetX, y: targetY, scale: 1, opacity: 1 }}\n                exit={\n                  shouldReduceMotion\n                    ? { opacity: 0 }\n                    : { x: 0, y: 0, scale: 0.3, opacity: 0 }\n                }\n                whileHover={shouldReduceMotion ? undefined : { scale: 1.14 }}\n                whileTap={shouldReduceMotion ? undefined : { scale: 0.92 }}\n                transition={\n                  shouldReduceMotion\n                    ? { duration: 0 }\n                    : {\n                        type: \"spring\",\n                        stiffness,\n                        damping,\n                        delay: index * 0.025,\n                      }\n                }\n                onClick={() => {\n                  setLastSelected(action.label);\n                  onSelect?.(action.id);\n                  action.onClick?.();\n                  setIsOpen(false);\n                }}\n                className=\"group absolute z-10 flex h-10 w-10 items-center justify-center rounded-full border border-neutral-200 bg-white text-black shadow-md transition-colors hover:border-black hover:bg-black hover:text-white focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-black dark:border-[#2A2A2A] dark:bg-[#121212] dark:text-white dark:hover:border-white dark:hover:bg-white dark:hover:text-black dark:focus-visible:ring-white\"\n              >\n                {action.icon}\n                <span className=\"pointer-events-none absolute -top-7 whitespace-nowrap rounded bg-black px-1.5 py-0.5 text-[10px] font-semibold text-white opacity-0 transition-opacity group-hover:opacity-100 group-focus-visible:opacity-100 dark:bg-white dark:text-black\">\n                  {action.label}\n                </span>\n              </motion.button>\n            );\n          })}\n      </AnimatePresence>\n\n      {/* Center Core Trigger Orb */}\n      <motion.button\n        type=\"button\"\n        aria-expanded={isOpen}\n        aria-label={isOpen ? \"Close radial command menu\" : \"Open radial command menu\"}\n        onClick={() => setIsOpen((prev) => !prev)}\n        whileTap={shouldReduceMotion ? undefined : { scale: 0.92 }}\n        className=\"relative z-20 flex h-14 w-14 items-center justify-center rounded-full border border-black bg-black text-white shadow-lg transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-black focus-visible:ring-offset-2 dark:border-white dark:bg-white dark:text-black dark:focus-visible:ring-white\"\n      >\n        <motion.span\n          animate={{ rotate: isOpen ? 135 : 0 }}\n          transition={\n            shouldReduceMotion\n              ? { duration: 0 }\n              : { type: \"spring\", stiffness: 360, damping: 22 }\n          }\n        >\n          <Plus className=\"h-5 w-5\" />\n        </motion.span>\n      </motion.button>\n\n      {/* Telemetry Status Readout */}\n      <div className=\"pointer-events-none absolute bottom-1 font-mono text-[11px] text-neutral-400 dark:text-neutral-500\">\n        {isOpen ? \"Select orbital node • Esc to close\" : `Action: ${lastSelected}`}\n      </div>\n    </div>\n  );\n}\n\nexport default RadialMenuOrb;\n",
          "type": "registry:ui",
          "target": "components/ui/radial-menu-orb.tsx"
        },
        {
          "path": "lib/utils.ts",
          "content": "import { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...inputs: ClassValue[]) {\n  return twMerge(clsx(inputs));\n}\n\nexport async function copyToClipboard(text: string): Promise<boolean> {\n  if (typeof window === \"undefined\") return false;\n\n  try {\n    if (navigator.clipboard && window.isSecureContext) {\n      await navigator.clipboard.writeText(text);\n      return true;\n    }\n\n    const textArea = document.createElement(\"textarea\");\n    textArea.value = text;\n    textArea.style.position = \"fixed\";\n    textArea.style.left = \"-999999px\";\n    textArea.style.top = \"-999999px\";\n    document.body.appendChild(textArea);\n    textArea.focus();\n    textArea.select();\n    const succeeded = document.execCommand(\"copy\");\n    textArea.remove();\n    return succeeded;\n  } catch {\n    return false;\n  }\n}\n",
          "type": "registry:lib",
          "target": "lib/utils.ts"
        }
      ]
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "rain-on-glass",
      "type": "registry:ui",
      "title": "Rain on Glass",
      "author": "Rishabh Bose <https://theb0se.vercel.app/>",
      "description": "Atmospheric window-pane rain simulation over a blurred bokeh backdrop where droplets slide down with surface-tension stutter, leave bead trails, and refract light.",
      "dependencies": [
        "lucide-react",
        "clsx",
        "tailwind-merge"
      ],
      "files": [
        {
          "path": "components/ui/rain-on-glass.tsx",
          "content": "\"use client\";\n\nimport React, { useEffect, useRef, useState } from \"react\";\nimport { CloudRain } from \"lucide-react\";\nimport { cn } from \"@/lib/utils\";\n\nexport interface RainOnGlassProps {\n  /** Number of main sliding rain droplets. Default: 45 */\n  dropCount?: number;\n  /** Fall speed multiplier. Default: 1 */\n  speed?: number;\n  /** Horizontal wind slant (-1 to 1). Default: 0.05 */\n  wind?: number;\n  /** Intensity of the flipped inner refractive highlight (0 to 1). Default: 0.85 */\n  refraction?: number;\n  /** Optional foreground content */\n  children?: React.ReactNode;\n  className?: string;\n}\n\ninterface Droplet {\n  x: number;\n  y: number;\n  r: number;\n  vy: number;\n  trailTimer: number;\n}\n\ninterface TrailBead {\n  x: number;\n  y: number;\n  r: number;\n  alpha: number;\n}\n\nexport function RainOnGlass({\n  dropCount = 45,\n  speed = 1,\n  wind = 0.05,\n  refraction = 0.85,\n  children,\n  className,\n}: RainOnGlassProps) {\n  const canvasRef = useRef<HTMLCanvasElement>(null);\n  const [stormMode, setStormMode] = useState(false);\n\n  const effectiveSpeed = stormMode ? speed * 2.2 : speed;\n  const effectiveDrops = stormMode ? Math.round(dropCount * 1.6) : dropCount;\n\n  useEffect(() => {\n    const canvas = canvasRef.current;\n    if (!canvas) return;\n    const ctx = canvas.getContext(\"2d\");\n    if (!ctx) return;\n\n    let rafId: number;\n    let width = (canvas.width = canvas.offsetWidth || 600);\n    let height = (canvas.height = canvas.offsetHeight || 360);\n\n    const drops: Droplet[] = Array.from({ length: effectiveDrops }, () => ({\n      x: Math.random() * width,\n      y: Math.random() * height,\n      r: 3.5 + Math.random() * 5.5,\n      vy: (35 + Math.random() * 75) * effectiveSpeed,\n      trailTimer: Math.random() * 0.3,\n    }));\n\n    const beads: TrailBead[] = [];\n\n    const handleResize = () => {\n      if (!canvas) return;\n      width = canvas.width = canvas.offsetWidth || 600;\n      height = canvas.height = canvas.offsetHeight || 360;\n    };\n\n    window.addEventListener(\"resize\", handleResize);\n\n    let last = performance.now();\n    const render = (now: number) => {\n      const dt = Math.min(0.05, (now - last) / 1000);\n      last = now;\n\n      ctx.clearRect(0, 0, width, height);\n\n      // Draw static/fading trail beads first\n      for (let i = beads.length - 1; i >= 0; i--) {\n        const b = beads[i];\n        b.alpha -= dt * 0.35;\n        if (b.alpha <= 0.02) {\n          beads.splice(i, 1);\n          continue;\n        }\n        ctx.beginPath();\n        ctx.arc(b.x, b.y, b.r, 0, Math.PI * 2);\n        ctx.fillStyle = `rgba(220, 238, 255, ${(b.alpha * 0.45).toFixed(3)})`;\n        ctx.fill();\n      }\n\n      // Update & draw main refractive droplets\n      for (let i = 0; i < drops.length; i++) {\n        const d = drops[i];\n        // Intermittent stutter-slide motion like real water on glass\n        const surge = 0.6 + 0.6 * Math.sin(now * 0.004 + i * 2.1);\n        d.y += d.vy * surge * dt;\n        d.x += wind * 40 * dt + Math.sin(d.y * 0.04 + i) * 0.25;\n\n        d.trailTimer -= dt;\n        if (d.trailTimer <= 0 && beads.length < 220) {\n          beads.push({\n            x: d.x + (Math.random() - 0.5) * 1.5,\n            y: d.y - d.r * 0.8,\n            r: 1.1 + Math.random() * 1.4,\n            alpha: 0.75,\n          });\n          d.trailTimer = 0.12 + Math.random() * 0.22;\n        }\n\n        if (d.y - d.r > height) {\n          d.y = -d.r - Math.random() * 30;\n          d.x = Math.random() * width;\n        }\n        if (d.x > width + 20) d.x = -10;\n        if (d.x < -20) d.x = width + 10;\n\n        // Droplet body (slightly elongated vertical tear/ellipse)\n        ctx.save();\n        ctx.beginPath();\n        ctx.ellipse(d.x, d.y, d.r * 0.82, d.r * 1.12, 0, 0, Math.PI * 2);\n\n        // Flipped internal refraction gradient (amber/cyan city lights inverted inside drop)\n        const refGrad = ctx.createRadialGradient(\n          d.x - d.r * 0.25,\n          d.y - d.r * 0.35,\n          d.r * 0.1,\n          d.x,\n          d.y,\n          d.r * 1.1\n        );\n        refGrad.addColorStop(0, `rgba(255, 255, 255, ${(0.9 * refraction).toFixed(2)})`);\n        refGrad.addColorStop(0.45, `rgba(125, 211, 252, ${(0.45 * refraction).toFixed(2)})`);\n        refGrad.addColorStop(0.85, `rgba(251, 146, 60, ${(0.28 * refraction).toFixed(2)})`);\n        refGrad.addColorStop(1, \"rgba(15, 23, 42, 0.55)\");\n\n        ctx.fillStyle = refGrad;\n        ctx.fill();\n\n        // Crisp specular rim highlight at bottom-right of drop\n        ctx.strokeStyle = \"rgba(255, 255, 255, 0.45)\";\n        ctx.lineWidth = 0.8;\n        ctx.stroke();\n        ctx.restore();\n      }\n\n      rafId = requestAnimationFrame(render);\n    };\n\n    rafId = requestAnimationFrame(render);\n    return () => {\n      cancelAnimationFrame(rafId);\n      window.removeEventListener(\"resize\", handleResize);\n    };\n  }, [effectiveDrops, effectiveSpeed, wind, refraction]);\n\n  return (\n    <div\n      data-fullscreen-scroll\n      className={cn(\n        \"relative flex min-h-[360px] w-full flex-col justify-between overflow-hidden rounded-3xl border border-neutral-800 bg-[#070B14] p-6 text-white shadow-sm\",\n        className\n      )}\n    >\n      {/* Blurred Bokeh Cityscape Background behind the glass */}\n      <div\n        aria-hidden=\"true\"\n        className=\"pointer-events-none absolute inset-0 overflow-hidden opacity-80 blur-2xl\"\n      >\n        <div className=\"absolute -left-10 top-6 h-56 w-56 rounded-full bg-sky-600/35\" />\n        <div className=\"absolute right-8 top-12 h-64 w-64 rounded-full bg-indigo-600/30\" />\n        <div className=\"absolute bottom-2 left-1/3 h-48 w-64 rounded-full bg-amber-500/30\" />\n        <div className=\"absolute bottom-6 right-12 h-40 w-40 rounded-full bg-rose-500/25\" />\n      </div>\n\n      {/* Frosted Window Pane Tint */}\n      <div\n        aria-hidden=\"true\"\n        className=\"pointer-events-none absolute inset-0 bg-slate-950/35 backdrop-blur-md\"\n      />\n\n      {/* Refractive Droplets Canvas */}\n      <canvas\n        ref={canvasRef}\n        aria-hidden=\"true\"\n        className=\"pointer-events-none absolute inset-0 h-full w-full\"\n      />\n\n      {/* Foreground Content */}\n      <div className=\"relative z-10 flex flex-1 flex-col justify-between\">\n        {children ?? (\n          <>\n            <div className=\"flex items-center justify-between gap-2\">\n              <span className=\"inline-flex items-center gap-1.5 rounded-full border border-white/15 bg-black/35 px-3 py-1 font-mono text-[11px] font-medium text-white backdrop-blur-md\">\n                <CloudRain className=\"h-3.5 w-3.5 text-sky-300\" />\n                Rain on Glass · Refractive Lens\n              </span>\n\n              <button\n                type=\"button\"\n                onClick={() => setStormMode((s) => !s)}\n                className=\"rounded-full border border-white/15 bg-white/10 px-3 py-1 font-mono text-[11px] text-white backdrop-blur-md transition-colors hover:bg-white/20\"\n              >\n                Intensity: {stormMode ? \"Downpour\" : \"Steady Rain\"}\n              </button>\n            </div>\n\n            <div className=\"my-auto max-w-md py-8\">\n              <h3 className=\"text-2xl font-bold tracking-tight text-white sm:text-3xl\">\n                Refractive Window Droplets\n              </h3>\n              <p className=\"mt-2 text-xs leading-relaxed text-white/80 sm:text-sm\">\n                Blurred bokeh backdrop with water droplets that stutter-slide\n                down the pane, leave micro-bead trails, and refract inverted\n                highlights.\n              </p>\n            </div>\n\n            <div className=\"font-mono text-[11px] text-white/55\">\n              Drops: {effectiveDrops} · Refraction: {Math.round(refraction * 100)}%\n            </div>\n          </>\n        )}\n      </div>\n    </div>\n  );\n}\n\nexport default RainOnGlass;\n",
          "type": "registry:ui",
          "target": "components/ui/rain-on-glass.tsx"
        },
        {
          "path": "lib/utils.ts",
          "content": "import { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...inputs: ClassValue[]) {\n  return twMerge(clsx(inputs));\n}\n\nexport async function copyToClipboard(text: string): Promise<boolean> {\n  if (typeof window === \"undefined\") return false;\n\n  try {\n    if (navigator.clipboard && window.isSecureContext) {\n      await navigator.clipboard.writeText(text);\n      return true;\n    }\n\n    const textArea = document.createElement(\"textarea\");\n    textArea.value = text;\n    textArea.style.position = \"fixed\";\n    textArea.style.left = \"-999999px\";\n    textArea.style.top = \"-999999px\";\n    document.body.appendChild(textArea);\n    textArea.focus();\n    textArea.select();\n    const succeeded = document.execCommand(\"copy\");\n    textArea.remove();\n    return succeeded;\n  } catch {\n    return false;\n  }\n}\n",
          "type": "registry:lib",
          "target": "lib/utils.ts"
        }
      ]
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "reaction-picker",
      "type": "registry:ui",
      "title": "Reaction Picker",
      "author": "Rishabh Bose <https://theb0se.vercel.app/>",
      "description": "Slack-style floating emoji reaction bar with quick reactions, spring count bump badges, toggleable personal reaction state, hover tooltip user attributions, and an expandable full emoji picker with search.",
      "dependencies": [
        "framer-motion",
        "lucide-react",
        "clsx",
        "tailwind-merge"
      ],
      "files": [
        {
          "path": "components/ui/reaction-picker.tsx",
          "content": "\"use client\";\n\nimport React, { useState, useRef, useEffect } from \"react\";\nimport { motion, AnimatePresence } from \"framer-motion\";\nimport {\n  Smile,\n  Plus,\n  Search,\n  RotateCcw,\n  MessageCircle,\n  Sparkles,\n  Check,\n} from \"lucide-react\";\nimport { cn } from \"@/lib/utils\";\n\nexport interface ReactionItem {\n  emoji: string;\n  count: number;\n  reactedByMe: boolean;\n  users: string[];\n}\n\nexport interface ReactionPickerProps {\n  initialReactions?: ReactionItem[];\n  messageText?: string;\n  authorName?: string;\n  authorRole?: string;\n  /** Whether to render only the inline reaction badge pills and add button */\n  inline?: boolean;\n  className?: string;\n}\n\nconst QUICK_EMOJIS = [\"👍\", \"❤️\", \"🚀\", \"🎉\", \"🔥\", \"👀\", \"🙌\", \"💡\"];\n\nconst FULL_EMOJIS = [\n  { emoji: \"👍\", name: \"thumbs up\", category: \"Frequent\" },\n  { emoji: \"❤️\", name: \"heart\", category: \"Frequent\" },\n  { emoji: \"🚀\", name: \"rocket\", category: \"Frequent\" },\n  { emoji: \"🎉\", name: \"tada party\", category: \"Frequent\" },\n  { emoji: \"🔥\", name: \"fire lit\", category: \"Frequent\" },\n  { emoji: \"👀\", name: \"eyes look\", category: \"Frequent\" },\n  { emoji: \"🙌\", name: \"raised hands\", category: \"Frequent\" },\n  { emoji: \"💡\", name: \"idea bulb\", category: \"Frequent\" },\n  { emoji: \"⚡\", name: \"zap lightning\", category: \"Objects\" },\n  { emoji: \"⭐\", name: \"star gold\", category: \"Objects\" },\n  { emoji: \"💯\", name: \"hundred score\", category: \"Symbols\" },\n  { emoji: \"🤝\", name: \"handshake deal\", category: \"People\" },\n  { emoji: \"🦾\", name: \"mechanical arm tech\", category: \"People\" },\n  { emoji: \"🎯\", name: \"dart bullseye target\", category: \"Objects\" },\n  { emoji: \"☕\", name: \"coffee drink\", category: \"Food\" },\n  { emoji: \"💎\", name: \"gem diamond\", category: \"Objects\" },\n];\n\nconst DEFAULT_REACTIONS: ReactionItem[] = [\n  {\n    emoji: \"🚀\",\n    count: 14,\n    reactedByMe: true,\n    users: [\"You\", \"Elena Rostova\", \"Marcus Chen\", \"Liam Vance\"],\n  },\n  {\n    emoji: \"🔥\",\n    count: 8,\n    reactedByMe: false,\n    users: [\"Sarah Jenkins\", \"Chloe Dupont\", \"Amara Okafor\"],\n  },\n  {\n    emoji: \"❤️\",\n    count: 5,\n    reactedByMe: true,\n    users: [\"You\", \"Daisuke Sato\", \"Nadia Thorne\"],\n  },\n  {\n    emoji: \"🎉\",\n    count: 9,\n    reactedByMe: false,\n    users: [\"Marcus Chen\", \"Elena Rostova\", \"Sarah Jenkins\"],\n  },\n];\n\nexport function ReactionPicker({\n  initialReactions = DEFAULT_REACTIONS,\n  messageText = \"Just shipped the brand-new financial charts and collaboration suite! All 60fps spring transitions are running smoothly in staging. Let me know your feedback! 🚀⚡\",\n  authorName = \"Alexander Vance\",\n  authorRole = \"Staff Design Technologist\",\n  inline = false,\n  className,\n}: ReactionPickerProps) {\n  const [reactions, setReactions] = useState<ReactionItem[]>(initialReactions);\n  const [isQuickBarOpen, setIsQuickBarOpen] = useState(false);\n  const [isFullPickerOpen, setIsFullPickerOpen] = useState(false);\n  const [searchQuery, setSearchQuery] = useState(\"\");\n  const [hoveredBadge, setHoveredBadge] = useState<string | null>(null);\n\n  const containerRef = useRef<HTMLDivElement>(null);\n\n  // Toggle reaction vote\n  const toggleReaction = (emoji: string) => {\n    setReactions((prev) => {\n      const existing = prev.find((r) => r.emoji === emoji);\n      if (existing) {\n        if (existing.reactedByMe) {\n          // Decrement\n          const newCount = existing.count - 1;\n          if (newCount <= 0) {\n            return prev.filter((r) => r.emoji !== emoji);\n          }\n          return prev.map((r) =>\n            r.emoji === emoji\n              ? {\n                  ...r,\n                  count: newCount,\n                  reactedByMe: false,\n                  users: r.users.filter((u) => u !== \"You\"),\n                }\n              : r\n          );\n        } else {\n          // Increment\n          return prev.map((r) =>\n            r.emoji === emoji\n              ? {\n                  ...r,\n                  count: r.count + 1,\n                  reactedByMe: true,\n                  users: [\"You\", ...r.users],\n                }\n              : r\n          );\n        }\n      } else {\n        // Add brand new reaction\n        return [\n          ...prev,\n          {\n            emoji,\n            count: 1,\n            reactedByMe: true,\n            users: [\"You\"],\n          },\n        ];\n      }\n    });\n\n    setIsQuickBarOpen(false);\n    setIsFullPickerOpen(false);\n  };\n\n  const filteredFullEmojis = FULL_EMOJIS.filter((item) =>\n    item.name.toLowerCase().includes(searchQuery.toLowerCase().trim())\n  );\n\n  useEffect(() => {\n    function handleClickOutside(event: MouseEvent) {\n      if (containerRef.current && !containerRef.current.contains(event.target as Node)) {\n        setIsQuickBarOpen(false);\n        setIsFullPickerOpen(false);\n      }\n    }\n    document.addEventListener(\"mousedown\", handleClickOutside);\n    return () => document.removeEventListener(\"mousedown\", handleClickOutside);\n  }, []);\n\n  if (inline) {\n    return (\n      <div ref={containerRef} className={cn(\"relative flex flex-wrap items-center gap-1.5\", className)}>\n        {reactions.map((r) => (\n          <div\n            key={r.emoji}\n            className=\"relative\"\n            onMouseEnter={() => setHoveredBadge(r.emoji)}\n            onMouseLeave={() => setHoveredBadge(null)}\n          >\n            <motion.button\n              whileTap={{ scale: 0.88 }}\n              transition={{\n                type: \"spring\",\n                stiffness: 500,\n                damping: 25,\n              }}\n              type=\"button\"\n              onClick={() => toggleReaction(r.emoji)}\n              className={cn(\n                \"inline-flex items-center gap-1.5 rounded-full border px-2.5 py-1 text-xs font-medium transition-all select-none\",\n                r.reactedByMe\n                  ? \"border-indigo-500/60 bg-indigo-500/20 text-indigo-200 shadow-sm shadow-indigo-500/20\"\n                  : \"border-neutral-800 bg-neutral-900/90 text-neutral-400 hover:border-neutral-700 hover:bg-neutral-800 hover:text-neutral-200\"\n              )}\n            >\n              <span className=\"text-sm leading-none\">{r.emoji}</span>\n              <motion.span\n                key={r.count}\n                initial={{ scale: 1.3, y: -2 }}\n                animate={{ scale: 1, y: 0 }}\n                className=\"font-mono text-xs font-semibold\"\n              >\n                {r.count}\n              </motion.span>\n            </motion.button>\n\n            {/* Tooltip showing voters */}\n            <AnimatePresence>\n              {hoveredBadge === r.emoji && (\n                <motion.div\n                  initial={{ opacity: 0, y: 4, scale: 0.95 }}\n                  animate={{ opacity: 1, y: 0, scale: 1 }}\n                  exit={{ opacity: 0, scale: 0.95 }}\n                  className=\"pointer-events-none absolute bottom-full left-1/2 -translate-x-1/2 mb-1.5 z-30 whitespace-nowrap rounded-md border border-neutral-700 bg-neutral-900 px-2 py-1 text-[10px] text-neutral-200 shadow-xl\"\n                >\n                  <span>\n                    {r.users.slice(0, 3).join(\", \")}\n                    {r.users.length > 3 && ` and ${r.users.length - 3} others`}\n                  </span>\n                </motion.div>\n              )}\n            </AnimatePresence>\n          </div>\n        ))}\n\n        {/* Add reaction plus pill */}\n        <div className=\"relative\">\n          <button\n            type=\"button\"\n            onClick={() => setIsFullPickerOpen((prev) => !prev)}\n            className=\"inline-flex items-center gap-1 rounded-full border border-neutral-800 bg-neutral-900/60 px-2.5 py-1 text-xs text-neutral-400 hover:border-neutral-700 hover:bg-neutral-800 hover:text-neutral-200 transition-colors\"\n          >\n            <Plus className=\"h-3 w-3\" />\n            <Smile className=\"h-3.5 w-3.5\" />\n          </button>\n\n          {/* Quick Picker Dropdown */}\n          <AnimatePresence>\n            {isFullPickerOpen && (\n              <motion.div\n                initial={{ opacity: 0, y: 8, scale: 0.95 }}\n                animate={{ opacity: 1, y: 0, scale: 1 }}\n                exit={{ opacity: 0, y: 8, scale: 0.95 }}\n                transition={{ duration: 0.15 }}\n                className=\"absolute left-0 bottom-full mb-2 z-30 w-72 rounded-2xl border border-neutral-800 bg-neutral-950/95 p-3 shadow-2xl backdrop-blur-2xl\"\n              >\n                <div className=\"relative mb-3\">\n                  <Search className=\"absolute left-2.5 top-1/2 -translate-y-1/2 h-3.5 w-3.5 text-neutral-500\" />\n                  <input\n                    type=\"text\"\n                    value={searchQuery}\n                    onChange={(e) => setSearchQuery(e.target.value)}\n                    placeholder=\"Search reactions...\"\n                    className=\"w-full rounded-lg border border-neutral-800 bg-neutral-900 pl-8 pr-3 py-1.5 text-xs text-neutral-200 placeholder:text-neutral-500 focus:border-indigo-500 focus:outline-none\"\n                    autoFocus\n                  />\n                </div>\n                <div className=\"grid grid-cols-6 gap-1 max-h-48 overflow-y-auto pr-1\">\n                  {filteredFullEmojis.map((item) => (\n                    <motion.button\n                      key={item.name}\n                      whileHover={{ scale: 1.25 }}\n                      whileTap={{ scale: 0.9 }}\n                      type=\"button\"\n                      onClick={() => {\n                        toggleReaction(item.emoji);\n                        setIsFullPickerOpen(false);\n                      }}\n                      className=\"flex h-9 w-9 items-center justify-center rounded-lg text-xl hover:bg-neutral-800 transition-colors\"\n                      title={item.name}\n                    >\n                      {item.emoji}\n                    </motion.button>\n                  ))}\n                </div>\n              </motion.div>\n            )}\n          </AnimatePresence>\n        </div>\n      </div>\n    );\n  }\n\n  return (\n    <div\n      data-fullscreen-scroll\n      className={cn(\n        \"relative w-full min-h-[520px] overflow-hidden rounded-2xl border border-neutral-200/80 bg-neutral-950 p-6 text-neutral-100 shadow-xl dark:border-neutral-800 flex flex-col justify-between\",\n        className\n      )}\n    >\n      {/* Ambient background blur */}\n      <div className=\"pointer-events-none absolute -top-32 right-1/4 h-80 w-80 rounded-full bg-pink-500/10 blur-[120px]\" />\n\n      {/* Top Header */}\n      <div className=\"relative z-10 flex flex-col sm:flex-row items-start sm:items-center justify-between gap-3 border-b border-neutral-800/80 pb-4\">\n        <div className=\"flex items-center gap-2\">\n          <MessageCircle className=\"h-5 w-5 text-neutral-400\" />\n          <span className=\"font-semibold text-sm text-white\">\n            Slack-Style Emoji Reaction Bar\n          </span>\n          <span className=\"rounded-full bg-neutral-800 border border-neutral-700/80 px-2 py-0.5 text-[10px] font-mono text-neutral-400\">\n            Spring Physics & Popover\n          </span>\n        </div>\n\n        <button\n          type=\"button\"\n          onClick={() => setReactions(DEFAULT_REACTIONS)}\n          className=\"flex items-center gap-1.5 rounded-lg border border-neutral-800 bg-neutral-900 px-2.5 py-1 text-xs text-neutral-400 hover:text-neutral-200 transition-colors\"\n        >\n          <RotateCcw className=\"h-3 w-3\" />\n          <span>Reset Reactions</span>\n        </button>\n      </div>\n\n      {/* Main Slack Message Card Stage */}\n      <div className=\"relative my-8 mx-auto w-full max-w-2xl\">\n        <div\n          ref={containerRef}\n          className=\"group relative rounded-2xl border border-neutral-800/90 bg-neutral-900/60 p-5 backdrop-blur-md transition-all hover:border-neutral-700/80 hover:bg-neutral-900/80 shadow-xl\"\n        >\n          {/* Floating Slack Quick Reaction Bar on Hover / Trigger */}\n          <div className=\"absolute -top-4 right-4 z-20 flex items-center gap-1 rounded-xl border border-neutral-700/80 bg-neutral-900/95 p-1 shadow-2xl backdrop-blur-lg\">\n            {QUICK_EMOJIS.slice(0, 5).map((emoji) => (\n              <motion.button\n                key={emoji}\n                whileHover={{ scale: 1.35, y: -2 }}\n                whileTap={{ scale: 0.9 }}\n                transition={{ type: \"spring\", stiffness: 400, damping: 20 }}\n                type=\"button\"\n                onClick={() => toggleReaction(emoji)}\n                className=\"flex h-7 w-7 items-center justify-center rounded-lg text-base hover:bg-neutral-800 transition-colors\"\n                title={`React with ${emoji}`}\n              >\n                {emoji}\n              </motion.button>\n            ))}\n\n            {/* Open Quick Bar Popover or Full Picker */}\n            <button\n              type=\"button\"\n              onClick={() => setIsFullPickerOpen((prev) => !prev)}\n              className={cn(\n                \"flex h-7 w-7 items-center justify-center rounded-lg text-neutral-400 hover:bg-neutral-800 hover:text-white transition-colors\",\n                isFullPickerOpen && \"bg-neutral-800 text-white\"\n              )}\n              title=\"Add reaction\"\n            >\n              <Smile className=\"h-4 w-4\" />\n            </button>\n          </div>\n\n          {/* Full Expanded Emoji Picker Modal/Popover */}\n          <AnimatePresence>\n            {isFullPickerOpen && (\n              <motion.div\n                initial={{ opacity: 0, y: 8, scale: 0.95 }}\n                animate={{ opacity: 1, y: 0, scale: 1 }}\n                exit={{ opacity: 0, y: 8, scale: 0.95 }}\n                transition={{ duration: 0.15 }}\n                className=\"absolute right-4 top-8 z-30 w-72 rounded-2xl border border-neutral-800 bg-neutral-950/95 p-3 shadow-2xl backdrop-blur-2xl\"\n              >\n                {/* Search Bar */}\n                <div className=\"relative mb-3\">\n                  <Search className=\"absolute left-2.5 top-1/2 -translate-y-1/2 h-3.5 w-3.5 text-neutral-500\" />\n                  <input\n                    type=\"text\"\n                    value={searchQuery}\n                    onChange={(e) => setSearchQuery(e.target.value)}\n                    placeholder=\"Search reactions...\"\n                    className=\"w-full rounded-lg border border-neutral-800 bg-neutral-900 pl-8 pr-3 py-1.5 text-xs text-neutral-200 placeholder:text-neutral-500 focus:border-indigo-500 focus:outline-none\"\n                    autoFocus\n                  />\n                </div>\n\n                {/* Emoji Grid */}\n                <div className=\"grid grid-cols-6 gap-1 max-h-48 overflow-y-auto pr-1\">\n                  {filteredFullEmojis.map((item) => (\n                    <motion.button\n                      key={item.name}\n                      whileHover={{ scale: 1.25 }}\n                      whileTap={{ scale: 0.9 }}\n                      type=\"button\"\n                      onClick={() => toggleReaction(item.emoji)}\n                      className=\"flex h-9 w-9 items-center justify-center rounded-lg text-xl hover:bg-neutral-800 transition-colors\"\n                      title={item.name}\n                    >\n                      {item.emoji}\n                    </motion.button>\n                  ))}\n                </div>\n              </motion.div>\n            )}\n          </AnimatePresence>\n\n          {/* Message Author Header */}\n          <div className=\"flex items-start gap-3\">\n            <div className=\"relative h-10 w-10 shrink-0 rounded-full bg-gradient-to-tr from-indigo-500 to-rose-500 p-0.5\">\n              <div className=\"h-full w-full rounded-full bg-neutral-950 flex items-center justify-center font-bold text-xs text-white\">\n                AV\n              </div>\n              <span className=\"absolute bottom-0 right-0 h-3 w-3 rounded-full border-2 border-neutral-900 bg-emerald-500\" />\n            </div>\n\n            <div className=\"flex-1\">\n              <div className=\"flex items-baseline gap-2\">\n                <span className=\"font-semibold text-sm text-white\">\n                  {authorName}\n                </span>\n                <span className=\"text-[11px] text-neutral-500 font-mono\">\n                  {authorRole}\n                </span>\n                <span className=\"text-[10px] text-neutral-600\">\n                  Today at 10:42 AM\n                </span>\n              </div>\n\n              {/* Message Body */}\n              <p className=\"mt-1.5 text-sm text-neutral-200 leading-relaxed\">\n                {messageText}\n              </p>\n\n              {/* Active Reaction Pills Container */}\n              <div className=\"mt-4 flex flex-wrap items-center gap-1.5\">\n                {reactions.map((r) => {\n                  return (\n                    <div\n                      key={r.emoji}\n                      className=\"relative\"\n                      onMouseEnter={() => setHoveredBadge(r.emoji)}\n                      onMouseLeave={() => setHoveredBadge(null)}\n                    >\n                      <motion.button\n                        whileTap={{ scale: 0.88 }}\n                        transition={{\n                          type: \"spring\",\n                          stiffness: 500,\n                          damping: 25,\n                        }}\n                        type=\"button\"\n                        onClick={() => toggleReaction(r.emoji)}\n                        className={cn(\n                          \"inline-flex items-center gap-1.5 rounded-full border px-2.5 py-1 text-xs font-medium transition-all select-none\",\n                          r.reactedByMe\n                            ? \"border-indigo-500/60 bg-indigo-500/20 text-indigo-200 shadow-sm shadow-indigo-500/20\"\n                            : \"border-neutral-800 bg-neutral-900/90 text-neutral-400 hover:border-neutral-700 hover:bg-neutral-800 hover:text-neutral-200\"\n                        )}\n                      >\n                        <span className=\"text-sm leading-none\">{r.emoji}</span>\n                        <motion.span\n                          key={r.count}\n                          initial={{ scale: 1.3, y: -2 }}\n                          animate={{ scale: 1, y: 0 }}\n                          className=\"font-mono text-xs font-semibold\"\n                        >\n                          {r.count}\n                        </motion.span>\n                      </motion.button>\n\n                      {/* Tooltip showing voters */}\n                      <AnimatePresence>\n                        {hoveredBadge === r.emoji && (\n                          <motion.div\n                            initial={{ opacity: 0, y: 4, scale: 0.95 }}\n                            animate={{ opacity: 1, y: 0, scale: 1 }}\n                            exit={{ opacity: 0, scale: 0.95 }}\n                            className=\"pointer-events-none absolute bottom-full left-1/2 -translate-x-1/2 mb-1.5 z-30 whitespace-nowrap rounded-md border border-neutral-700 bg-neutral-900 px-2 py-1 text-[10px] text-neutral-200 shadow-xl\"\n                          >\n                            <span>\n                              {r.users.slice(0, 3).join(\", \")}\n                              {r.users.length > 3 &&\n                                ` and ${r.users.length - 3} others`}\n                            </span>\n                          </motion.div>\n                        )}\n                      </AnimatePresence>\n                    </div>\n                  );\n                })}\n\n                {/* Add reaction plus pill */}\n                <button\n                  type=\"button\"\n                  onClick={() => setIsFullPickerOpen((prev) => !prev)}\n                  className=\"inline-flex items-center gap-1 rounded-full border border-neutral-800 bg-neutral-900/60 px-2.5 py-1 text-xs text-neutral-400 hover:border-neutral-700 hover:bg-neutral-800 hover:text-neutral-200 transition-colors\"\n                >\n                  <Plus className=\"h-3 w-3\" />\n                  <Smile className=\"h-3.5 w-3.5\" />\n                </button>\n              </div>\n            </div>\n          </div>\n        </div>\n      </div>\n\n      {/* Footer Features Info */}\n      <div className=\"relative z-10 flex flex-wrap items-center justify-between gap-3 border-t border-neutral-800/80 pt-4 text-xs text-neutral-400\">\n        <div className=\"flex items-center gap-2\">\n          <span className=\"h-2 w-2 rounded-full bg-indigo-500\" />\n          <span>Click reaction badge to toggle your vote</span>\n        </div>\n\n        <div className=\"flex items-center gap-1.5 text-neutral-500 font-mono text-[11px]\">\n          <Sparkles className=\"h-3 w-3 text-indigo-400\" />\n          <span>Framer Motion Spring Count Bumps</span>\n        </div>\n      </div>\n    </div>\n  );\n}\n\nexport default ReactionPicker;\n",
          "type": "registry:ui",
          "target": "components/ui/reaction-picker.tsx"
        },
        {
          "path": "lib/utils.ts",
          "content": "import { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...inputs: ClassValue[]) {\n  return twMerge(clsx(inputs));\n}\n\nexport async function copyToClipboard(text: string): Promise<boolean> {\n  if (typeof window === \"undefined\") return false;\n\n  try {\n    if (navigator.clipboard && window.isSecureContext) {\n      await navigator.clipboard.writeText(text);\n      return true;\n    }\n\n    const textArea = document.createElement(\"textarea\");\n    textArea.value = text;\n    textArea.style.position = \"fixed\";\n    textArea.style.left = \"-999999px\";\n    textArea.style.top = \"-999999px\";\n    document.body.appendChild(textArea);\n    textArea.focus();\n    textArea.select();\n    const succeeded = document.execCommand(\"copy\");\n    textArea.remove();\n    return succeeded;\n  } catch {\n    return false;\n  }\n}\n",
          "type": "registry:lib",
          "target": "lib/utils.ts"
        }
      ]
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "ripple-burst-button",
      "type": "registry:ui",
      "title": "Ripple Burst Button",
      "author": "Rishabh Bose <https://theb0se.vercel.app/>",
      "description": "Tactile impulse button that spawns dual concentric shockwave rings from the exact pointer click coordinate with spring recoil.",
      "dependencies": [
        "framer-motion",
        "lucide-react",
        "clsx",
        "tailwind-merge"
      ],
      "files": [
        {
          "path": "components/ui/ripple-burst-button.tsx",
          "content": "\"use client\";\n\nimport React, { useRef, useState } from \"react\";\nimport { motion, useReducedMotion } from \"framer-motion\";\nimport { Zap } from \"lucide-react\";\nimport { cn } from \"@/lib/utils\";\n\nexport interface RippleBurstButtonProps {\n  /** Button label text. Default: \"Emit Shockwave Pulse\" */\n  label?: string;\n  /** Spring stiffness coefficient for tactile press compression. Default: 400 */\n  stiffness?: number;\n  /** Spring damping coefficient for tactile press compression. Default: 22 */\n  damping?: number;\n  /** Click callback */\n  onClick?: () => void;\n  className?: string;\n}\n\ninterface RippleWave {\n  id: number;\n  x: number;\n  y: number;\n}\n\nexport function RippleBurstButton({\n  label = \"Emit Shockwave Pulse\",\n  stiffness = 400,\n  damping = 22,\n  onClick,\n  className,\n}: RippleBurstButtonProps) {\n  const shouldReduceMotion = useReducedMotion() ?? false;\n  const btnRef = useRef<HTMLButtonElement | null>(null);\n  const [waves, setWaves] = useState<RippleWave[]>([]);\n  const [pulseCount, setPulseCount] = useState(0);\n\n  const handleTrigger = (e: React.MouseEvent<HTMLButtonElement>) => {\n    const el = btnRef.current;\n    if (el && !shouldReduceMotion) {\n      const rect = el.getBoundingClientRect();\n      const x = e.clientX ? e.clientX - rect.left : rect.width / 2;\n      const y = e.clientY ? e.clientY - rect.top : rect.height / 2;\n      const id = Date.now() + Math.random();\n      setWaves((prev) => [...prev.slice(-3), { id, x, y }]);\n    }\n    setPulseCount((c) => c + 1);\n    onClick?.();\n  };\n\n  return (\n    <motion.button\n      ref={btnRef}\n      type=\"button\"\n      onClick={handleTrigger}\n      whileHover={shouldReduceMotion ? undefined : { scale: 1.03, y: -2 }}\n      whileTap={shouldReduceMotion ? undefined : { scale: 0.95 }}\n      transition={{ type: \"spring\", stiffness, damping }}\n      className={cn(\n        \"relative inline-flex h-12 items-center justify-center gap-2.5 overflow-hidden rounded-2xl border border-black bg-black px-6 text-xs font-semibold text-white shadow-sm focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-black focus-visible:ring-offset-2 dark:border-white dark:bg-white dark:text-black dark:focus-visible:ring-white\",\n        className\n      )}\n    >\n      {/* Concentric Dual Shockwave Rings */}\n      {!shouldReduceMotion &&\n        waves.map((wave) => (\n          <React.Fragment key={wave.id}>\n            <motion.span\n              aria-hidden=\"true\"\n              initial={{ scale: 0, opacity: 0.65 }}\n              animate={{ scale: 4.5, opacity: 0 }}\n              transition={{ duration: 0.65, ease: \"easeOut\" }}\n              style={{ left: wave.x - 24, top: wave.y - 24 }}\n              className=\"pointer-events-none absolute h-12 w-12 rounded-full bg-white/35 dark:bg-black/25\"\n            />\n            <motion.span\n              aria-hidden=\"true\"\n              initial={{ scale: 0, opacity: 0.8 }}\n              animate={{ scale: 3.2, opacity: 0 }}\n              transition={{ duration: 0.55, delay: 0.06, ease: \"easeOut\" }}\n              style={{ left: wave.x - 24, top: wave.y - 24 }}\n              className=\"pointer-events-none absolute h-12 w-12 rounded-full border border-white/60 dark:border-black/50\"\n            />\n          </React.Fragment>\n        ))}\n\n      <Zap className=\"relative z-10 h-4 w-4\" />\n      <span className=\"relative z-10\">{label}</span>\n      {pulseCount > 0 && (\n        <span className=\"relative z-10 rounded-full bg-white/20 px-1.5 py-0.5 font-mono text-[10px] dark:bg-black/15\">\n          ×{pulseCount}\n        </span>\n      )}\n    </motion.button>\n  );\n}\n\nexport default RippleBurstButton;\n",
          "type": "registry:ui",
          "target": "components/ui/ripple-burst-button.tsx"
        },
        {
          "path": "lib/utils.ts",
          "content": "import { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...inputs: ClassValue[]) {\n  return twMerge(clsx(inputs));\n}\n\nexport async function copyToClipboard(text: string): Promise<boolean> {\n  if (typeof window === \"undefined\") return false;\n\n  try {\n    if (navigator.clipboard && window.isSecureContext) {\n      await navigator.clipboard.writeText(text);\n      return true;\n    }\n\n    const textArea = document.createElement(\"textarea\");\n    textArea.value = text;\n    textArea.style.position = \"fixed\";\n    textArea.style.left = \"-999999px\";\n    textArea.style.top = \"-999999px\";\n    document.body.appendChild(textArea);\n    textArea.focus();\n    textArea.select();\n    const succeeded = document.execCommand(\"copy\");\n    textArea.remove();\n    return succeeded;\n  } catch {\n    return false;\n  }\n}\n",
          "type": "registry:lib",
          "target": "lib/utils.ts"
        }
      ]
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "rolling-number-ticker",
      "type": "registry:ui",
      "title": "Rolling Number Ticker",
      "author": "Rishabh Bose <https://theb0se.vercel.app/>",
      "description": "Wise and Robinhood-style vertical rolling cylinder odometer number ticker with independent digit strips, smooth Hooke's Law spring physics, customizable currency prefix, and decimal formatting.",
      "dependencies": [
        "framer-motion",
        "lucide-react",
        "clsx",
        "tailwind-merge"
      ],
      "files": [
        {
          "path": "components/ui/rolling-number-ticker.tsx",
          "content": "\"use client\";\n\nimport React, { useEffect, useRef, useState } from \"react\";\nimport { motion } from \"framer-motion\";\nimport { ArrowUpRight, ArrowDownRight } from \"lucide-react\";\nimport { cn } from \"@/lib/utils\";\n\nexport interface RollingNumberTickerProps {\n  /** Target numeric value to display */\n  value?: number;\n  /** Currency symbol or prefix (e.g. \"$\", \"€\") */\n  currency?: string;\n  /** Decimal precision (default: 2) */\n  decimalPlaces?: number;\n  /** Font size scale variant */\n  fontSize?: \"sm\" | \"md\" | \"lg\" | \"xl\";\n  /** Spring physics stiffness (default: 260) */\n  stiffness?: number;\n  /** Spring physics damping (default: 26) */\n  damping?: number;\n  className?: string;\n}\n\nconst DIGITS = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];\n\ninterface SingleDigitColumnProps {\n  digit: number;\n  itemHeight: number;\n  stiffness: number;\n  damping: number;\n}\n\nfunction SingleDigitColumn({\n  digit,\n  itemHeight,\n  stiffness,\n  damping,\n}: SingleDigitColumnProps) {\n  return (\n    <div\n      style={{ height: itemHeight }}\n      className=\"relative overflow-hidden inline-flex items-center justify-center font-mono font-bold select-none\"\n    >\n      <motion.div\n        animate={{ y: -digit * itemHeight }}\n        transition={{\n          type: \"spring\",\n          stiffness,\n          damping,\n          mass: 0.8,\n        }}\n        className=\"flex flex-col items-center\"\n      >\n        {DIGITS.map((d) => (\n          <div\n            key={d}\n            style={{ height: itemHeight, lineHeight: `${itemHeight}px` }}\n            className=\"flex items-center justify-center\"\n          >\n            {d}\n          </div>\n        ))}\n      </motion.div>\n    </div>\n  );\n}\n\nexport function RollingNumberTicker({\n  value = 48932.18,\n  currency = \"$\",\n  decimalPlaces = 2,\n  fontSize = \"xl\",\n  stiffness = 260,\n  damping = 26,\n  className,\n}: RollingNumberTickerProps) {\n  const [lastDirection, setLastDirection] = useState<\"up\" | \"down\" | null>(null);\n  const prevValRef = useRef(value);\n\n  useEffect(() => {\n    if (value > prevValRef.current) {\n      setLastDirection(\"up\");\n    } else if (value < prevValRef.current) {\n      setLastDirection(\"down\");\n    }\n    prevValRef.current = value;\n\n    const timer = setTimeout(() => {\n      setLastDirection(null);\n    }, 900);\n    return () => clearTimeout(timer);\n  }, [value]);\n\n  const formattedString = value.toLocaleString(\"en-US\", {\n    minimumFractionDigits: decimalPlaces,\n    maximumFractionDigits: decimalPlaces,\n  });\n\n  const chars = formattedString.split(\"\");\n  const itemHeight = fontSize === \"sm\" ? 36 : fontSize === \"md\" ? 44 : fontSize === \"lg\" ? 54 : 64;\n\n  const fontClasses =\n    fontSize === \"sm\"\n      ? \"text-xl sm:text-2xl\"\n      : fontSize === \"md\"\n      ? \"text-2xl sm:text-3xl\"\n      : fontSize === \"lg\"\n      ? \"text-3xl sm:text-4xl\"\n      : \"text-3xl sm:text-5xl\";\n\n  return (\n    <div\n      data-fullscreen-scroll\n      className={cn(\n        \"relative inline-flex flex-col items-center justify-center select-none\",\n        className\n      )}\n    >\n      {/* Status Pill Indicator */}\n      {lastDirection && (\n        <div className=\"mb-2 flex items-center gap-1 text-xs font-medium\">\n          {lastDirection === \"up\" && (\n            <motion.span\n              initial={{ opacity: 0, y: 4 }}\n              animate={{ opacity: 1, y: 0 }}\n              className=\"inline-flex items-center gap-1 text-emerald-400 font-mono text-[11px]\"\n            >\n              <ArrowUpRight className=\"h-3 w-3\" />\n              <span>Increased</span>\n            </motion.span>\n          )}\n          {lastDirection === \"down\" && (\n            <motion.span\n              initial={{ opacity: 0, y: -4 }}\n              animate={{ opacity: 1, y: 0 }}\n              className=\"inline-flex items-center gap-1 text-rose-400 font-mono text-[11px]\"\n            >\n              <ArrowDownRight className=\"h-3 w-3\" />\n              <span>Decreased</span>\n            </motion.span>\n          )}\n        </div>\n      )}\n\n      {/* Cylinder Odometer Frame */}\n      <div className=\"relative flex items-center justify-center rounded-2xl border border-neutral-800 bg-neutral-900/90 px-6 py-3 shadow-2xl backdrop-blur-md\">\n        {/* Shading Masks */}\n        <div className=\"pointer-events-none absolute inset-x-0 top-0 h-3 bg-gradient-to-b from-neutral-900 via-neutral-900/80 to-transparent z-10\" />\n        <div className=\"pointer-events-none absolute inset-x-0 bottom-0 h-3 bg-gradient-to-t from-neutral-900 via-neutral-900/80 to-transparent z-10\" />\n\n        {/* Currency Prefix */}\n        {currency && (\n          <span\n            style={{ height: itemHeight, lineHeight: `${itemHeight}px` }}\n            className={cn(\"mr-1.5 font-mono font-extrabold text-neutral-400\", fontClasses)}\n          >\n            {currency}\n          </span>\n        )}\n\n        {/* Rolling Columns */}\n        <div className={cn(\"flex items-center font-extrabold text-white\", fontClasses)}>\n          {chars.map((char, index) => {\n            const digit = parseInt(char, 10);\n            const isDigit = !isNaN(digit);\n\n            if (!isDigit) {\n              return (\n                <span\n                  key={`static-${index}`}\n                  style={{ height: itemHeight, lineHeight: `${itemHeight}px` }}\n                  className=\"inline-flex items-center justify-center font-mono text-neutral-400 px-0.5\"\n                >\n                  {char}\n                </span>\n              );\n            }\n\n            return (\n              <SingleDigitColumn\n                key={`col-${index}`}\n                digit={digit}\n                itemHeight={itemHeight}\n                stiffness={stiffness}\n                damping={damping}\n              />\n            );\n          })}\n        </div>\n      </div>\n    </div>\n  );\n}\n\nexport default RollingNumberTicker;\n",
          "type": "registry:ui",
          "target": "components/ui/rolling-number-ticker.tsx"
        },
        {
          "path": "lib/utils.ts",
          "content": "import { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...inputs: ClassValue[]) {\n  return twMerge(clsx(inputs));\n}\n\nexport async function copyToClipboard(text: string): Promise<boolean> {\n  if (typeof window === \"undefined\") return false;\n\n  try {\n    if (navigator.clipboard && window.isSecureContext) {\n      await navigator.clipboard.writeText(text);\n      return true;\n    }\n\n    const textArea = document.createElement(\"textarea\");\n    textArea.value = text;\n    textArea.style.position = \"fixed\";\n    textArea.style.left = \"-999999px\";\n    textArea.style.top = \"-999999px\";\n    document.body.appendChild(textArea);\n    textArea.focus();\n    textArea.select();\n    const succeeded = document.execCommand(\"copy\");\n    textArea.remove();\n    return succeeded;\n  } catch {\n    return false;\n  }\n}\n",
          "type": "registry:lib",
          "target": "lib/utils.ts"
        }
      ]
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "rotary-spring-dial",
      "type": "registry:ui",
      "title": "Rotary Spring Dial",
      "author": "Rishabh Bose <https://theb0se.vercel.app/>",
      "description": "Synthesizer-inspired tactile rotary knob with a 270-degree spring-damped rotor, vertical drag scrubbing, and keyboard arrow control.",
      "dependencies": [
        "framer-motion",
        "clsx",
        "tailwind-merge"
      ],
      "files": [
        {
          "path": "components/ui/rotary-spring-dial.tsx",
          "content": "\"use client\";\n\nimport React, { useRef, useState } from \"react\";\nimport { motion, useSpring, useReducedMotion } from \"framer-motion\";\nimport { cn } from \"@/lib/utils\";\n\nexport interface RotarySpringDialProps {\n  /** Dial parameter label. Default: \"Damping Ratio\" */\n  label?: string;\n  /** Initial value between min and max. Default: 65 */\n  defaultValue?: number;\n  /** Minimum value. Default: 0 */\n  min?: number;\n  /** Maximum value. Default: 100 */\n  max?: number;\n  /** Step increment. Default: 5 */\n  step?: number;\n  /** Unit suffix. Default: \"%\" */\n  unit?: string;\n  /** Spring stiffness coefficient for rotary needle. Default: 340 */\n  stiffness?: number;\n  /** Spring damping coefficient for rotary needle. Default: 24 */\n  damping?: number;\n  /** Callback fired when value changes */\n  onChange?: (val: number) => void;\n  className?: string;\n}\n\nexport function RotarySpringDial({\n  label = \"Damping Ratio\",\n  defaultValue = 65,\n  min = 0,\n  max = 100,\n  step = 5,\n  unit = \"%\",\n  stiffness = 340,\n  damping = 24,\n  onChange,\n  className,\n}: RotarySpringDialProps) {\n  const shouldReduceMotion = useReducedMotion() ?? false;\n  const [value, setValue] = useState<number>(() =>\n    Math.min(max, Math.max(min, defaultValue))\n  );\n  const [isDragging, setIsDragging] = useState(false);\n  const startYRef = useRef<number>(0);\n  const startValRef = useRef<number>(defaultValue);\n\n  const range = Math.max(1, max - min);\n  const ratio = (value - min) / range;\n  // Map 0..1 ratio to -135deg .. +135deg rotary arc\n  const targetAngle = -135 + ratio * 270;\n\n  const springAngle = useSpring(targetAngle, {\n    stiffness,\n    damping,\n    mass: 0.4,\n  });\n\n  const commitValue = (nextRaw: number) => {\n    const stepped = Math.round((nextRaw - min) / step) * step + min;\n    const clamped = Math.min(max, Math.max(min, stepped));\n    setValue(clamped);\n    const nextRatio = (clamped - min) / range;\n    springAngle.set(-135 + nextRatio * 270);\n    onChange?.(clamped);\n  };\n\n  const handlePointerDown = (e: React.PointerEvent<HTMLDivElement>) => {\n    e.currentTarget.setPointerCapture(e.pointerId);\n    setIsDragging(true);\n    startYRef.current = e.clientY;\n    startValRef.current = value;\n  };\n\n  const handlePointerMove = (e: React.PointerEvent<HTMLDivElement>) => {\n    if (!isDragging) return;\n    // Dragging upward increases value, downward decreases\n    const deltaY = startYRef.current - e.clientY;\n    const deltaVal = (deltaY / 120) * range;\n    commitValue(startValRef.current + deltaVal);\n  };\n\n  const handlePointerUp = (e: React.PointerEvent<HTMLDivElement>) => {\n    if (e.currentTarget.hasPointerCapture(e.pointerId)) {\n      e.currentTarget.releasePointerCapture(e.pointerId);\n    }\n    setIsDragging(false);\n  };\n\n  const handleKeyDown = (e: React.KeyboardEvent<HTMLDivElement>) => {\n    if (e.key === \"ArrowUp\" || e.key === \"ArrowRight\") {\n      e.preventDefault();\n      commitValue(value + step);\n    } else if (e.key === \"ArrowDown\" || e.key === \"ArrowLeft\") {\n      e.preventDefault();\n      commitValue(value - step);\n    } else if (e.key === \"Home\") {\n      e.preventDefault();\n      commitValue(min);\n    } else if (e.key === \"End\") {\n      e.preventDefault();\n      commitValue(max);\n    }\n  };\n\n  return (\n    <div\n      className={cn(\n        \"inline-flex flex-col items-center gap-3 rounded-3xl border border-neutral-200 bg-white px-6 py-5 shadow-sm select-none dark:border-[#222222] dark:bg-[#0A0A0A]\",\n        className\n      )}\n    >\n      <div className=\"text-[11px] font-semibold uppercase tracking-wider text-neutral-400\">\n        {label}\n      </div>\n\n      {/* Tactile Synthesizer Rotary Knob */}\n      <div\n        role=\"slider\"\n        tabIndex={0}\n        aria-label={label}\n        aria-valuemin={min}\n        aria-valuemax={max}\n        aria-valuenow={value}\n        aria-valuetext={`${value}${unit}`}\n        onPointerDown={handlePointerDown}\n        onPointerMove={handlePointerMove}\n        onPointerUp={handlePointerUp}\n        onPointerCancel={handlePointerUp}\n        onKeyDown={handleKeyDown}\n        className={cn(\n          \"relative flex h-24 w-24 cursor-ns-resize touch-none items-center justify-center rounded-full border-2 bg-neutral-50 shadow-inner transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-black dark:bg-[#121212] dark:focus-visible:ring-white\",\n          isDragging\n            ? \"border-black dark:border-white\"\n            : \"border-neutral-200 hover:border-neutral-400 dark:border-[#262626] dark:hover:border-[#3A3A3A]\"\n        )}\n      >\n        {/* Rotating Dial Rotor + Indicator Notch */}\n        <motion.div\n          aria-hidden=\"true\"\n          style={{\n            rotate: shouldReduceMotion ? targetAngle : springAngle,\n          }}\n          className=\"relative flex h-16 w-16 items-start justify-center rounded-full border border-neutral-300 bg-white pt-1.5 shadow-md dark:border-[#333333] dark:bg-[#1B1B1B]\"\n        >\n          <span className=\"h-3 w-1 rounded-full bg-black dark:bg-white\" />\n        </motion.div>\n      </div>\n\n      {/* Digital Readout + Quick Stepper */}\n      <div className=\"font-mono text-sm font-bold tabular-nums text-black dark:text-white\">\n        {value}\n        {unit}\n      </div>\n\n      <div className=\"text-[10px] text-neutral-400\">\n        Drag vertically or use ↑/↓ keys\n      </div>\n    </div>\n  );\n}\n\nexport default RotarySpringDial;\n",
          "type": "registry:ui",
          "target": "components/ui/rotary-spring-dial.tsx"
        },
        {
          "path": "lib/utils.ts",
          "content": "import { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...inputs: ClassValue[]) {\n  return twMerge(clsx(inputs));\n}\n\nexport async function copyToClipboard(text: string): Promise<boolean> {\n  if (typeof window === \"undefined\") return false;\n\n  try {\n    if (navigator.clipboard && window.isSecureContext) {\n      await navigator.clipboard.writeText(text);\n      return true;\n    }\n\n    const textArea = document.createElement(\"textarea\");\n    textArea.value = text;\n    textArea.style.position = \"fixed\";\n    textArea.style.left = \"-999999px\";\n    textArea.style.top = \"-999999px\";\n    document.body.appendChild(textArea);\n    textArea.focus();\n    textArea.select();\n    const succeeded = document.execCommand(\"copy\");\n    textArea.remove();\n    return succeeded;\n  } catch {\n    return false;\n  }\n}\n",
          "type": "registry:lib",
          "target": "lib/utils.ts"
        }
      ]
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "scrubbable-number-input",
      "type": "registry:ui",
      "title": "Scrubbable Number Input",
      "author": "Rishabh Bose <https://theb0se.vercel.app/>",
      "description": "Figma and Blender-inspired tactile numeric input with horizontal pointer drag scrubbing, elastic housing displacement, and kinetic digit roll.",
      "dependencies": [
        "framer-motion",
        "lucide-react",
        "clsx",
        "tailwind-merge"
      ],
      "files": [
        {
          "path": "components/ui/scrubbable-number-input.tsx",
          "content": "\"use client\";\n\nimport React, { useRef, useState } from \"react\";\nimport {\n  AnimatePresence,\n  motion,\n  useMotionValue,\n  useSpring,\n  useReducedMotion,\n} from \"framer-motion\";\nimport { MoveHorizontal, Minus, Plus } from \"lucide-react\";\nimport { cn } from \"@/lib/utils\";\n\nexport interface ScrubbableNumberInputProps {\n  /** Label shown on the left side of the scrubbable pill. Default: \"Stiffness\" */\n  label?: string;\n  /** Controlled numeric value */\n  value?: number;\n  /** Uncontrolled initial numeric value. Default: 240 */\n  defaultValue?: number;\n  /** Minimum value. Default: 0 */\n  min?: number;\n  /** Maximum value. Default: 1000 */\n  max?: number;\n  /** Base increment step per scrub unit. Default: 5 */\n  step?: number;\n  /** Pixels of horizontal drag required per step increment. Default: 4 */\n  pixelsPerStep?: number;\n  /** Unit suffix displayed next to the value. Default: \"N/m\" */\n  unit?: string;\n  /** Callback fired when numeric value changes */\n  onChange?: (value: number) => void;\n  className?: string;\n}\n\nexport function ScrubbableNumberInput({\n  label = \"Stiffness\",\n  value: controlledValue,\n  defaultValue = 240,\n  min = 0,\n  max = 1000,\n  step = 5,\n  pixelsPerStep = 4,\n  unit = \"N/m\",\n  onChange,\n  className,\n}: ScrubbableNumberInputProps) {\n  const shouldReduceMotion = useReducedMotion() ?? false;\n  const [internalValue, setInternalValue] = useState<number>(() =>\n    Math.min(max, Math.max(min, defaultValue))\n  );\n  const [isScrubbing, setIsScrubbing] = useState(false);\n  const [direction, setDirection] = useState<1 | -1>(1);\n\n  const startXRef = useRef<number>(0);\n  const startValRef = useRef<number>(defaultValue);\n\n  const currentValue =\n    controlledValue !== undefined ? controlledValue : internalValue;\n\n  // Elastic housing horizontal tug\n  const tugX = useMotionValue(0);\n  const springTugX = useSpring(tugX, {\n    stiffness: 380,\n    damping: 24,\n    mass: 0.4,\n  });\n\n  const commitValue = (nextRaw: number) => {\n    const stepped = Math.round((nextRaw - min) / step) * step + min;\n    const clamped = Math.min(max, Math.max(min, stepped));\n    if (clamped !== currentValue) {\n      setDirection(clamped > currentValue ? 1 : -1);\n      if (controlledValue === undefined) {\n        setInternalValue(clamped);\n      }\n      onChange?.(clamped);\n    }\n  };\n\n  const handlePointerDown = (e: React.PointerEvent<HTMLDivElement>) => {\n    if ((e.target as HTMLElement).closest(\"button\")) return;\n    e.currentTarget.setPointerCapture(e.pointerId);\n    setIsScrubbing(true);\n    startXRef.current = e.clientX;\n    startValRef.current = currentValue;\n  };\n\n  const handlePointerMove = (e: React.PointerEvent<HTMLDivElement>) => {\n    if (!isScrubbing) return;\n    const deltaX = e.clientX - startXRef.current;\n    const modifier = e.shiftKey ? 5 : e.altKey ? 0.2 : 1;\n    const stepsMoved = Math.round(deltaX / pixelsPerStep);\n    const nextVal = startValRef.current + stepsMoved * step * modifier;\n\n    // Subtle spring tug feedback capped at +-10px\n    const clampedTug = Math.max(-10, Math.min(10, deltaX * 0.12));\n    tugX.set(shouldReduceMotion ? 0 : clampedTug);\n\n    commitValue(nextVal);\n  };\n\n  const handlePointerUp = (e: React.PointerEvent<HTMLDivElement>) => {\n    if (e.currentTarget.hasPointerCapture(e.pointerId)) {\n      e.currentTarget.releasePointerCapture(e.pointerId);\n    }\n    setIsScrubbing(false);\n    tugX.set(0);\n  };\n\n  const handleKeyDown = (e: React.KeyboardEvent<HTMLDivElement>) => {\n    const multiplier = e.shiftKey ? 10 : 1;\n    if (e.key === \"ArrowRight\" || e.key === \"ArrowUp\") {\n      e.preventDefault();\n      commitValue(currentValue + step * multiplier);\n    } else if (e.key === \"ArrowLeft\" || e.key === \"ArrowDown\") {\n      e.preventDefault();\n      commitValue(currentValue - step * multiplier);\n    } else if (e.key === \"Home\") {\n      e.preventDefault();\n      commitValue(min);\n    } else if (e.key === \"End\") {\n      e.preventDefault();\n      commitValue(max);\n    }\n  };\n\n  return (\n    <motion.div\n      role=\"spinbutton\"\n      tabIndex={0}\n      aria-label={label}\n      aria-valuemin={min}\n      aria-valuemax={max}\n      aria-valuenow={currentValue}\n      aria-valuetext={`${currentValue} ${unit}`}\n      onPointerDown={handlePointerDown}\n      onPointerMove={handlePointerMove}\n      onPointerUp={handlePointerUp}\n      onPointerCancel={handlePointerUp}\n      onKeyDown={handleKeyDown}\n      style={{ x: shouldReduceMotion ? 0 : springTugX }}\n      className={cn(\n        \"group inline-flex w-full max-w-xs cursor-ew-resize select-none touch-none items-center justify-between gap-3 rounded-2xl border bg-white px-4 py-3 transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-black dark:bg-[#0A0A0A] dark:focus-visible:ring-white\",\n        isScrubbing\n          ? \"border-black shadow-sm dark:border-white\"\n          : \"border-neutral-200 hover:border-neutral-400 dark:border-[#222222] dark:hover:border-[#383838]\",\n        className\n      )}\n    >\n      {/* Left Scrub Label */}\n      <div className=\"flex items-center gap-2\">\n        <MoveHorizontal\n          aria-hidden=\"true\"\n          className={cn(\n            \"h-3.5 w-3.5 transition-colors\",\n            isScrubbing\n              ? \"text-black dark:text-white\"\n              : \"text-neutral-400 group-hover:text-neutral-600 dark:group-hover:text-neutral-300\"\n          )}\n        />\n        <span className=\"text-xs font-semibold text-neutral-600 dark:text-neutral-300\">\n          {label}\n        </span>\n      </div>\n\n      {/* Right Value + Stepper Controls */}\n      <div className=\"flex items-center gap-2\">\n        <button\n          type=\"button\"\n          tabIndex={-1}\n          aria-label={`Decrease ${label}`}\n          onClick={() => commitValue(currentValue - step)}\n          disabled={currentValue <= min}\n          className=\"flex h-6 w-6 items-center justify-center rounded-lg border border-neutral-200 text-neutral-500 transition-colors hover:border-black hover:text-black disabled:opacity-30 dark:border-[#262626] dark:hover:border-white dark:hover:text-white\"\n        >\n          <Minus className=\"h-3 w-3\" />\n        </button>\n\n        <div className=\"relative flex min-w-[4.5rem] items-baseline justify-end overflow-hidden font-mono text-sm font-semibold tabular-nums text-black dark:text-white\">\n          <AnimatePresence mode=\"popLayout\" initial={false}>\n            <motion.span\n              key={currentValue}\n              initial={\n                shouldReduceMotion\n                  ? { opacity: 1 }\n                  : { y: direction * 12, opacity: 0 }\n              }\n              animate={{ y: 0, opacity: 1 }}\n              exit={\n                shouldReduceMotion\n                  ? { opacity: 0 }\n                  : { y: direction * -12, opacity: 0 }\n              }\n              transition={{ type: \"spring\", stiffness: 420, damping: 28 }}\n              className=\"inline-block\"\n            >\n              {currentValue}\n            </motion.span>\n          </AnimatePresence>\n          {unit && (\n            <span className=\"ml-1 text-[10px] font-normal text-neutral-400\">\n              {unit}\n            </span>\n          )}\n        </div>\n\n        <button\n          type=\"button\"\n          tabIndex={-1}\n          aria-label={`Increase ${label}`}\n          onClick={() => commitValue(currentValue + step)}\n          disabled={currentValue >= max}\n          className=\"flex h-6 w-6 items-center justify-center rounded-lg border border-neutral-200 text-neutral-500 transition-colors hover:border-black hover:text-black disabled:opacity-30 dark:border-[#262626] dark:hover:border-white dark:hover:text-white\"\n        >\n          <Plus className=\"h-3 w-3\" />\n        </button>\n      </div>\n    </motion.div>\n  );\n}\n\nexport default ScrubbableNumberInput;\n",
          "type": "registry:ui",
          "target": "components/ui/scrubbable-number-input.tsx"
        },
        {
          "path": "lib/utils.ts",
          "content": "import { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...inputs: ClassValue[]) {\n  return twMerge(clsx(inputs));\n}\n\nexport async function copyToClipboard(text: string): Promise<boolean> {\n  if (typeof window === \"undefined\") return false;\n\n  try {\n    if (navigator.clipboard && window.isSecureContext) {\n      await navigator.clipboard.writeText(text);\n      return true;\n    }\n\n    const textArea = document.createElement(\"textarea\");\n    textArea.value = text;\n    textArea.style.position = \"fixed\";\n    textArea.style.left = \"-999999px\";\n    textArea.style.top = \"-999999px\";\n    document.body.appendChild(textArea);\n    textArea.focus();\n    textArea.select();\n    const succeeded = document.execCommand(\"copy\");\n    textArea.remove();\n    return succeeded;\n  } catch {\n    return false;\n  }\n}\n",
          "type": "registry:lib",
          "target": "lib/utils.ts"
        }
      ]
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "scrubbable-sparkline",
      "type": "registry:ui",
      "title": "Scrubbable Sparkline",
      "author": "Rishabh Bose <https://theb0se.vercel.app/>",
      "description": "Robinhood-style financial stock and cryptocurrency sparkline chart with interactive touch/mouse scrubbing, dynamic cursor crosshair, live price readout, and animated delta gains or losses.",
      "dependencies": [
        "framer-motion",
        "lucide-react",
        "clsx",
        "tailwind-merge"
      ],
      "files": [
        {
          "path": "components/ui/scrubbable-sparkline.tsx",
          "content": "\"use client\";\n\nimport React, { useState, useRef, useMemo, useCallback } from \"react\";\nimport { motion, AnimatePresence } from \"framer-motion\";\nimport {\n  TrendingUp,\n  TrendingDown,\n  Activity,\n  Maximize2,\n  RefreshCw,\n  Sparkles,\n} from \"lucide-react\";\nimport { cn } from \"@/lib/utils\";\n\nexport interface SparklinePoint {\n  time: string;\n  value: number;\n}\n\nexport interface ScrubbableSparklineProps {\n  data?: SparklinePoint[];\n  title?: string;\n  ticker?: string;\n  currency?: string;\n  height?: number;\n  showGradient?: boolean;\n  showGrid?: boolean;\n  minimal?: boolean;\n  className?: string;\n}\n\nconst PRESET_DATASETS: Record<string, { ticker: string; name: string; currency: string; points: SparklinePoint[] }> = {\n  BTC: {\n    ticker: \"BTC/USD\",\n    name: \"Bitcoin\",\n    currency: \"$\",\n    points: [\n      { time: \"09:30\", value: 64250 },\n      { time: \"10:30\", value: 64580 },\n      { time: \"11:30\", value: 64320 },\n      { time: \"12:30\", value: 65120 },\n      { time: \"13:30\", value: 64980 },\n      { time: \"14:30\", value: 65890 },\n      { time: \"15:30\", value: 66420 },\n      { time: \"16:30\", value: 66150 },\n      { time: \"17:30\", value: 67200 },\n      { time: \"18:30\", value: 67890 },\n      { time: \"19:30\", value: 67450 },\n      { time: \"20:30\", value: 68340 },\n    ],\n  },\n  ETH: {\n    ticker: \"ETH/USD\",\n    name: \"Ethereum\",\n    currency: \"$\",\n    points: [\n      { time: \"09:30\", value: 3450 },\n      { time: \"10:30\", value: 3420 },\n      { time: \"11:30\", value: 3380 },\n      { time: \"12:30\", value: 3395 },\n      { time: \"13:30\", value: 3360 },\n      { time: \"14:30\", value: 3320 },\n      { time: \"15:30\", value: 3290 },\n      { time: \"16:30\", value: 3310 },\n      { time: \"17:30\", value: 3275 },\n      { time: \"18:30\", value: 3240 },\n      { time: \"19:30\", value: 3260 },\n      { time: \"20:30\", value: 3215 },\n    ],\n  },\n  NVDA: {\n    ticker: \"NVDA\",\n    name: \"NVIDIA Corp.\",\n    currency: \"$\",\n    points: [\n      { time: \"09:30\", value: 118.5 },\n      { time: \"10:30\", value: 120.2 },\n      { time: \"11:30\", value: 119.8 },\n      { time: \"12:30\", value: 122.4 },\n      { time: \"13:30\", value: 123.9 },\n      { time: \"14:30\", value: 123.1 },\n      { time: \"15:30\", value: 125.6 },\n      { time: \"16:30\", value: 127.2 },\n      { time: \"17:30\", value: 126.8 },\n      { time: \"18:30\", value: 129.4 },\n      { time: \"19:30\", value: 130.5 },\n      { time: \"20:30\", value: 132.8 },\n    ],\n  },\n  SOL: {\n    ticker: \"SOL/USD\",\n    name: \"Solana\",\n    currency: \"$\",\n    points: [\n      { time: \"09:30\", value: 154.2 },\n      { time: \"10:30\", value: 151.8 },\n      { time: \"11:30\", value: 153.4 },\n      { time: \"12:30\", value: 156.9 },\n      { time: \"13:30\", value: 155.1 },\n      { time: \"14:30\", value: 158.7 },\n      { time: \"15:30\", value: 161.2 },\n      { time: \"16:30\", value: 159.8 },\n      { time: \"17:30\", value: 163.5 },\n      { time: \"18:30\", value: 165.2 },\n      { time: \"19:30\", value: 164.1 },\n      { time: \"20:30\", value: 168.0 },\n    ],\n  },\n};\n\nexport function ScrubbableSparkline({\n  data: initialData,\n  title = \"Bitcoin\",\n  ticker = \"BTC/USD\",\n  currency = \"$\",\n  height = 240,\n  showGradient = true,\n  showGrid = true,\n  minimal = false,\n  className,\n}: ScrubbableSparklineProps) {\n  const [selectedPresetKey, setSelectedPresetKey] = useState<string>(\"BTC\");\n  const [isLiveStreaming, setIsLiveStreaming] = useState(false);\n\n  // Active dataset\n  const activeDataset = initialData\n    ? {\n        ticker,\n        name: title,\n        currency,\n        points: initialData,\n      }\n    : PRESET_DATASETS[selectedPresetKey] || PRESET_DATASETS.BTC;\n\n  const points = activeDataset.points;\n  const svgRef = useRef<SVGSVGElement | null>(null);\n\n  // Min and max for scaling\n  const { minVal, maxVal, firstVal, lastVal } = useMemo(() => {\n    if (!points || points.length === 0) {\n      return { minVal: 0, maxVal: 100, firstVal: 0, lastVal: 0 };\n    }\n    const vals = points.map((p) => p.value);\n    const min = Math.min(...vals);\n    const max = Math.max(...vals);\n    const pad = (max - min) * 0.08 || 1;\n    return {\n      minVal: min - pad,\n      maxVal: max + pad,\n      firstVal: points[0].value,\n      lastVal: points[points.length - 1].value,\n    };\n  }, [points]);\n\n  // Scrubbing state\n  const [activeIndex, setActiveIndex] = useState<number | null>(null);\n\n  const currentPoint = activeIndex !== null ? points[activeIndex] : points[points.length - 1];\n  const currentVal = currentPoint?.value ?? lastVal;\n  const delta = currentVal - firstVal;\n  const deltaPercent = firstVal !== 0 ? (delta / firstVal) * 100 : 0;\n  const isPositive = delta >= 0;\n\n  // Viewbox metrics\n  const vbWidth = 800;\n  const vbHeight = height;\n  const paddingX = 20;\n  const paddingTop = 20;\n  const paddingBottom = 20;\n  const chartWidth = vbWidth - paddingX * 2;\n  const chartHeight = vbHeight - paddingTop - paddingBottom;\n\n  // Compute SVG coordinates\n  const coords = useMemo(() => {\n    if (points.length === 0) return [];\n    return points.map((p, i) => {\n      const x = paddingX + (i / (points.length - 1)) * chartWidth;\n      const normalizedY = (p.value - minVal) / (maxVal - minVal || 1);\n      const y = paddingTop + chartHeight - normalizedY * chartHeight;\n      return { x, y, point: p };\n    });\n  }, [points, minVal, maxVal, chartWidth, chartHeight, paddingX, paddingTop]);\n\n  // Generate smooth cubic bezier SVG path\n  const pathD = useMemo(() => {\n    if (coords.length < 2) return \"\";\n    let d = `M ${coords[0].x} ${coords[0].y}`;\n    for (let i = 0; i < coords.length - 1; i++) {\n      const p0 = coords[i === 0 ? 0 : i - 1];\n      const p1 = coords[i];\n      const p2 = coords[i + 1];\n      const p3 = coords[i + 2] || p2;\n\n      const cp1x = p1.x + (p2.x - p0.x) / 6;\n      const cp1y = p1.y + (p2.y - p0.y) / 6;\n      const cp2x = p2.x - (p3.x - p1.x) / 6;\n      const cp2y = p2.y - (p3.y - p1.y) / 6;\n\n      d += ` C ${cp1x} ${cp1y}, ${cp2x} ${cp2y}, ${p2.x} ${p2.y}`;\n    }\n    return d;\n  }, [coords]);\n\n  // Area path\n  const areaD = useMemo(() => {\n    if (coords.length < 2) return \"\";\n    const bottomY = vbHeight - paddingBottom;\n    return `${pathD} L ${coords[coords.length - 1].x} ${bottomY} L ${coords[0].x} ${bottomY} Z`;\n  }, [pathD, coords, vbHeight, paddingBottom]);\n\n  // Pointer scrub handler\n  const handlePointerMove = useCallback(\n    (e: React.PointerEvent<SVGSVGElement>) => {\n      if (!svgRef.current || coords.length === 0) return;\n      const rect = svgRef.current.getBoundingClientRect();\n      const clientX = e.clientX - rect.left;\n      const relativeX = (clientX / rect.width) * vbWidth;\n\n      // Find closest point by x coordinate\n      let closestIdx = 0;\n      let minDiff = Infinity;\n      coords.forEach((coord, idx) => {\n        const diff = Math.abs(coord.x - relativeX);\n        if (diff < minDiff) {\n          minDiff = diff;\n          closestIdx = idx;\n        }\n      });\n      setActiveIndex(closestIdx);\n    },\n    [coords, vbWidth]\n  );\n\n  const handlePointerLeave = () => {\n    setActiveIndex(null);\n  };\n\n  const activeCoord = activeIndex !== null ? coords[activeIndex] : null;\n\n  // Format currency\n  const formatPrice = (val: number) => {\n    return `${activeDataset.currency}${val.toLocaleString(\"en-US\", {\n      minimumFractionDigits: 2,\n      maximumFractionDigits: 2,\n    })}`;\n  };\n\n  if (minimal) {\n    return (\n      <div className={cn(\"relative w-full overflow-hidden select-none\", className)}>\n        <div className=\"flex items-center justify-between pb-2 text-xs\">\n          <div className=\"flex items-baseline gap-2\">\n            <span className=\"font-mono text-base font-bold text-white\">\n              {formatPrice(currentVal)}\n            </span>\n            <span\n              className={cn(\n                \"text-[10px] font-mono font-semibold\",\n                isPositive ? \"text-emerald-400\" : \"text-rose-400\"\n              )}\n            >\n              {isPositive ? \"+\" : \"\"}\n              {deltaPercent.toFixed(1)}%\n            </span>\n          </div>\n          <span className=\"font-mono text-neutral-400 text-[10px]\">\n            {activeIndex !== null ? currentPoint.time : \"Live\"}\n          </span>\n        </div>\n        <div className=\"relative select-none\">\n          <svg\n            ref={svgRef}\n            viewBox={`0 0 ${vbWidth} ${vbHeight}`}\n            className=\"w-full cursor-crosshair overflow-visible touch-none\"\n            style={{ height }}\n            onPointerMove={handlePointerMove}\n            onPointerLeave={handlePointerLeave}\n          >\n            <defs>\n              <linearGradient id=\"sparkline-emerald-grad-min\" x1=\"0\" y1=\"0\" x2=\"0\" y2=\"1\">\n                <stop offset=\"0%\" stopColor=\"#10b981\" stopOpacity=\"0.35\" />\n                <stop offset=\"70%\" stopColor=\"#10b981\" stopOpacity=\"0.05\" />\n                <stop offset=\"100%\" stopColor=\"#10b981\" stopOpacity=\"0\" />\n              </linearGradient>\n              <linearGradient id=\"sparkline-rose-grad-min\" x1=\"0\" y1=\"0\" x2=\"0\" y2=\"1\">\n                <stop offset=\"0%\" stopColor=\"#f43f5e\" stopOpacity=\"0.35\" />\n                <stop offset=\"70%\" stopColor=\"#f43f5e\" stopOpacity=\"0.05\" />\n                <stop offset=\"100%\" stopColor=\"#f43f5e\" stopOpacity=\"0\" />\n              </linearGradient>\n              <filter id=\"sparkline-glow-min\" x=\"-20%\" y=\"-20%\" width=\"140%\" height=\"140%\">\n                <feGaussianBlur stdDeviation=\"3\" result=\"blur\" />\n                <feComposite in=\"SourceGraphic\" in2=\"blur\" operator=\"over\" />\n              </filter>\n            </defs>\n            {showGrid && (\n              <g className=\"stroke-neutral-800/60 stroke-[1]\">\n                <line\n                  x1={paddingX}\n                  y1={paddingTop + chartHeight * 0.5}\n                  x2={vbWidth - paddingX}\n                  y2={paddingTop + chartHeight * 0.5}\n                  strokeDasharray=\"3 3\"\n                />\n              </g>\n            )}\n            {showGradient && areaD && (\n              <path\n                d={areaD}\n                fill={isPositive ? \"url(#sparkline-emerald-grad-min)\" : \"url(#sparkline-rose-grad-min)\"}\n              />\n            )}\n            {pathD && (\n              <path\n                d={pathD}\n                fill=\"none\"\n                stroke={isPositive ? \"#10b981\" : \"#f43f5e\"}\n                strokeWidth=\"2.5\"\n                strokeLinecap=\"round\"\n                strokeLinejoin=\"round\"\n                filter=\"url(#sparkline-glow-min)\"\n              />\n            )}\n            {activeCoord && (\n              <g>\n                <line\n                  x1={activeCoord.x}\n                  y1={paddingTop}\n                  x2={activeCoord.x}\n                  y2={vbHeight - paddingBottom}\n                  stroke=\"#737373\"\n                  strokeWidth=\"1.5\"\n                  strokeDasharray=\"4 4\"\n                  className=\"opacity-80\"\n                />\n                <circle\n                  cx={activeCoord.x}\n                  cy={activeCoord.y}\n                  r=\"7\"\n                  fill={isPositive ? \"rgba(16, 185, 129, 0.2)\" : \"rgba(244, 63, 94, 0.2)\"}\n                />\n                <circle\n                  cx={activeCoord.x}\n                  cy={activeCoord.y}\n                  r=\"3.5\"\n                  fill={isPositive ? \"#10b981\" : \"#f43f5e\"}\n                  stroke=\"#ffffff\"\n                  strokeWidth=\"1.5\"\n                />\n              </g>\n            )}\n          </svg>\n        </div>\n      </div>\n    );\n  }\n\n  return (\n    <div\n      data-fullscreen-scroll\n      className={cn(\n        \"relative w-full min-h-[520px] overflow-hidden rounded-2xl border border-neutral-200/80 bg-neutral-950 p-6 text-neutral-100 shadow-xl dark:border-neutral-800\",\n        className\n      )}\n    >\n      {/* Background radial highlight */}\n      <div\n        className={cn(\n          \"pointer-events-none absolute -top-32 left-1/2 h-96 w-96 -translate-x-1/2 rounded-full blur-[100px] transition-colors duration-700 opacity-20\",\n          isPositive ? \"bg-emerald-500\" : \"bg-rose-500\"\n        )}\n      />\n\n      {/* Header & Controls bar */}\n      <div className=\"relative z-10 flex flex-col gap-4 sm:flex-row sm:items-center sm:justify-between\">\n        <div>\n          <div className=\"flex items-center gap-2\">\n            <span className=\"font-semibold text-lg text-white\">\n              {activeDataset.name}\n            </span>\n            <span className=\"rounded-md bg-neutral-800/80 px-2 py-0.5 text-xs font-mono font-medium text-neutral-400\">\n              {activeDataset.ticker}\n            </span>\n            <div\n              className={cn(\n                \"inline-flex items-center gap-1 rounded-full px-2 py-0.5 text-xs font-semibold tracking-wide\",\n                isPositive\n                  ? \"bg-emerald-500/10 text-emerald-400 border border-emerald-500/20\"\n                  : \"bg-rose-500/10 text-rose-400 border border-rose-500/20\"\n              )}\n            >\n              {isPositive ? (\n                <TrendingUp className=\"h-3 w-3\" />\n              ) : (\n                <TrendingDown className=\"h-3 w-3\" />\n              )}\n              <span>\n                {isPositive ? \"+\" : \"\"}\n                {deltaPercent.toFixed(2)}%\n              </span>\n            </div>\n          </div>\n\n          {/* Large Live Ticker Readout */}\n          <div className=\"mt-2 flex items-baseline gap-3\">\n            <motion.h2\n              key={currentVal}\n              initial={{ opacity: 0.8, y: -2 }}\n              animate={{ opacity: 1, y: 0 }}\n              className=\"text-4xl font-extrabold tracking-tight font-mono text-white\"\n            >\n              {formatPrice(currentVal)}\n            </motion.h2>\n            <span className=\"text-sm font-medium text-neutral-400\">\n              {activeIndex !== null ? `at ${currentPoint.time}` : \"Live Market\"}\n            </span>\n          </div>\n        </div>\n\n        {/* Preset Selector Buttons */}\n        <div className=\"flex flex-wrap items-center gap-1.5 rounded-xl border border-neutral-800 bg-neutral-900/90 p-1 backdrop-blur-md\">\n          {Object.keys(PRESET_DATASETS).map((key) => {\n            const isSelected = selectedPresetKey === key;\n            return (\n              <button\n                key={key}\n                type=\"button\"\n                onClick={() => {\n                  setSelectedPresetKey(key);\n                  setActiveIndex(null);\n                }}\n                className={cn(\n                  \"relative rounded-lg px-3 py-1.5 text-xs font-medium transition-all duration-200\",\n                  isSelected\n                    ? \"text-white font-semibold shadow-sm\"\n                    : \"text-neutral-400 hover:text-neutral-200 hover:bg-neutral-800/50\"\n                )}\n              >\n                {isSelected && (\n                  <motion.div\n                    layoutId=\"sparkline-asset-pill\"\n                    className=\"absolute inset-0 rounded-lg bg-neutral-800\"\n                    transition={{ type: \"spring\", stiffness: 380, damping: 30 }}\n                  />\n                )}\n                <span className=\"relative z-10\">{key}</span>\n              </button>\n            );\n          })}\n        </div>\n      </div>\n\n      {/* Main Sparkline Stage */}\n      <div className=\"relative mt-8 select-none\">\n        <svg\n          ref={svgRef}\n          viewBox={`0 0 ${vbWidth} ${vbHeight}`}\n          className=\"w-full cursor-crosshair overflow-visible touch-none\"\n          onPointerMove={handlePointerMove}\n          onPointerLeave={handlePointerLeave}\n        >\n          <defs>\n            {/* Emerald Gradient */}\n            <linearGradient id=\"sparkline-emerald-grad\" x1=\"0\" y1=\"0\" x2=\"0\" y2=\"1\">\n              <stop offset=\"0%\" stopColor=\"#10b981\" stopOpacity=\"0.35\" />\n              <stop offset=\"70%\" stopColor=\"#10b981\" stopOpacity=\"0.05\" />\n              <stop offset=\"100%\" stopColor=\"#10b981\" stopOpacity=\"0\" />\n            </linearGradient>\n\n            {/* Rose Gradient */}\n            <linearGradient id=\"sparkline-rose-grad\" x1=\"0\" y1=\"0\" x2=\"0\" y2=\"1\">\n              <stop offset=\"0%\" stopColor=\"#f43f5e\" stopOpacity=\"0.35\" />\n              <stop offset=\"70%\" stopColor=\"#f43f5e\" stopOpacity=\"0.05\" />\n              <stop offset=\"100%\" stopColor=\"#f43f5e\" stopOpacity=\"0\" />\n            </linearGradient>\n\n            {/* Glow Filter */}\n            <filter id=\"sparkline-glow\" x=\"-20%\" y=\"-20%\" width=\"140%\" height=\"140%\">\n              <feGaussianBlur stdDeviation=\"3\" result=\"blur\" />\n              <feComposite in=\"SourceGraphic\" in2=\"blur\" operator=\"over\" />\n            </filter>\n          </defs>\n\n          {/* Horizontal Grid lines */}\n          {showGrid && (\n            <g className=\"stroke-neutral-800/60 stroke-[1] stroke-dasharray-4\">\n              <line x1={paddingX} y1={paddingTop + chartHeight * 0.25} x2={vbWidth - paddingX} y2={paddingTop + chartHeight * 0.25} strokeDasharray=\"3 3\" />\n              <line x1={paddingX} y1={paddingTop + chartHeight * 0.5} x2={vbWidth - paddingX} y2={paddingTop + chartHeight * 0.5} strokeDasharray=\"3 3\" />\n              <line x1={paddingX} y1={paddingTop + chartHeight * 0.75} x2={vbWidth - paddingX} y2={paddingTop + chartHeight * 0.75} strokeDasharray=\"3 3\" />\n            </g>\n          )}\n\n          {/* Area Fill */}\n          {showGradient && areaD && (\n            <motion.path\n              d={areaD}\n              fill={isPositive ? \"url(#sparkline-emerald-grad)\" : \"url(#sparkline-rose-grad)\"}\n              initial={{ opacity: 0 }}\n              animate={{ opacity: 1 }}\n              transition={{ duration: 0.5 }}\n            />\n          )}\n\n          {/* Main Sparkline Stroke */}\n          {pathD && (\n            <motion.path\n              d={pathD}\n              fill=\"none\"\n              stroke={isPositive ? \"#10b981\" : \"#f43f5e\"}\n              strokeWidth=\"2.5\"\n              strokeLinecap=\"round\"\n              strokeLinejoin=\"round\"\n              filter=\"url(#sparkline-glow)\"\n              initial={{ pathLength: 0 }}\n              animate={{ pathLength: 1 }}\n              transition={{ duration: 0.8, ease: \"easeOut\" }}\n            />\n          )}\n\n          {/* Scrub Vertical Crosshair Cursor */}\n          {activeCoord && (\n            <g>\n              <line\n                x1={activeCoord.x}\n                y1={paddingTop}\n                x2={activeCoord.x}\n                y2={vbHeight - paddingBottom}\n                stroke=\"#737373\"\n                strokeWidth=\"1.5\"\n                strokeDasharray=\"4 4\"\n                className=\"opacity-80\"\n              />\n              {/* Outer pulsing ring */}\n              <circle\n                cx={activeCoord.x}\n                cy={activeCoord.y}\n                r=\"9\"\n                fill={isPositive ? \"rgba(16, 185, 129, 0.2)\" : \"rgba(244, 63, 94, 0.2)\"}\n              />\n              {/* Core indicator dot */}\n              <circle\n                cx={activeCoord.x}\n                cy={activeCoord.y}\n                r=\"4.5\"\n                fill={isPositive ? \"#10b981\" : \"#f43f5e\"}\n                stroke=\"#ffffff\"\n                strokeWidth=\"2\"\n              />\n            </g>\n          )}\n        </svg>\n\n        {/* Scrub tooltip badge */}\n        <AnimatePresence>\n          {activeCoord && (\n            <motion.div\n              initial={{ opacity: 0, y: 10, scale: 0.95 }}\n              animate={{ opacity: 1, y: 0, scale: 1 }}\n              exit={{ opacity: 0, scale: 0.9 }}\n              transition={{ duration: 0.15 }}\n              style={{\n                left: `${(activeCoord.x / vbWidth) * 100}%`,\n                top: `${(activeCoord.y / vbHeight) * 100}%`,\n              }}\n              className=\"pointer-events-none absolute -translate-x-1/2 -translate-y-12 z-20 whitespace-nowrap rounded-lg border border-neutral-700 bg-neutral-900/95 px-2.5 py-1 text-xs shadow-xl backdrop-blur-md\"\n            >\n              <span className=\"font-mono font-semibold text-white\">\n                {formatPrice(activeCoord.point.value)}\n              </span>\n              <span className=\"ml-1.5 text-[10px] text-neutral-400\">\n                {activeCoord.point.time}\n              </span>\n            </motion.div>\n          )}\n        </AnimatePresence>\n      </div>\n    </div>\n  );\n}\n\nexport default ScrubbableSparkline;\n",
          "type": "registry:ui",
          "target": "components/ui/scrubbable-sparkline.tsx"
        },
        {
          "path": "lib/utils.ts",
          "content": "import { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...inputs: ClassValue[]) {\n  return twMerge(clsx(inputs));\n}\n\nexport async function copyToClipboard(text: string): Promise<boolean> {\n  if (typeof window === \"undefined\") return false;\n\n  try {\n    if (navigator.clipboard && window.isSecureContext) {\n      await navigator.clipboard.writeText(text);\n      return true;\n    }\n\n    const textArea = document.createElement(\"textarea\");\n    textArea.value = text;\n    textArea.style.position = \"fixed\";\n    textArea.style.left = \"-999999px\";\n    textArea.style.top = \"-999999px\";\n    document.body.appendChild(textArea);\n    textArea.focus();\n    textArea.select();\n    const succeeded = document.execCommand(\"copy\");\n    textArea.remove();\n    return succeeded;\n  } catch {\n    return false;\n  }\n}\n",
          "type": "registry:lib",
          "target": "lib/utils.ts"
        }
      ]
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "segmented-range-picker",
      "type": "registry:ui",
      "title": "Segmented Range Picker",
      "author": "Rishabh Bose <https://theb0se.vercel.app/>",
      "description": "Financial timeframe range selector (1D, 1W, 1M, 1Y, ALL) with a sliding pill highlight, synchronized animated chart transitions, interval resolution badge, and high/low metric cards.",
      "dependencies": [
        "framer-motion",
        "lucide-react",
        "clsx",
        "tailwind-merge"
      ],
      "files": [
        {
          "path": "components/ui/segmented-range-picker.tsx",
          "content": "\"use client\";\n\nimport React, { useState, useId } from \"react\";\nimport { motion, AnimatePresence } from \"framer-motion\";\nimport {\n  Calendar,\n  BarChart2,\n  LineChart,\n  ArrowUpRight,\n  ArrowDownRight,\n  Clock,\n  Layers,\n} from \"lucide-react\";\nimport { cn } from \"@/lib/utils\";\n\nexport type TimeRange = \"1D\" | \"1W\" | \"1M\" | \"1Y\" | \"ALL\";\n\nexport interface RangeDataConfig {\n  label: TimeRange;\n  resolution: string;\n  price: string;\n  change: string;\n  isPositive: boolean;\n  high: string;\n  low: string;\n  volume: string;\n  points: number[];\n}\n\nconst DEFAULT_RANGE_DATA: Record<TimeRange, RangeDataConfig> = {\n  \"1D\": {\n    label: \"1D\",\n    resolution: \"5m interval\",\n    price: \"$68,420.50\",\n    change: \"+2.45%\",\n    isPositive: true,\n    high: \"$68,910.00\",\n    low: \"$66,780.00\",\n    volume: \"$24.8B\",\n    points: [40, 42, 38, 55, 62, 58, 70, 75, 72, 85, 82, 90],\n  },\n  \"1W\": {\n    label: \"1W\",\n    resolution: \"1h interval\",\n    price: \"$68,420.50\",\n    change: \"-1.18%\",\n    isPositive: false,\n    high: \"$70,120.00\",\n    low: \"$65,240.00\",\n    volume: \"$168.2B\",\n    points: [85, 80, 75, 78, 65, 60, 58, 62, 70, 68, 72, 65],\n  },\n  \"1M\": {\n    label: \"1M\",\n    resolution: \"4h interval\",\n    price: \"$68,420.50\",\n    change: \"+14.32%\",\n    isPositive: true,\n    high: \"$69,500.00\",\n    low: \"$58,900.00\",\n    volume: \"$720.5B\",\n    points: [30, 35, 42, 40, 48, 55, 62, 59, 72, 78, 85, 92],\n  },\n  \"1Y\": {\n    label: \"1Y\",\n    resolution: \"1D interval\",\n    price: \"$68,420.50\",\n    change: \"+108.64%\",\n    isPositive: true,\n    high: \"$73,750.00\",\n    low: \"$28,400.00\",\n    volume: \"$8.4T\",\n    points: [20, 25, 30, 45, 52, 60, 58, 75, 82, 88, 95, 98],\n  },\n  ALL: {\n    label: \"ALL\",\n    resolution: \"1W interval\",\n    price: \"$68,420.50\",\n    change: \"+4,820.10%\",\n    isPositive: true,\n    high: \"$73,750.00\",\n    low: \"$120.00\",\n    volume: \"$34.2T\",\n    points: [5, 8, 12, 18, 28, 45, 60, 50, 70, 85, 92, 100],\n  },\n};\n\nexport interface SegmentedRangePickerProps {\n  ranges?: TimeRange[];\n  defaultRange?: TimeRange;\n  onRangeChange?: (range: TimeRange) => void;\n  className?: string;\n}\n\nexport function SegmentedRangePicker({\n  ranges = [\"1D\", \"1W\", \"1M\", \"1Y\", \"ALL\"],\n  defaultRange = \"1D\",\n  onRangeChange,\n  className,\n}: SegmentedRangePickerProps) {\n  const [selectedRange, setSelectedRange] = useState<TimeRange>(defaultRange);\n  const [chartMode, setChartMode] = useState<\"line\" | \"bars\">(\"line\");\n  const uniquePillId = useId();\n\n  const activeData = DEFAULT_RANGE_DATA[selectedRange] || DEFAULT_RANGE_DATA[\"1D\"];\n\n  const handleSelect = (r: TimeRange) => {\n    setSelectedRange(r);\n    onRangeChange?.(r);\n  };\n\n  // Compute SVG line points\n  const svgWidth = 600;\n  const svgHeight = 160;\n  const padX = 16;\n  const padY = 20;\n  const w = svgWidth - padX * 2;\n  const h = svgHeight - padY * 2;\n\n  const minPt = Math.min(...activeData.points);\n  const maxPt = Math.max(...activeData.points);\n\n  const coords = activeData.points.map((pt, i) => {\n    const x = padX + (i / (activeData.points.length - 1)) * w;\n    const y = padY + h - ((pt - minPt) / (maxPt - minPt || 1)) * h;\n    return { x, y };\n  });\n\n  const linePath = coords.reduce((acc, curr, i) => {\n    return i === 0 ? `M ${curr.x} ${curr.y}` : `${acc} L ${curr.x} ${curr.y}`;\n  }, \"\");\n\n  const areaPath =\n    coords.length > 0\n      ? `${linePath} L ${coords[coords.length - 1].x} ${svgHeight} L ${coords[0].x} ${svgHeight} Z`\n      : \"\";\n\n  return (\n    <div\n      data-fullscreen-scroll\n      className={cn(\n        \"relative w-full min-h-[520px] overflow-hidden rounded-2xl border border-neutral-200/80 bg-neutral-950 p-6 text-neutral-100 shadow-xl dark:border-neutral-800 flex flex-col justify-between\",\n        className\n      )}\n    >\n      {/* Background ambient lighting */}\n      <div\n        className={cn(\n          \"pointer-events-none absolute -top-32 right-1/4 h-80 w-80 rounded-full blur-[110px] transition-colors duration-700 opacity-20\",\n          activeData.isPositive ? \"bg-emerald-500\" : \"bg-rose-500\"\n        )}\n      />\n\n      {/* Header Bar */}\n      <div className=\"relative z-10 flex flex-col sm:flex-row items-start sm:items-center justify-between gap-4\">\n        <div>\n          <div className=\"flex items-center gap-2\">\n            <span className=\"font-semibold text-base text-white\">BTC/USD Market Overview</span>\n            <div\n              className={cn(\n                \"inline-flex items-center gap-1 rounded-full px-2 py-0.5 text-xs font-semibold\",\n                activeData.isPositive\n                  ? \"bg-emerald-500/10 text-emerald-400 border border-emerald-500/20\"\n                  : \"bg-rose-500/10 text-rose-400 border border-rose-500/20\"\n              )}\n            >\n              {activeData.isPositive ? (\n                <ArrowUpRight className=\"h-3 w-3\" />\n              ) : (\n                <ArrowDownRight className=\"h-3 w-3\" />\n              )}\n              <span>{activeData.change}</span>\n            </div>\n          </div>\n          <div className=\"mt-1 flex items-baseline gap-2\">\n            <span className=\"font-mono text-3xl font-extrabold text-white\">\n              {activeData.price}\n            </span>\n            <span className=\"text-xs text-neutral-400 flex items-center gap-1\">\n              <Clock className=\"h-3 w-3\" /> {activeData.resolution}\n            </span>\n          </div>\n        </div>\n\n        {/* Sliding Segmented Range Picker Pills */}\n        <div className=\"flex items-center rounded-xl border border-neutral-800 bg-neutral-900/90 p-1 backdrop-blur-md\">\n          {ranges.map((r) => {\n            const isSelected = selectedRange === r;\n            return (\n              <button\n                key={r}\n                type=\"button\"\n                onClick={() => handleSelect(r)}\n                className={cn(\n                  \"relative rounded-lg px-3.5 py-1.5 text-xs font-semibold font-mono transition-colors duration-200\",\n                  isSelected\n                    ? \"text-white\"\n                    : \"text-neutral-400 hover:text-neutral-200 hover:bg-neutral-800/40\"\n                )}\n              >\n                {isSelected && (\n                  <motion.div\n                    layoutId={`segmented-pill-${uniquePillId}`}\n                    className=\"absolute inset-0 rounded-lg bg-neutral-800 shadow-sm border border-neutral-700/60\"\n                    transition={{ type: \"spring\", stiffness: 420, damping: 32 }}\n                  />\n                )}\n                <span className=\"relative z-10\">{r}</span>\n              </button>\n            );\n          })}\n        </div>\n      </div>\n\n      {/* Main Animated Chart Transition Canvas */}\n      <div className=\"relative my-8 select-none\">\n        <AnimatePresence mode=\"wait\">\n          <motion.div\n            key={selectedRange + chartMode}\n            initial={{ opacity: 0, scale: 0.98 }}\n            animate={{ opacity: 1, scale: 1 }}\n            exit={{ opacity: 0, scale: 0.98 }}\n            transition={{ duration: 0.25, ease: \"easeOut\" }}\n            className=\"w-full\"\n          >\n            {chartMode === \"line\" ? (\n              <svg\n                viewBox={`0 0 ${svgWidth} ${svgHeight}`}\n                className=\"w-full h-44 overflow-visible\"\n              >\n                <defs>\n                  <linearGradient\n                    id={`range-grad-${uniquePillId}`}\n                    x1=\"0\"\n                    y1=\"0\"\n                    x2=\"0\"\n                    y2=\"1\"\n                  >\n                    <stop\n                      offset=\"0%\"\n                      stopColor={activeData.isPositive ? \"#10b981\" : \"#f43f5e\"}\n                      stopOpacity=\"0.3\"\n                    />\n                    <stop\n                      offset=\"100%\"\n                      stopColor={activeData.isPositive ? \"#10b981\" : \"#f43f5e\"}\n                      stopOpacity=\"0\"\n                    />\n                  </linearGradient>\n                </defs>\n\n                {/* Subtle horizontal grid lines */}\n                <line\n                  x1={padX}\n                  y1={padY + h * 0.3}\n                  x2={svgWidth - padX}\n                  y2={padY + h * 0.3}\n                  stroke=\"#262626\"\n                  strokeDasharray=\"4 4\"\n                />\n                <line\n                  x1={padX}\n                  y1={padY + h * 0.7}\n                  x2={svgWidth - padX}\n                  y2={padY + h * 0.7}\n                  stroke=\"#262626\"\n                  strokeDasharray=\"4 4\"\n                />\n\n                {/* Area Gradient */}\n                {areaPath && (\n                  <path\n                    d={areaPath}\n                    fill={`url(#range-grad-${uniquePillId})`}\n                  />\n                )}\n\n                {/* Main Stroke */}\n                {linePath && (\n                  <path\n                    d={linePath}\n                    fill=\"none\"\n                    stroke={activeData.isPositive ? \"#10b981\" : \"#f43f5e\"}\n                    strokeWidth=\"2.5\"\n                    strokeLinecap=\"round\"\n                    strokeLinejoin=\"round\"\n                  />\n                )}\n\n                {/* Data Points */}\n                {coords.map((c, i) => (\n                  <circle\n                    key={i}\n                    cx={c.x}\n                    cy={c.y}\n                    r=\"3.5\"\n                    fill=\"#0a0a0a\"\n                    stroke={activeData.isPositive ? \"#10b981\" : \"#f43f5e\"}\n                    strokeWidth=\"2\"\n                  />\n                ))}\n              </svg>\n            ) : (\n              /* Bar Histogram View */\n              <div className=\"flex h-44 items-end justify-between gap-2 px-4 pb-2\">\n                {activeData.points.map((pt, i) => {\n                  const normalized = ((pt - minPt) / (maxPt - minPt || 1)) * 100;\n                  return (\n                    <div\n                      key={i}\n                      className=\"flex-1 flex flex-col items-center gap-1\"\n                    >\n                      <motion.div\n                        initial={{ height: 0 }}\n                        animate={{ height: `${Math.max(12, normalized)}%` }}\n                        transition={{ duration: 0.3, delay: i * 0.02 }}\n                        className={cn(\n                          \"w-full rounded-t-sm transition-colors\",\n                          activeData.isPositive\n                            ? \"bg-emerald-500/80 hover:bg-emerald-400\"\n                            : \"bg-rose-500/80 hover:bg-rose-400\"\n                        )}\n                      />\n                    </div>\n                  );\n                })}\n              </div>\n            )}\n          </motion.div>\n        </AnimatePresence>\n\n        {/* Financial Stat Cards */}\n        <div className=\"mt-4 grid grid-cols-2 sm:grid-cols-4 gap-3\">\n          <div className=\"rounded-xl border border-neutral-800 bg-neutral-900/60 p-3\">\n            <span className=\"text-[10px] uppercase font-mono text-neutral-500 block\">\n              Range High\n            </span>\n            <span className=\"font-mono text-sm font-semibold text-neutral-200\">\n              {activeData.high}\n            </span>\n          </div>\n          <div className=\"rounded-xl border border-neutral-800 bg-neutral-900/60 p-3\">\n            <span className=\"text-[10px] uppercase font-mono text-neutral-500 block\">\n              Range Low\n            </span>\n            <span className=\"font-mono text-sm font-semibold text-neutral-200\">\n              {activeData.low}\n            </span>\n          </div>\n          <div className=\"rounded-xl border border-neutral-800 bg-neutral-900/60 p-3\">\n            <span className=\"text-[10px] uppercase font-mono text-neutral-500 block\">\n              Volume ({selectedRange})\n            </span>\n            <span className=\"font-mono text-sm font-semibold text-neutral-200\">\n              {activeData.volume}\n            </span>\n          </div>\n          <div className=\"rounded-xl border border-neutral-800 bg-neutral-900/60 p-3\">\n            <span className=\"text-[10px] uppercase font-mono text-neutral-500 block\">\n              Time Interval\n            </span>\n            <span className=\"font-mono text-sm font-semibold text-neutral-200\">\n              {activeData.resolution}\n            </span>\n          </div>\n        </div>\n      </div>\n\n      {/* Footer Controls Bar */}\n      <div className=\"relative z-10 flex flex-wrap items-center justify-between gap-3 border-t border-neutral-800/80 pt-4 text-xs text-neutral-400\">\n        <div className=\"flex items-center gap-2\">\n          <button\n            type=\"button\"\n            onClick={() => setChartMode(\"line\")}\n            className={cn(\n              \"flex items-center gap-1.5 rounded-lg px-2.5 py-1 text-xs font-medium transition-colors\",\n              chartMode === \"line\"\n                ? \"bg-neutral-800 text-white font-semibold\"\n                : \"text-neutral-400 hover:text-neutral-200\"\n            )}\n          >\n            <LineChart className=\"h-3.5 w-3.5\" />\n            <span>Line Curve</span>\n          </button>\n          <button\n            type=\"button\"\n            onClick={() => setChartMode(\"bars\")}\n            className={cn(\n              \"flex items-center gap-1.5 rounded-lg px-2.5 py-1 text-xs font-medium transition-colors\",\n              chartMode === \"bars\"\n                ? \"bg-neutral-800 text-white font-semibold\"\n                : \"text-neutral-400 hover:text-neutral-200\"\n            )}\n          >\n            <BarChart2 className=\"h-3.5 w-3.5\" />\n            <span>Volume Bars</span>\n          </button>\n        </div>\n\n        <div className=\"flex items-center gap-2 font-mono text-[11px] text-neutral-500\">\n          <Layers className=\"h-3.5 w-3.5\" />\n          <span>Active Window: {selectedRange}</span>\n        </div>\n      </div>\n    </div>\n  );\n}\n\nexport default SegmentedRangePicker;\n",
          "type": "registry:ui",
          "target": "components/ui/segmented-range-picker.tsx"
        },
        {
          "path": "lib/utils.ts",
          "content": "import { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...inputs: ClassValue[]) {\n  return twMerge(clsx(inputs));\n}\n\nexport async function copyToClipboard(text: string): Promise<boolean> {\n  if (typeof window === \"undefined\") return false;\n\n  try {\n    if (navigator.clipboard && window.isSecureContext) {\n      await navigator.clipboard.writeText(text);\n      return true;\n    }\n\n    const textArea = document.createElement(\"textarea\");\n    textArea.value = text;\n    textArea.style.position = \"fixed\";\n    textArea.style.left = \"-999999px\";\n    textArea.style.top = \"-999999px\";\n    document.body.appendChild(textArea);\n    textArea.focus();\n    textArea.select();\n    const succeeded = document.execCommand(\"copy\");\n    textArea.remove();\n    return succeeded;\n  } catch {\n    return false;\n  }\n}\n",
          "type": "registry:lib",
          "target": "lib/utils.ts"
        }
      ]
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "shimmer-text",
      "type": "registry:ui",
      "title": "Shimmer Text",
      "author": "Rishabh Bose <https://theb0se.vercel.app/>",
      "description": "Linear-inspired metallic gradient typography with a high-gloss light beam that sweeps across headlines continuously or upon hover interaction.",
      "dependencies": [
        "framer-motion",
        "lucide-react",
        "clsx",
        "tailwind-merge"
      ],
      "files": [
        {
          "path": "components/ui/shimmer-text.tsx",
          "content": "\"use client\";\n\nimport React, { useState } from \"react\";\nimport { motion, useReducedMotion } from \"framer-motion\";\nimport {\n  Sparkles,\n  Play,\n  Pause,\n  RotateCcw,\n  Sliders,\n  Type,\n  Eye,\n  Check,\n  Copy,\n} from \"lucide-react\";\nimport { cn } from \"@/lib/utils\";\n\nexport type ShimmerPalette = \"silver\" | \"gold\" | \"violet\" | \"emerald\";\n\nexport interface ShimmerTextProps {\n  text?: string;\n  palette?: ShimmerPalette;\n  duration?: number;\n  angle?: number;\n  shimmerOnHoverOnly?: boolean;\n  className?: string;\n}\n\nconst PALETTES: Record<\n  ShimmerPalette,\n  {\n    name: string;\n    textGradient: string;\n    shimmerGlow: string;\n    border: string;\n    badgeBg: string;\n    badgeText: string;\n    beamGradient: string;\n  }\n> = {\n  silver: {\n    name: \"Platinum Silver\",\n    textGradient:\n      \"linear-gradient(180deg, #FFFFFF 0%, #E2E8F0 45%, #94A3B8 100%)\",\n    shimmerGlow: \"rgba(255, 255, 255, 0.4)\",\n    border: \"border-slate-700/60\",\n    badgeBg: \"bg-slate-800/80\",\n    badgeText: \"text-slate-200\",\n    beamGradient:\n      \"linear-gradient(90deg, rgba(255,255,255,0) 0%, rgba(255,255,255,0.95) 50%, rgba(255,255,255,0) 100%)\",\n  },\n  gold: {\n    name: \"Liquid Gold\",\n    textGradient:\n      \"linear-gradient(180deg, #FFFBEB 0%, #FDE68A 40%, #D97706 100%)\",\n    shimmerGlow: \"rgba(251, 191, 36, 0.45)\",\n    border: \"border-amber-700/60\",\n    badgeBg: \"bg-amber-950/60\",\n    badgeText: \"text-amber-300\",\n    beamGradient:\n      \"linear-gradient(90deg, rgba(254,243,199,0) 0%, rgba(254,240,138,0.95) 50%, rgba(254,243,199,0) 100%)\",\n  },\n  violet: {\n    name: \"Cyber Neon\",\n    textGradient:\n      \"linear-gradient(180deg, #FAF5FF 0%, #D8B4FE 45%, #9333EA 100%)\",\n    shimmerGlow: \"rgba(168, 85, 247, 0.45)\",\n    border: \"border-purple-700/60\",\n    badgeBg: \"bg-purple-950/60\",\n    badgeText: \"text-purple-300\",\n    beamGradient:\n      \"linear-gradient(90deg, rgba(243,232,255,0) 0%, rgba(216,180,254,0.95) 50%, rgba(243,232,255,0) 100%)\",\n  },\n  emerald: {\n    name: \"Matrix Emerald\",\n    textGradient:\n      \"linear-gradient(180deg, #ECFDF5 0%, #6EE7B7 45%, #059669 100%)\",\n    shimmerGlow: \"rgba(52, 211, 153, 0.45)\",\n    border: \"border-emerald-700/60\",\n    badgeBg: \"bg-emerald-950/60\",\n    badgeText: \"text-emerald-300\",\n    beamGradient:\n      \"linear-gradient(90deg, rgba(209,250,229,0) 0%, rgba(110,231,183,0.95) 50%, rgba(209,250,229,0) 100%)\",\n  },\n};\n\nconst DEFAULT_HEADLINE =\n  \"Linear issue tracking engineered for high-velocity software teams.\";\n\nexport function ShimmerText({\n  text = DEFAULT_HEADLINE,\n  palette = \"silver\",\n  duration = 3,\n  angle = 115,\n  shimmerOnHoverOnly = false,\n  className,\n}: ShimmerTextProps) {\n  const shouldReduceMotion = useReducedMotion() ?? false;\n  const [headline, setHeadline] = useState(text);\n  const [activePalette, setActivePalette] = useState<ShimmerPalette>(palette);\n  const [speed, setSpeed] = useState(duration);\n  const [beamAngle, setBeamAngle] = useState(angle);\n  const [hoverOnly, setHoverOnly] = useState(shimmerOnHoverOnly);\n  const [isPlaying, setIsPlaying] = useState(true);\n  const [isHovered, setIsHovered] = useState(false);\n  const [copied, setCopied] = useState(false);\n  const [fontSize, setFontSize] = useState<\"md\" | \"lg\" | \"xl\">(\"lg\");\n\n  const currentTheme = PALETTES[activePalette];\n  const activeAnimation = !shouldReduceMotion && isPlaying && (!hoverOnly || isHovered);\n\n  const handleCopy = () => {\n    navigator.clipboard?.writeText(headline);\n    setCopied(true);\n    setTimeout(() => setCopied(false), 2000);\n  };\n\n  return (\n    <div\n      data-fullscreen-scroll\n      className={cn(\n        \"relative w-full min-h-[520px] overflow-hidden rounded-2xl border border-neutral-800 bg-[#08090D] p-6 text-white shadow-2xl flex flex-col justify-between selection:bg-purple-500/30\",\n        className\n      )}\n    >\n      {/* Background ambient radial aura */}\n      <div\n        className=\"pointer-events-none absolute inset-0 opacity-25 blur-3xl transition-all duration-700\"\n        style={{\n          background: `radial-gradient(circle at 50% 40%, ${currentTheme.shimmerGlow} 0%, transparent 60%)`,\n        }}\n      />\n\n      {/* Control Header */}\n      <div className=\"relative z-10 flex flex-wrap items-center justify-between gap-4 border-b border-neutral-800/80 pb-4\">\n        <div className=\"flex items-center gap-2.5\">\n          <div className=\"flex h-8 w-8 items-center justify-center rounded-lg border border-neutral-700 bg-neutral-900 font-mono text-xs font-bold text-neutral-200\">\n            <Sparkles className=\"h-4 w-4 text-neutral-300\" />\n          </div>\n          <div>\n            <h3 className=\"text-sm font-semibold tracking-tight text-white flex items-center gap-2\">\n              Specular Shimmer Text\n              <span\n                className={cn(\n                  \"text-[10px] uppercase font-mono px-2 py-0.5 rounded-full border\",\n                  currentTheme.border,\n                  currentTheme.badgeBg,\n                  currentTheme.badgeText\n                )}\n              >\n                {currentTheme.name}\n              </span>\n            </h3>\n            <p className=\"text-xs text-neutral-400 font-mono\">\n              Linear-grade metallic typography with high-gloss beam refraction\n            </p>\n          </div>\n        </div>\n\n        {/* Palette selector & Controls */}\n        <div className=\"flex flex-wrap items-center gap-2\">\n          <div className=\"flex items-center rounded-lg border border-neutral-800 bg-neutral-900/90 p-1\">\n            {([\"silver\", \"gold\", \"violet\", \"emerald\"] as const).map((p) => (\n              <button\n                key={p}\n                onClick={() => setActivePalette(p)}\n                className={cn(\n                  \"px-2.5 py-1 text-[11px] font-mono rounded capitalize transition-all\",\n                  activePalette === p\n                    ? \"bg-neutral-800 text-white font-bold shadow-sm\"\n                    : \"text-neutral-400 hover:text-neutral-200\"\n                )}\n              >\n                {p}\n              </button>\n            ))}\n          </div>\n\n          {/* Size picker */}\n          <div className=\"flex items-center rounded-lg border border-neutral-800 bg-neutral-900/90 p-1 font-mono text-[10px]\">\n            {([\"md\", \"lg\", \"xl\"] as const).map((s) => (\n              <button\n                key={s}\n                onClick={() => setFontSize(s)}\n                className={cn(\n                  \"px-2 py-1 rounded uppercase transition-all\",\n                  fontSize === s\n                    ? \"bg-neutral-800 text-white font-bold\"\n                    : \"text-neutral-400 hover:text-neutral-200\"\n                )}\n              >\n                {s}\n              </button>\n            ))}\n          </div>\n\n          {/* Play / Pause toggle */}\n          <button\n            onClick={() => setIsPlaying(!isPlaying)}\n            aria-label={isPlaying ? \"Pause Shimmer\" : \"Play Shimmer\"}\n            className=\"flex items-center gap-1 px-2.5 py-1 text-xs font-mono rounded-lg border border-neutral-800 bg-neutral-900 text-neutral-300 hover:text-white transition-colors\"\n          >\n            {isPlaying ? <Pause className=\"h-3 w-3\" /> : <Play className=\"h-3 w-3\" />}\n            <span>{isPlaying ? \"Pause\" : \"Play\"}</span>\n          </button>\n        </div>\n      </div>\n\n      {/* Main Display Area */}\n      <div\n        onMouseEnter={() => setIsHovered(true)}\n        onMouseLeave={() => setIsHovered(false)}\n        className=\"relative my-auto flex flex-col items-center justify-center py-12 px-4 text-center cursor-default select-none\"\n      >\n        {/* Release Pill Badge */}\n        <div\n          className={cn(\n            \"mb-6 inline-flex items-center gap-2 rounded-full border px-3 py-1 font-mono text-[11px] font-medium backdrop-blur-md transition-all\",\n            currentTheme.border,\n            currentTheme.badgeBg,\n            currentTheme.badgeText\n          )}\n        >\n          <span className=\"relative flex h-2 w-2\">\n            <span className=\"absolute inline-flex h-full w-full animate-ping rounded-full bg-current opacity-75\" />\n            <span className=\"relative inline-flex h-2 w-2 rounded-full bg-current\" />\n          </span>\n          <span>LINEAR 2.0 PROTOCOL // RELEASE REFS</span>\n        </div>\n\n        {/* Shimmering Headline Container */}\n        <div className=\"relative inline-block max-w-3xl\">\n          {/* Base metallic gradient text */}\n          <h1\n            className={cn(\n              \"font-bold tracking-tight leading-[1.15] transition-all\",\n              fontSize === \"md\" && \"text-2xl md:text-3xl\",\n              fontSize === \"lg\" && \"text-3xl md:text-5xl\",\n              fontSize === \"xl\" && \"text-4xl md:text-6xl\"\n            )}\n            style={{\n              backgroundImage: currentTheme.textGradient,\n              WebkitBackgroundClip: \"text\",\n              WebkitTextFillColor: \"transparent\",\n            }}\n          >\n            {headline}\n          </h1>\n\n          {/* Sweeping specular light beam overlay via mask and absolute clone */}\n          {activeAnimation && (\n            <motion.div\n              aria-hidden=\"true\"\n              className={cn(\n                \"pointer-events-none absolute inset-0 font-bold tracking-tight leading-[1.15]\",\n                fontSize === \"md\" && \"text-2xl md:text-3xl\",\n                fontSize === \"lg\" && \"text-3xl md:text-5xl\",\n                fontSize === \"xl\" && \"text-4xl md:text-6xl\"\n              )}\n              initial={{\n                maskPosition: \"-200% 0%\",\n                WebkitMaskPosition: \"-200% 0%\",\n              }}\n              animate={{\n                maskPosition: [\"-100% 0%\", \"200% 0%\"],\n                WebkitMaskPosition: [\"-100% 0%\", \"200% 0%\"],\n              }}\n              transition={{\n                repeat: Infinity,\n                duration: speed,\n                ease: \"easeInOut\",\n                repeatDelay: 0.5,\n              }}\n              style={{\n                background: currentTheme.beamGradient,\n                WebkitBackgroundClip: \"text\",\n                WebkitTextFillColor: \"transparent\",\n                filter: \"drop-shadow(0 0 12px rgba(255, 255, 255, 0.8))\",\n                maskImage: `linear-gradient(${beamAngle}deg, transparent 20%, black 50%, transparent 80%)`,\n                WebkitMaskImage: `linear-gradient(${beamAngle}deg, transparent 20%, black 50%, transparent 80%)`,\n                maskSize: \"200% 100%\",\n                WebkitMaskSize: \"200% 100%\",\n              }}\n            >\n              {headline}\n            </motion.div>\n          )}\n        </div>\n\n        {/* Subtitle */}\n        <p className=\"mt-6 max-w-xl text-sm md:text-base text-neutral-400 font-sans\">\n          Engineered with microsecond responsiveness, real-time sync, and fluid keyboard ergonomics.\n        </p>\n\n        {/* Interactive copy button */}\n        <div className=\"mt-6 flex items-center gap-3\">\n          <button\n            onClick={handleCopy}\n            className=\"inline-flex items-center gap-2 rounded-xl border border-neutral-700 bg-neutral-800/80 px-4 py-2 text-xs font-medium text-neutral-200 hover:bg-neutral-700 hover:text-white transition-all shadow-sm\"\n          >\n            {copied ? (\n              <>\n                <Check className=\"h-3.5 w-3.5 text-emerald-400\" />\n                <span>Copied to Clipboard</span>\n              </>\n            ) : (\n              <>\n                <Copy className=\"h-3.5 w-3.5\" />\n                <span>Copy Headline</span>\n              </>\n            )}\n          </button>\n\n          <button\n            onClick={() => setHoverOnly(!hoverOnly)}\n            className={cn(\n              \"inline-flex items-center gap-1.5 rounded-xl border px-3 py-2 text-xs font-mono transition-all\",\n              hoverOnly\n                ? \"border-neutral-600 bg-neutral-800 text-white font-medium\"\n                : \"border-neutral-800 bg-neutral-900/60 text-neutral-400 hover:text-neutral-200\"\n            )}\n          >\n            <Eye className=\"h-3.5 w-3.5\" />\n            <span>{hoverOnly ? \"Sweep on Hover Only: ON\" : \"Sweep on Hover Only: OFF\"}</span>\n          </button>\n        </div>\n      </div>\n\n      {/* Interactive Controls Bar */}\n      <div className=\"relative z-10 grid grid-cols-1 md:grid-cols-3 gap-4 border-t border-neutral-800/80 pt-4 text-xs\">\n        {/* Live Headline Editor */}\n        <div className=\"flex flex-col gap-1.5\">\n          <label className=\"text-[11px] font-mono text-neutral-400 flex items-center gap-1\">\n            <Type className=\"h-3 w-3\" />\n            <span>CUSTOM TEXT</span>\n          </label>\n          <input\n            type=\"text\"\n            value={headline}\n            onChange={(e) => setHeadline(e.target.value)}\n            placeholder=\"Type custom headline...\"\n            className=\"w-full rounded-lg border border-neutral-700 bg-neutral-900 px-3 py-1.5 font-sans text-xs text-white placeholder-neutral-500 focus:border-neutral-500 focus:outline-none\"\n          />\n        </div>\n\n        {/* Shimmer Speed Slider */}\n        <div className=\"flex flex-col gap-1.5\">\n          <div className=\"flex justify-between text-[11px] font-mono text-neutral-400\">\n            <span>SWEEP DURATION</span>\n            <span className=\"text-white font-bold\">{speed}s</span>\n          </div>\n          <input\n            type=\"range\"\n            min=\"1\"\n            max=\"6\"\n            step=\"0.5\"\n            value={speed}\n            onChange={(e) => setSpeed(parseFloat(e.target.value))}\n            className=\"accent-neutral-300 h-1.5 w-full cursor-pointer rounded-lg bg-neutral-800\"\n          />\n        </div>\n\n        {/* Beam Angle Slider */}\n        <div className=\"flex flex-col gap-1.5\">\n          <div className=\"flex justify-between text-[11px] font-mono text-neutral-400\">\n            <span>BEAM ANGLE</span>\n            <span className=\"text-white font-bold\">{beamAngle}&deg;</span>\n          </div>\n          <input\n            type=\"range\"\n            min=\"45\"\n            max=\"180\"\n            step=\"5\"\n            value={beamAngle}\n            onChange={(e) => setBeamAngle(parseInt(e.target.value))}\n            className=\"accent-neutral-300 h-1.5 w-full cursor-pointer rounded-lg bg-neutral-800\"\n          />\n        </div>\n      </div>\n    </div>\n  );\n}\n\nexport default ShimmerText;\n",
          "type": "registry:ui",
          "target": "components/ui/shimmer-text.tsx"
        },
        {
          "path": "lib/utils.ts",
          "content": "import { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...inputs: ClassValue[]) {\n  return twMerge(clsx(inputs));\n}\n\nexport async function copyToClipboard(text: string): Promise<boolean> {\n  if (typeof window === \"undefined\") return false;\n\n  try {\n    if (navigator.clipboard && window.isSecureContext) {\n      await navigator.clipboard.writeText(text);\n      return true;\n    }\n\n    const textArea = document.createElement(\"textarea\");\n    textArea.value = text;\n    textArea.style.position = \"fixed\";\n    textArea.style.left = \"-999999px\";\n    textArea.style.top = \"-999999px\";\n    document.body.appendChild(textArea);\n    textArea.focus();\n    textArea.select();\n    const succeeded = document.execCommand(\"copy\");\n    textArea.remove();\n    return succeeded;\n  } catch {\n    return false;\n  }\n}\n",
          "type": "registry:lib",
          "target": "lib/utils.ts"
        }
      ]
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "shooting-stars",
      "type": "registry:ui",
      "title": "Shooting Stars",
      "author": "Rishabh Bose <https://theb0se.vercel.app/>",
      "description": "Atmospheric meteor shower background that spawns diagonal shooting stars with glowing heads and transparent gradient tails at configurable intervals.",
      "dependencies": [
        "lucide-react",
        "clsx",
        "tailwind-merge"
      ],
      "files": [
        {
          "path": "components/ui/shooting-stars.tsx",
          "content": "\"use client\";\n\nimport React, { useEffect, useRef, useState } from \"react\";\nimport { Sparkles } from \"lucide-react\";\nimport { cn } from \"@/lib/utils\";\n\nexport interface ShootingStarsProps {\n  /** Average spawns per second. Default: 2.5 */\n  frequency?: number;\n  /** Trajectory angle in degrees. Default: 35 */\n  angle?: number;\n  /** Hex or RGB color for the meteor head and tail. Default: \"#FFFFFF\" */\n  color?: string;\n  /** Maximum simultaneous shooting stars. Default: 6 */\n  maxConcurrent?: number;\n  /** Optional foreground content */\n  children?: React.ReactNode;\n  className?: string;\n}\n\ninterface Meteor {\n  x: number;\n  y: number;\n  length: number;\n  speed: number;\n  life: number;\n  maxLife: number;\n}\n\nexport function ShootingStars({\n  frequency = 2.5,\n  angle = 35,\n  color = \"#FFFFFF\",\n  maxConcurrent = 6,\n  children,\n  className,\n}: ShootingStarsProps) {\n  const canvasRef = useRef<HTMLCanvasElement>(null);\n  const [burstTrigger, setBurstTrigger] = useState(0);\n\n  useEffect(() => {\n    const canvas = canvasRef.current;\n    if (!canvas) return;\n    const ctx = canvas.getContext(\"2d\");\n    if (!ctx) return;\n\n    let rafId: number;\n    let width = (canvas.width = canvas.offsetWidth || 600);\n    let height = (canvas.height = canvas.offsetHeight || 360);\n\n    const rad = (angle * Math.PI) / 180;\n    const vx = Math.cos(rad);\n    const vy = Math.sin(rad);\n\n    const meteors: Meteor[] = [];\n\n    const spawnMeteor = () => {\n      if (meteors.length >= maxConcurrent) return;\n      meteors.push({\n        x: Math.random() * width * 0.85,\n        y: Math.random() * height * 0.45,\n        length: 80 + Math.random() * 90,\n        speed: 520 + Math.random() * 340,\n        life: 0,\n        maxLife: 0.75 + Math.random() * 0.45,\n      });\n    };\n\n    // Initial spawn\n    spawnMeteor();\n\n    let last = performance.now();\n    const render = (now: number) => {\n      const dt = Math.min(0.05, (now - last) / 1000);\n      last = now;\n\n      if (Math.random() < frequency * dt) {\n        spawnMeteor();\n      }\n\n      ctx.clearRect(0, 0, width, height);\n\n      for (let i = meteors.length - 1; i >= 0; i--) {\n        const m = meteors[i];\n        m.life += dt;\n        if (m.life >= m.maxLife) {\n          meteors.splice(i, 1);\n          continue;\n        }\n\n        m.x += vx * m.speed * dt;\n        m.y += vy * m.speed * dt;\n\n        const progress = m.life / m.maxLife;\n        const alpha =\n          progress < 0.2\n            ? progress / 0.2\n            : Math.max(0, 1 - (progress - 0.2) / 0.8);\n\n        const tailX = m.x - vx * m.length;\n        const tailY = m.y - vy * m.length;\n\n        const grad = ctx.createLinearGradient(m.x, m.y, tailX, tailY);\n        grad.addColorStop(0, color);\n        grad.addColorStop(1, \"rgba(255, 255, 255, 0)\");\n\n        ctx.save();\n        ctx.globalAlpha = alpha;\n        ctx.strokeStyle = grad;\n        ctx.lineWidth = 2;\n        ctx.lineCap = \"round\";\n        ctx.beginPath();\n        ctx.moveTo(m.x, m.y);\n        ctx.lineTo(tailX, tailY);\n        ctx.stroke();\n\n        // Bright head glow\n        ctx.fillStyle = color;\n        ctx.beginPath();\n        ctx.arc(m.x, m.y, 2.2, 0, Math.PI * 2);\n        ctx.fill();\n        ctx.restore();\n      }\n\n      rafId = requestAnimationFrame(render);\n    };\n\n    rafId = requestAnimationFrame(render);\n    return () => cancelAnimationFrame(rafId);\n  }, [frequency, angle, color, maxConcurrent, burstTrigger]);\n\n  return (\n    <div\n      data-fullscreen-scroll\n      className={cn(\n        \"relative flex min-h-[360px] w-full flex-col justify-between overflow-hidden rounded-3xl border border-neutral-800 bg-[#05070F] p-6 text-white shadow-sm\",\n        className\n      )}\n    >\n      {/* Subtle Background Star Dust */}\n      <div\n        aria-hidden=\"true\"\n        className=\"pointer-events-none absolute inset-0 opacity-25 [background-image:radial-gradient(white_1px,transparent_1px)] [background-size:32px_32px]\"\n      />\n\n      <canvas\n        ref={canvasRef}\n        aria-hidden=\"true\"\n        className=\"pointer-events-none absolute inset-0 h-full w-full\"\n      />\n\n      <div className=\"relative z-10 flex flex-1 flex-col justify-between\">\n        {children ?? (\n          <>\n            <div className=\"flex items-center justify-between gap-2\">\n              <span className=\"inline-flex items-center gap-1.5 rounded-full border border-white/15 bg-white/10 px-3 py-1 font-mono text-[11px] font-medium text-white backdrop-blur-md\">\n                <Sparkles className=\"h-3.5 w-3.5 text-amber-200\" />\n                Shooting Stars · {angle}° Trajectory\n              </span>\n\n              <button\n                type=\"button\"\n                onClick={() => setBurstTrigger((c) => c + 1)}\n                className=\"rounded-full border border-white/15 bg-white/10 px-3 py-1 font-mono text-[11px] text-white backdrop-blur-md transition-colors hover:bg-white/20\"\n              >\n                Spawn Meteor\n              </button>\n            </div>\n\n            <div className=\"my-auto max-w-md py-8\">\n              <h3 className=\"text-2xl font-bold tracking-tight text-white sm:text-3xl\">\n                Meteor Shower Streaking\n              </h3>\n              <p className=\"mt-2 text-xs leading-relaxed text-white/75 sm:text-sm\">\n                Randomized diagonal meteors with bright heads and linear-gradient\n                tails that fade out smoothly over a 1-second lifecycle.\n              </p>\n            </div>\n\n            <div className=\"font-mono text-[11px] text-white/50\">\n              Max Concurrent: {maxConcurrent} · Frequency: {frequency}/s\n            </div>\n          </>\n        )}\n      </div>\n    </div>\n  );\n}\n\nexport default ShootingStars;\n",
          "type": "registry:ui",
          "target": "components/ui/shooting-stars.tsx"
        },
        {
          "path": "lib/utils.ts",
          "content": "import { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...inputs: ClassValue[]) {\n  return twMerge(clsx(inputs));\n}\n\nexport async function copyToClipboard(text: string): Promise<boolean> {\n  if (typeof window === \"undefined\") return false;\n\n  try {\n    if (navigator.clipboard && window.isSecureContext) {\n      await navigator.clipboard.writeText(text);\n      return true;\n    }\n\n    const textArea = document.createElement(\"textarea\");\n    textArea.value = text;\n    textArea.style.position = \"fixed\";\n    textArea.style.left = \"-999999px\";\n    textArea.style.top = \"-999999px\";\n    document.body.appendChild(textArea);\n    textArea.focus();\n    textArea.select();\n    const succeeded = document.execCommand(\"copy\");\n    textArea.remove();\n    return succeeded;\n  } catch {\n    return false;\n  }\n}\n",
          "type": "registry:lib",
          "target": "lib/utils.ts"
        }
      ]
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "siri-glow-edge",
      "type": "registry:ui",
      "title": "Siri Glow Edge",
      "author": "Rishabh Bose <https://theb0se.vercel.app/>",
      "description": "Apple Intelligence-inspired fluid perimeter rainbow chromatic aura with multi-layer conic gradient blur, breathing light cycles, live voice waveform reaction, and adjustable glow thickness.",
      "dependencies": [
        "framer-motion",
        "lucide-react",
        "clsx",
        "tailwind-merge"
      ],
      "files": [
        {
          "path": "components/ui/siri-glow-edge.tsx",
          "content": "\"use client\";\n\nimport React, { useState, useEffect } from \"react\";\nimport { motion, AnimatePresence } from \"framer-motion\";\nimport { Mic, MicOff, Sparkles, Volume2, Sliders, RefreshCw, AudioWaveform } from \"lucide-react\";\nimport { cn } from \"@/lib/utils\";\n\nexport type SiriState = \"idle\" | \"listening\" | \"thinking\" | \"responding\";\n\nexport interface SiriGlowEdgeProps {\n  /** Initial or controlled intelligence state */\n  initialState?: SiriState;\n  /** Glow intensity factor (0.4 to 2.0) */\n  intensity?: number;\n  /** Glow spread thickness in px */\n  glowWidth?: number;\n  /** Whether the chromatic aura breathes / pulses */\n  enableBreathing?: boolean;\n  /** Inner content or prompt card */\n  children?: React.ReactNode;\n  /** Container custom classes */\n  className?: string;\n}\n\nexport function SiriGlowEdge({\n  initialState = \"idle\",\n  intensity = 1.0,\n  glowWidth = 14,\n  enableBreathing = true,\n  children,\n  className,\n}: SiriGlowEdgeProps) {\n  const [siriState, setSiriState] = useState<SiriState>(initialState);\n  const [currentIntensity, setCurrentIntensity] = useState(intensity);\n  const [currentGlowWidth, setCurrentGlowWidth] = useState(glowWidth);\n  const [promptText, setPromptText] = useState(\"\");\n  const [waveformBars, setWaveformBars] = useState<number[]>([\n    24, 45, 78, 62, 90, 48, 85, 34, 60, 40,\n  ]);\n\n  // Audio wave simulation when listening/responding\n  useEffect(() => {\n    if (siriState === \"idle\") return;\n\n    const interval = setInterval(() => {\n      setWaveformBars(\n        Array.from({ length: 12 }, () =>\n          Math.floor(Math.random() * (siriState === \"listening\" ? 75 : 45) + 15)\n        )\n      );\n    }, 110);\n\n    return () => clearInterval(interval);\n  }, [siriState]);\n\n  // State configurations\n  const stateConfigs = {\n    idle: {\n      badge: \"Apple Intelligence Ready\",\n      color: \"text-neutral-400\",\n      auraSpeed: \"12s\",\n      auraOpacity: 0.55 * currentIntensity,\n      blurAmount: `${currentGlowWidth * 1.2}px`,\n    },\n    listening: {\n      badge: \"Listening to Audio Input...\",\n      color: \"text-cyan-400\",\n      auraSpeed: \"4s\",\n      auraOpacity: 0.95 * currentIntensity,\n      blurAmount: `${currentGlowWidth * 1.8}px`,\n    },\n    thinking: {\n      badge: \"Processing Neural Query...\",\n      color: \"text-purple-400\",\n      auraSpeed: \"2.5s\",\n      auraOpacity: 0.9 * currentIntensity,\n      blurAmount: `${currentGlowWidth * 2.0}px`,\n    },\n    responding: {\n      badge: \"Apple Intelligence Synthesizing...\",\n      color: \"text-amber-400\",\n      auraSpeed: \"6s\",\n      auraOpacity: 0.85 * currentIntensity,\n      blurAmount: `${currentGlowWidth * 1.5}px`,\n    },\n  };\n\n  const currentCfg = stateConfigs[siriState];\n\n  const handleMicToggle = () => {\n    if (siriState === \"idle\") {\n      setSiriState(\"listening\");\n      setPromptText(\"Summarize my notifications and draft a reply to Sarah...\");\n    } else if (siriState === \"listening\") {\n      setSiriState(\"thinking\");\n      setTimeout(() => {\n        setSiriState(\"responding\");\n        setTimeout(() => {\n          setSiriState(\"idle\");\n        }, 4000);\n      }, 1500);\n    } else {\n      setSiriState(\"idle\");\n    }\n  };\n\n  if (children) {\n    return (\n      <div className={cn(\"relative w-full\", className)}>\n        <style>{`\n          @keyframes siriConicRotate {\n            0% { transform: rotate(0deg) scale(1.02); }\n            50% { transform: rotate(180deg) scale(1.07); }\n            100% { transform: rotate(360deg) scale(1.02); }\n          }\n          @keyframes siriBreathingAura {\n            0%, 100% { opacity: ${currentCfg.auraOpacity * 0.75}; }\n            50% { opacity: ${Math.min(1, currentCfg.auraOpacity * 1.25)}; }\n          }\n        `}</style>\n        {/* Layer 1: Hyper-diffuse outer rainbow chromatic aura blur */}\n        <div\n          className=\"pointer-events-none absolute -inset-3 rounded-3xl transition-all duration-700\"\n          style={{\n            filter: `blur(${currentCfg.blurAmount})`,\n            opacity: currentCfg.auraOpacity,\n            animation: enableBreathing ? `siriBreathingAura 3.6s ease-in-out infinite` : undefined,\n            background: `conic-gradient(from 0deg at 50% 50%,\n              #F43F5E, #FB923C, #FACC15, #34D399, #38BDF8, #818CF8, #C084FC, #F43F5E\n            )`,\n          }}\n        />\n        {/* Layer 2: Rotating crisp edge conic contour */}\n        <div\n          className=\"pointer-events-none absolute -inset-[3px] rounded-3xl transition-opacity duration-500 overflow-hidden\"\n          style={{ opacity: Math.min(1, currentCfg.auraOpacity * 1.1) }}\n        >\n          <div\n            className=\"absolute -inset-[100%]\"\n            style={{\n              animation: `siriConicRotate ${currentCfg.auraSpeed} linear infinite`,\n              background: `conic-gradient(from 180deg at 50% 50%,\n                #EC4899 0%, #F97316 20%, #38BDF8 40%, #8B5CF6 60%, #06B6D4 80%, #EC4899 100%\n              )`,\n            }}\n          />\n        </div>\n        {/* Layer 3: Inner Content */}\n        <div className=\"relative rounded-2xl overflow-hidden shadow-2xl\">\n          {children}\n        </div>\n      </div>\n    );\n  }\n\n  return (\n    <div\n      data-fullscreen-scroll\n      className={cn(\n        \"relative w-full min-h-[520px] overflow-hidden rounded-2xl border border-neutral-200/80 bg-[#07090E] p-6 text-neutral-100 shadow-2xl transition-all dark:border-neutral-800\",\n        className\n      )}\n    >\n      {/* Dynamic Keyframe style for Siri conic aura rotation */}\n      <style>{`\n        @keyframes siriConicRotate {\n          0% { transform: rotate(0deg) scale(1.02); }\n          50% { transform: rotate(180deg) scale(1.07); }\n          100% { transform: rotate(360deg) scale(1.02); }\n        }\n        @keyframes siriBreathingAura {\n          0%, 100% { opacity: ${currentCfg.auraOpacity * 0.75}; }\n          50% { opacity: ${Math.min(1, currentCfg.auraOpacity * 1.25)}; }\n        }\n      `}</style>\n\n      {/* Atmospheric backdrop */}\n      <div\n        className=\"pointer-events-none absolute inset-0 opacity-40 transition-opacity duration-700\"\n        style={{\n          background: `radial-gradient(ellipse at 50% 50%, rgba(244, 63, 94, 0.12), rgba(59, 130, 246, 0.12), transparent 75%)`,\n        }}\n      />\n\n      {/* Top Controls Header */}\n      <div className=\"relative z-10 flex flex-wrap items-center justify-between gap-4 border-b border-neutral-800/80 pb-4\">\n        <div>\n          <div className=\"inline-flex items-center gap-2 rounded-full border border-neutral-800 bg-neutral-900/90 px-3 py-1 text-xs font-medium text-neutral-300 backdrop-blur-md\">\n            <Sparkles className=\"h-3 w-3 text-cyan-400\" />\n            Apple Intelligence Siri Glow\n          </div>\n          <h2 className=\"mt-2 text-xl font-semibold tracking-tight text-white\">\n            Fluid Perimeter Chromatic Aura\n          </h2>\n          <p className=\"text-xs text-neutral-400\">\n            Multi-layer conic gradient perimeter aura with breathing pulse and voice waveform feedback\n          </p>\n        </div>\n\n        {/* State Selector Buttons */}\n        <div className=\"flex flex-wrap items-center gap-1.5 rounded-xl border border-neutral-800 bg-neutral-900/90 p-1\">\n          {([\"idle\", \"listening\", \"thinking\", \"responding\"] as const).map((st) => (\n            <button\n              key={st}\n              type=\"button\"\n              onClick={() => setSiriState(st)}\n              className={cn(\n                \"rounded-lg px-2.5 py-1 text-xs font-medium capitalize transition\",\n                siriState === st\n                  ? \"bg-neutral-800 text-white shadow-sm ring-1 ring-white/10\"\n                  : \"text-neutral-400 hover:text-white\"\n              )}\n            >\n              {st}\n            </button>\n          ))}\n        </div>\n      </div>\n\n      {/* Center Aura Card Showcase */}\n      <div className=\"relative z-10 flex min-h-[330px] items-center justify-center py-8\">\n        {/* The Outer Aura Wrapper */}\n        <div className=\"relative w-full max-w-xl\">\n          {/* Layer 1: Hyper-diffuse outer rainbow chromatic aura blur */}\n          <div\n            className=\"pointer-events-none absolute -inset-3 rounded-3xl transition-all duration-700\"\n            style={{\n              filter: `blur(${currentCfg.blurAmount})`,\n              opacity: currentCfg.auraOpacity,\n              animation: enableBreathing\n                ? `siriBreathingAura 3.6s ease-in-out infinite`\n                : undefined,\n              background: `conic-gradient(from 0deg at 50% 50%,\n                #F43F5E,\n                #FB923C,\n                #FACC15,\n                #34D399,\n                #38BDF8,\n                #818CF8,\n                #C084FC,\n                #F43F5E\n              )`,\n            }}\n          />\n\n          {/* Layer 2: Rotating crisp edge conic contour */}\n          <div\n            className=\"pointer-events-none absolute -inset-[3px] rounded-3xl transition-opacity duration-500 overflow-hidden\"\n            style={{\n              opacity: Math.min(1, currentCfg.auraOpacity * 1.1),\n            }}\n          >\n            <div\n              className=\"absolute -inset-[100%]\"\n              style={{\n                animation: `siriConicRotate ${currentCfg.auraSpeed} linear infinite`,\n                background: `conic-gradient(from 180deg at 50% 50%,\n                  #EC4899 0%,\n                  #F97316 20%,\n                  #38BDF8 40%,\n                  #8B5CF6 60%,\n                  #06B6D4 80%,\n                  #EC4899 100%\n                )`,\n              }}\n            />\n          </div>\n\n          {/* Layer 3: Inner Card Core Container */}\n          <div className=\"relative rounded-2xl border border-white/10 bg-[#0B0E17]/95 p-6 backdrop-blur-2xl shadow-2xl\">\n            {children || (\n              <div className=\"space-y-5\">\n                {/* Status Header */}\n                <div className=\"flex items-center justify-between\">\n                  <div className=\"flex items-center gap-2\">\n                    <span\n                      className={cn(\n                        \"h-2 w-2 rounded-full animate-ping\",\n                        siriState === \"listening\"\n                          ? \"bg-cyan-400\"\n                          : siriState === \"thinking\"\n                          ? \"bg-purple-400\"\n                          : siriState === \"responding\"\n                          ? \"bg-amber-400\"\n                          : \"bg-emerald-400\"\n                      )}\n                    />\n                    <span className={cn(\"text-xs font-medium\", currentCfg.color)}>\n                      {currentCfg.badge}\n                    </span>\n                  </div>\n\n                  <span className=\"rounded-full bg-white/5 px-2.5 py-0.5 text-[10px] font-mono text-neutral-400 border border-white/10\">\n                    A18 Neural Engine\n                  </span>\n                </div>\n\n                {/* Simulated Assistant Query / Response */}\n                <div className=\"rounded-xl border border-white/10 bg-white/5 p-4 text-xs leading-relaxed text-neutral-200\">\n                  {siriState === \"idle\" && (\n                    <span className=\"text-neutral-400\">\n                      Tap the microphone button or speak: &quot;Hey Siri, summarize the quarterly earnings and draft my key points.&quot;\n                    </span>\n                  )}\n                  {siriState === \"listening\" && (\n                    <span className=\"text-white font-medium animate-pulse\">\n                      &quot;{promptText}&quot;\n                    </span>\n                  )}\n                  {siriState === \"thinking\" && (\n                    <span className=\"text-purple-300\">\n                      Synthesizing context across Mail, Calendar, and Messages with on-device model...\n                    </span>\n                  )}\n                  {siriState === \"responding\" && (\n                    <span className=\"text-neutral-100\">\n                      &quot;You have 3 unread messages from Sarah regarding the prototype review at 3 PM. Would you like me to confirm?&quot;\n                    </span>\n                  )}\n                </div>\n\n                {/* Animated Voice Waveform Bars when active */}\n                <div className=\"flex items-center justify-between gap-4 pt-1\">\n                  <div className=\"flex items-center gap-1.5 h-8\">\n                    {siriState !== \"idle\" ? (\n                      waveformBars.map((height, i) => (\n                        <motion.span\n                          key={i}\n                          animate={{ height: `${height}%` }}\n                          transition={{ type: \"spring\", stiffness: 350, damping: 25 }}\n                          className=\"w-1.5 rounded-full bg-gradient-to-t from-cyan-400 via-purple-500 to-rose-400\"\n                        />\n                      ))\n                    ) : (\n                      <span className=\"text-[11px] text-neutral-500 flex items-center gap-1.5\">\n                        <AudioWaveform className=\"h-3.5 w-3.5\" />\n                        Microphone idle\n                      </span>\n                    )}\n                  </div>\n\n                  {/* Primary Trigger Button */}\n                  <button\n                    type=\"button\"\n                    onClick={handleMicToggle}\n                    className={cn(\n                      \"flex items-center gap-2 rounded-xl px-4 py-2 text-xs font-semibold shadow-lg transition active:scale-95\",\n                      siriState === \"listening\"\n                        ? \"bg-rose-500 text-white shadow-rose-500/25 animate-pulse\"\n                        : \"bg-white text-neutral-950 hover:bg-neutral-200\"\n                    )}\n                  >\n                    {siriState === \"listening\" ? (\n                      <>\n                        <MicOff className=\"h-3.5 w-3.5\" />\n                        <span>Stop Voice</span>\n                      </>\n                    ) : (\n                      <>\n                        <Mic className=\"h-3.5 w-3.5 text-neutral-900\" />\n                        <span>Talk to Siri</span>\n                      </>\n                    )}\n                  </button>\n                </div>\n              </div>\n            )}\n          </div>\n        </div>\n      </div>\n\n      {/* Live Tuning Sliders */}\n      <div className=\"relative z-10 mt-4 grid grid-cols-1 gap-4 rounded-xl border border-neutral-800 bg-neutral-900/70 p-4 backdrop-blur-md sm:grid-cols-2\">\n        {/* Aura Intensity Slider */}\n        <div className=\"space-y-1.5\">\n          <div className=\"flex items-center justify-between text-xs\">\n            <span className=\"text-neutral-300 font-medium\">Glow Intensity</span>\n            <span className=\"font-mono text-neutral-400\">{currentIntensity.toFixed(2)}x</span>\n          </div>\n          <input\n            type=\"range\"\n            min={0.4}\n            max={2.0}\n            step={0.1}\n            value={currentIntensity}\n            onChange={(e) => setCurrentIntensity(parseFloat(e.target.value))}\n            className=\"h-1.5 w-full cursor-pointer appearance-none rounded-lg bg-neutral-800 accent-purple-500\"\n          />\n        </div>\n\n        {/* Aura Thickness Slider */}\n        <div className=\"space-y-1.5\">\n          <div className=\"flex items-center justify-between text-xs\">\n            <span className=\"text-neutral-300 font-medium\">Perimeter Glow Spread</span>\n            <span className=\"font-mono text-neutral-400\">{currentGlowWidth}px</span>\n          </div>\n          <input\n            type=\"range\"\n            min={6}\n            max={30}\n            step={2}\n            value={currentGlowWidth}\n            onChange={(e) => setCurrentGlowWidth(parseInt(e.target.value, 10))}\n            className=\"h-1.5 w-full cursor-pointer appearance-none rounded-lg bg-neutral-800 accent-purple-500\"\n          />\n        </div>\n      </div>\n    </div>\n  );\n}\n\nexport default SiriGlowEdge;\n",
          "type": "registry:ui",
          "target": "components/ui/siri-glow-edge.tsx"
        },
        {
          "path": "lib/utils.ts",
          "content": "import { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...inputs: ClassValue[]) {\n  return twMerge(clsx(inputs));\n}\n\nexport async function copyToClipboard(text: string): Promise<boolean> {\n  if (typeof window === \"undefined\") return false;\n\n  try {\n    if (navigator.clipboard && window.isSecureContext) {\n      await navigator.clipboard.writeText(text);\n      return true;\n    }\n\n    const textArea = document.createElement(\"textarea\");\n    textArea.value = text;\n    textArea.style.position = \"fixed\";\n    textArea.style.left = \"-999999px\";\n    textArea.style.top = \"-999999px\";\n    document.body.appendChild(textArea);\n    textArea.focus();\n    textArea.select();\n    const succeeded = document.execCommand(\"copy\");\n    textArea.remove();\n    return succeeded;\n  } catch {\n    return false;\n  }\n}\n",
          "type": "registry:lib",
          "target": "lib/utils.ts"
        }
      ]
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "slash-command-menu",
      "type": "registry:ui",
      "title": "Slash Command Menu",
      "author": "Rishabh Bose <https://theb0se.vercel.app/>",
      "description": "Notion-style rich-text editor command menu triggered via '/', featuring fuzzy search filtering, keyboard arrow navigation, enter-to-insert blocks (Headings, To-Dos, Code Blocks, Callouts, Quotes), and delete controls.",
      "dependencies": [
        "framer-motion",
        "lucide-react",
        "clsx",
        "tailwind-merge"
      ],
      "files": [
        {
          "path": "components/ui/slash-command-menu.tsx",
          "content": "\"use client\";\n\nimport React, { useState, useRef, useEffect, useCallback } from \"react\";\nimport { motion, AnimatePresence } from \"framer-motion\";\nimport {\n  Heading1,\n  Heading2,\n  Heading3,\n  CheckSquare,\n  Code2,\n  List,\n  AlertCircle,\n  Quote,\n  Trash2,\n  FileText,\n  Search,\n  Sparkles,\n  Command,\n} from \"lucide-react\";\nimport { cn } from \"@/lib/utils\";\n\nexport type BlockType =\n  | \"p\"\n  | \"h1\"\n  | \"h2\"\n  | \"h3\"\n  | \"todo\"\n  | \"code\"\n  | \"bullet\"\n  | \"callout\"\n  | \"quote\";\n\nexport interface DocumentBlock {\n  id: string;\n  type: BlockType;\n  content: string;\n  checked?: boolean;\n}\n\nexport interface CommandOption {\n  id: BlockType;\n  title: string;\n  subtitle: string;\n  icon: React.ComponentType<{ className?: string }>;\n  category: \"Basic\" | \"List\" | \"Advanced\";\n}\n\nconst COMMAND_OPTIONS: CommandOption[] = [\n  {\n    id: \"h1\",\n    title: \"Heading 1\",\n    subtitle: \"Large top-level title section\",\n    icon: Heading1,\n    category: \"Basic\",\n  },\n  {\n    id: \"h2\",\n    title: \"Heading 2\",\n    subtitle: \"Medium subsection heading\",\n    icon: Heading2,\n    category: \"Basic\",\n  },\n  {\n    id: \"h3\",\n    title: \"Heading 3\",\n    subtitle: \"Small grouping subheader\",\n    icon: Heading3,\n    category: \"Basic\",\n  },\n  {\n    id: \"todo\",\n    title: \"To-do List\",\n    subtitle: \"Track tasks with toggleable checkboxes\",\n    icon: CheckSquare,\n    category: \"List\",\n  },\n  {\n    id: \"bullet\",\n    title: \"Bulleted List\",\n    subtitle: \"Create a simple unordered bulleted list\",\n    icon: List,\n    category: \"List\",\n  },\n  {\n    id: \"code\",\n    title: \"Code Block\",\n    subtitle: \"Capture code snippets with monospaced styling\",\n    icon: Code2,\n    category: \"Advanced\",\n  },\n  {\n    id: \"callout\",\n    title: \"Callout Box\",\n    subtitle: \"Highlight important context with an alert box\",\n    icon: AlertCircle,\n    category: \"Advanced\",\n  },\n  {\n    id: \"quote\",\n    title: \"Quote\",\n    subtitle: \"Capture memorable quotes or citations\",\n    icon: Quote,\n    category: \"Advanced\",\n  },\n];\n\nconst INITIAL_BLOCKS: DocumentBlock[] = [\n  {\n    id: \"b-1\",\n    type: \"h1\",\n    content: \"Product Strategy & Architecture\",\n  },\n  {\n    id: \"b-2\",\n    type: \"callout\",\n    content: \"All design components must adhere to the high-density Fintech guidelines.\",\n  },\n  {\n    id: \"b-3\",\n    type: \"todo\",\n    content: \"Implement real-time sparkline scrubbing\",\n    checked: true,\n  },\n  {\n    id: \"b-4\",\n    type: \"todo\",\n    content: \"Add multiplayer cursor canvas with live chat\",\n    checked: true,\n  },\n  {\n    id: \"b-5\",\n    type: \"code\",\n    content: \"const api = new PulseFinancialClient({ apiKey: 'pk_live_...' });\",\n  },\n];\n\nexport interface SlashCommandMenuProps {\n  initialBlocks?: DocumentBlock[];\n  placeholder?: string;\n  className?: string;\n}\n\nexport function SlashCommandMenu({\n  initialBlocks = INITIAL_BLOCKS,\n  placeholder = \"Type '/' for commands or start writing...\",\n  className,\n}: SlashCommandMenuProps) {\n  const [blocks, setBlocks] = useState<DocumentBlock[]>(initialBlocks);\n  const [currentInput, setCurrentInput] = useState(\"\");\n  const [menuOpen, setMenuOpen] = useState(false);\n  const [selectedIndex, setSelectedIndex] = useState(0);\n  const [searchQuery, setSearchQuery] = useState(\"\");\n\n  const inputRef = useRef<HTMLInputElement>(null);\n  const menuRef = useRef<HTMLDivElement>(null);\n\n  // Filter commands by fuzzy match against query\n  const filteredOptions = COMMAND_OPTIONS.filter((opt) => {\n    const q = searchQuery.toLowerCase().trim();\n    if (!q) return true;\n    return (\n      opt.title.toLowerCase().includes(q) ||\n      opt.subtitle.toLowerCase().includes(q) ||\n      opt.id.toLowerCase().includes(q)\n    );\n  });\n\n  // Keep selected index within bounds\n  useEffect(() => {\n    setSelectedIndex(0);\n  }, [searchQuery]);\n\n  // Handle typing inside the active block input\n  const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {\n    const val = e.target.value;\n    setCurrentInput(val);\n\n    if (val.startsWith(\"/\")) {\n      setMenuOpen(true);\n      setSearchQuery(val.slice(1));\n    } else {\n      setMenuOpen(false);\n      setSearchQuery(\"\");\n    }\n  };\n\n  // Insert a new block\n  const insertBlock = useCallback(\n    (type: BlockType) => {\n      const newBlock: DocumentBlock = {\n        id: `b-${Date.now()}`,\n        type,\n        content:\n          type === \"todo\"\n            ? \"New pending task...\"\n            : type === \"code\"\n            ? \"// Enter code snippet here\"\n            : type === \"callout\"\n            ? \"Important note context\"\n            : type === \"quote\"\n            ? \"Block quote inspiration\"\n            : type.startsWith(\"h\")\n            ? `New ${type.toUpperCase()} Section`\n            : \"New paragraph block\",\n        checked: false,\n      };\n\n      setBlocks((prev) => [...prev, newBlock]);\n      setCurrentInput(\"\");\n      setSearchQuery(\"\");\n      setMenuOpen(false);\n      setTimeout(() => {\n        inputRef.current?.focus();\n      }, 50);\n    },\n    []\n  );\n\n  // Key navigation inside input\n  const handleKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {\n    if (menuOpen) {\n      if (e.key === \"ArrowDown\") {\n        e.preventDefault();\n        setSelectedIndex((prev) =>\n          prev < filteredOptions.length - 1 ? prev + 1 : 0\n        );\n      } else if (e.key === \"ArrowUp\") {\n        e.preventDefault();\n        setSelectedIndex((prev) =>\n          prev > 0 ? prev - 1 : filteredOptions.length - 1\n        );\n      } else if (e.key === \"Enter\") {\n        e.preventDefault();\n        if (filteredOptions[selectedIndex]) {\n          insertBlock(filteredOptions[selectedIndex].id);\n        }\n      } else if (e.key === \"Escape\") {\n        e.preventDefault();\n        setMenuOpen(false);\n      }\n    } else if (e.key === \"Enter\" && currentInput.trim()) {\n      e.preventDefault();\n      // Insert standard paragraph\n      setBlocks((prev) => [\n        ...prev,\n        {\n          id: `b-${Date.now()}`,\n          type: \"p\",\n          content: currentInput,\n        },\n      ]);\n      setCurrentInput(\"\");\n    }\n  };\n\n  // Toggle todo item\n  const toggleTodo = (id: string) => {\n    setBlocks((prev) =>\n      prev.map((b) => (b.id === id ? { ...b, checked: !b.checked } : b))\n    );\n  };\n\n  // Delete a block\n  const deleteBlock = (id: string) => {\n    setBlocks((prev) => prev.filter((b) => b.id !== id));\n  };\n\n  return (\n    <div\n      data-fullscreen-scroll\n      className={cn(\n        \"relative w-full min-h-[520px] overflow-hidden rounded-2xl border border-neutral-200/80 bg-neutral-950 p-6 text-neutral-100 shadow-xl dark:border-neutral-800 flex flex-col justify-between\",\n        className\n      )}\n    >\n      {/* Top Header */}\n      <div className=\"relative z-10 flex flex-col sm:flex-row items-start sm:items-center justify-between gap-3 border-b border-neutral-800/80 pb-4\">\n        <div className=\"flex items-center gap-2\">\n          <FileText className=\"h-5 w-5 text-neutral-400\" />\n          <span className=\"font-semibold text-sm text-white\">\n            Notion-Style Slash Editor\n          </span>\n          <span className=\"rounded-full bg-neutral-800 border border-neutral-700/80 px-2 py-0.5 text-[10px] font-mono text-neutral-400\">\n            {blocks.length} Blocks\n          </span>\n        </div>\n\n        {/* Quick action triggers */}\n        <div className=\"flex items-center gap-2\">\n          <button\n            type=\"button\"\n            onClick={() => {\n              setCurrentInput(\"/\");\n              setMenuOpen(true);\n              setSearchQuery(\"\");\n              inputRef.current?.focus();\n            }}\n            className=\"flex items-center gap-1.5 rounded-lg border border-neutral-800 bg-neutral-900 px-2.5 py-1 text-xs font-medium text-neutral-200 hover:bg-neutral-800 transition-colors\"\n          >\n            <Command className=\"h-3 w-3 text-neutral-400\" />\n            <span>Open Menu (/)</span>\n          </button>\n          <button\n            type=\"button\"\n            onClick={() => setBlocks(INITIAL_BLOCKS)}\n            className=\"rounded-lg border border-neutral-800 bg-neutral-900 px-2.5 py-1 text-xs text-neutral-400 hover:text-neutral-200 transition-colors\"\n          >\n            Reset Template\n          </button>\n        </div>\n      </div>\n\n      {/* Main Document Canvas */}\n      <div className=\"relative my-4 flex-1 overflow-y-auto pr-1 space-y-3 max-h-[360px]\">\n        {blocks.map((block) => (\n          <div\n            key={block.id}\n            className=\"group relative flex items-start justify-between rounded-lg px-3 py-1.5 hover:bg-neutral-900/40 transition-colors\"\n          >\n            <div className=\"flex-1\">\n              {block.type === \"h1\" && (\n                <h1 className=\"text-2xl font-bold tracking-tight text-white\">\n                  {block.content}\n                </h1>\n              )}\n              {block.type === \"h2\" && (\n                <h2 className=\"text-xl font-semibold tracking-tight text-neutral-100\">\n                  {block.content}\n                </h2>\n              )}\n              {block.type === \"h3\" && (\n                <h3 className=\"text-base font-semibold text-neutral-200\">\n                  {block.content}\n                </h3>\n              )}\n              {block.type === \"p\" && (\n                <p className=\"text-sm text-neutral-300 leading-relaxed\">\n                  {block.content}\n                </p>\n              )}\n              {block.type === \"todo\" && (\n                <label className=\"flex items-center gap-2 cursor-pointer select-none\">\n                  <input\n                    type=\"checkbox\"\n                    checked={!!block.checked}\n                    onChange={() => toggleTodo(block.id)}\n                    className=\"h-4 w-4 rounded border-neutral-700 bg-neutral-800 text-indigo-500 focus:ring-0\"\n                  />\n                  <span\n                    className={cn(\n                      \"text-sm transition-all\",\n                      block.checked\n                        ? \"line-through text-neutral-500\"\n                        : \"text-neutral-200\"\n                    )}\n                  >\n                    {block.content}\n                  </span>\n                </label>\n              )}\n              {block.type === \"bullet\" && (\n                <div className=\"flex items-center gap-2 text-sm text-neutral-300\">\n                  <span className=\"h-1.5 w-1.5 rounded-full bg-neutral-400\" />\n                  <span>{block.content}</span>\n                </div>\n              )}\n              {block.type === \"code\" && (\n                <div className=\"rounded-lg border border-neutral-800 bg-neutral-900/90 p-3 font-mono text-xs text-emerald-400\">\n                  {block.content}\n                </div>\n              )}\n              {block.type === \"callout\" && (\n                <div className=\"flex items-start gap-2.5 rounded-lg border border-indigo-500/20 bg-indigo-950/20 p-3 text-xs text-indigo-200\">\n                  <AlertCircle className=\"h-4 w-4 text-indigo-400 shrink-0 mt-0.5\" />\n                  <span>{block.content}</span>\n                </div>\n              )}\n              {block.type === \"quote\" && (\n                <blockquote className=\"border-l-2 border-neutral-600 pl-3 italic text-sm text-neutral-400\">\n                  \"{block.content}\"\n                </blockquote>\n              )}\n            </div>\n\n            {/* Hover Delete Action */}\n            <button\n              type=\"button\"\n              onClick={() => deleteBlock(block.id)}\n              className=\"opacity-0 group-hover:opacity-100 transition-opacity p-1 text-neutral-500 hover:text-rose-400 rounded\"\n              title=\"Delete block\"\n            >\n              <Trash2 className=\"h-3.5 w-3.5\" />\n            </button>\n          </div>\n        ))}\n\n        {/* Active Input Line & Slash Menu Trigger */}\n        <div className=\"relative pt-2\">\n          <input\n            ref={inputRef}\n            type=\"text\"\n            value={currentInput}\n            onChange={handleInputChange}\n            onKeyDown={handleKeyDown}\n            placeholder={placeholder}\n            className=\"w-full bg-transparent px-3 py-2 text-sm text-neutral-100 placeholder:text-neutral-600 focus:outline-none border-b border-transparent focus:border-neutral-800\"\n          />\n\n          {/* Floating Slash Command Menu Popover */}\n          <AnimatePresence>\n            {menuOpen && (\n              <motion.div\n                ref={menuRef}\n                initial={{ opacity: 0, y: -6, scale: 0.98 }}\n                animate={{ opacity: 1, y: 0, scale: 1 }}\n                exit={{ opacity: 0, y: -6, scale: 0.98 }}\n                transition={{ duration: 0.15 }}\n                className=\"absolute left-2 top-12 z-30 w-72 max-h-72 overflow-y-auto rounded-xl border border-neutral-800 bg-neutral-900/95 p-1.5 shadow-2xl backdrop-blur-xl\"\n              >\n                <div className=\"px-2 py-1 text-[10px] font-mono font-semibold uppercase tracking-wider text-neutral-500 border-b border-neutral-800/80 mb-1 flex items-center justify-between\">\n                  <span>Insert Block</span>\n                  <span className=\"text-neutral-400\">↑↓ to navigate</span>\n                </div>\n\n                {filteredOptions.length === 0 ? (\n                  <div className=\"p-3 text-center text-xs text-neutral-500 font-mono\">\n                    No matching block found\n                  </div>\n                ) : (\n                  filteredOptions.map((opt, idx) => {\n                    const Icon = opt.icon;\n                    const isSelected = idx === selectedIndex;\n                    return (\n                      <button\n                        key={opt.id}\n                        type=\"button\"\n                        onClick={() => insertBlock(opt.id)}\n                        onMouseEnter={() => setSelectedIndex(idx)}\n                        className={cn(\n                          \"w-full flex items-center gap-2.5 rounded-lg px-2.5 py-1.5 text-left transition-colors\",\n                          isSelected\n                            ? \"bg-neutral-800 text-white\"\n                            : \"text-neutral-300 hover:bg-neutral-800/60\"\n                        )}\n                      >\n                        <div\n                          className={cn(\n                            \"flex h-7 w-7 shrink-0 items-center justify-center rounded-md border\",\n                            isSelected\n                              ? \"border-neutral-700 bg-neutral-700/80 text-white\"\n                              : \"border-neutral-800 bg-neutral-900 text-neutral-400\"\n                          )}\n                        >\n                          <Icon className=\"h-4 w-4\" />\n                        </div>\n                        <div className=\"flex-1 overflow-hidden\">\n                          <p className=\"text-xs font-medium truncate\">\n                            {opt.title}\n                          </p>\n                          <p className=\"text-[10px] text-neutral-500 truncate\">\n                            {opt.subtitle}\n                          </p>\n                        </div>\n                      </button>\n                    );\n                  })\n                )}\n              </motion.div>\n            )}\n          </AnimatePresence>\n        </div>\n      </div>\n\n      {/* Footer Helper Shortcuts */}\n      <div className=\"relative z-10 flex flex-wrap items-center justify-between gap-3 border-t border-neutral-800/80 pt-4 text-[11px] text-neutral-500 font-mono\">\n        <div className=\"flex items-center gap-2\">\n          <kbd className=\"rounded bg-neutral-900 border border-neutral-800 px-1.5 py-0.5 text-neutral-400\">\n            /\n          </kbd>\n          <span>to open menu</span>\n          <kbd className=\"rounded bg-neutral-900 border border-neutral-800 px-1.5 py-0.5 text-neutral-400\">\n            ↵\n          </kbd>\n          <span>to insert</span>\n          <kbd className=\"rounded bg-neutral-900 border border-neutral-800 px-1.5 py-0.5 text-neutral-400\">\n            Esc\n          </kbd>\n          <span>to cancel</span>\n        </div>\n\n        <div className=\"flex items-center gap-1.5 text-neutral-400\">\n          <Sparkles className=\"h-3 w-3 text-indigo-400\" />\n          <span>Fuzzy search filter enabled</span>\n        </div>\n      </div>\n    </div>\n  );\n}\n\nexport default SlashCommandMenu;\n",
          "type": "registry:ui",
          "target": "components/ui/slash-command-menu.tsx"
        },
        {
          "path": "lib/utils.ts",
          "content": "import { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...inputs: ClassValue[]) {\n  return twMerge(clsx(inputs));\n}\n\nexport async function copyToClipboard(text: string): Promise<boolean> {\n  if (typeof window === \"undefined\") return false;\n\n  try {\n    if (navigator.clipboard && window.isSecureContext) {\n      await navigator.clipboard.writeText(text);\n      return true;\n    }\n\n    const textArea = document.createElement(\"textarea\");\n    textArea.value = text;\n    textArea.style.position = \"fixed\";\n    textArea.style.left = \"-999999px\";\n    textArea.style.top = \"-999999px\";\n    document.body.appendChild(textArea);\n    textArea.focus();\n    textArea.select();\n    const succeeded = document.execCommand(\"copy\");\n    textArea.remove();\n    return succeeded;\n  } catch {\n    return false;\n  }\n}\n",
          "type": "registry:lib",
          "target": "lib/utils.ts"
        }
      ]
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "snowfall",
      "type": "registry:ui",
      "title": "Snowfall",
      "author": "Rishabh Bose <https://theb0se.vercel.app/>",
      "description": "Depth-sorted Canvas 2D snowfall simulation where larger foreground particles fall faster with higher opacity while drifting horizontally on sine waves.",
      "dependencies": [
        "lucide-react",
        "clsx",
        "tailwind-merge"
      ],
      "files": [
        {
          "path": "components/ui/snowfall.tsx",
          "content": "\"use client\";\n\nimport React, { useEffect, useRef, useState } from \"react\";\nimport { Snowflake } from \"lucide-react\";\nimport { cn } from \"@/lib/utils\";\n\nexport interface SnowfallProps {\n  /** Total number of snowflakes. Default: 140 */\n  flakeCount?: number;\n  /** Fall speed multiplier. Default: 1 */\n  speed?: number;\n  /** Horizontal wind drift (-2 to 2). Default: 0.3 */\n  wind?: number;\n  /** Maximum snowflake radius in pixels. Default: 4.2 */\n  maxSize?: number;\n  /** Optional foreground content */\n  children?: React.ReactNode;\n  className?: string;\n}\n\ninterface Flake {\n  x: number;\n  y: number;\n  r: number;\n  depth: number; // 0.2 to 1.0 (bigger = faster & more opaque)\n  phase: number;\n  swayAmp: number;\n}\n\nexport function Snowfall({\n  flakeCount = 140,\n  speed = 1,\n  wind = 0.3,\n  maxSize = 4.2,\n  children,\n  className,\n}: SnowfallProps) {\n  const canvasRef = useRef<HTMLCanvasElement>(null);\n  const [blizzard, setBlizzard] = useState(false);\n\n  const activeSpeed = blizzard ? speed * 2.4 : speed;\n  const activeWind = blizzard ? wind + 1.4 : wind;\n\n  useEffect(() => {\n    const canvas = canvasRef.current;\n    if (!canvas) return;\n    const ctx = canvas.getContext(\"2d\");\n    if (!ctx) return;\n\n    let rafId: number;\n    let width = (canvas.width = canvas.offsetWidth || 600);\n    let height = (canvas.height = canvas.offsetHeight || 360);\n\n    const flakes: Flake[] = Array.from({ length: flakeCount }, () => {\n      const depth = 0.2 + Math.random() * 0.8;\n      return {\n        x: Math.random() * width,\n        y: Math.random() * height,\n        r: 0.8 + depth * (maxSize - 0.8),\n        depth,\n        phase: Math.random() * Math.PI * 2,\n        swayAmp: 12 + Math.random() * 22,\n      };\n    });\n\n    const handleResize = () => {\n      if (!canvas) return;\n      width = canvas.width = canvas.offsetWidth || 600;\n      height = canvas.height = canvas.offsetHeight || 360;\n    };\n\n    window.addEventListener(\"resize\", handleResize);\n\n    let last = performance.now();\n    const render = (now: number) => {\n      const dt = Math.min(0.05, (now - last) / 1000);\n      const t = now * 0.001;\n      last = now;\n\n      ctx.clearRect(0, 0, width, height);\n\n      for (let i = 0; i < flakes.length; i++) {\n        const f = flakes[i];\n        // Bigger particles move faster and are more opaque for depth\n        const vy = (24 + f.depth * 68) * activeSpeed;\n        const vx =\n          activeWind * 28 * f.depth +\n          Math.sin(t * 1.4 + f.phase) * f.swayAmp * f.depth;\n\n        f.y += vy * dt;\n        f.x += vx * dt;\n\n        if (f.y > height + f.r) {\n          f.y = -f.r;\n          f.x = Math.random() * width;\n        }\n        if (f.x > width + f.r) f.x = -f.r;\n        if (f.x < -f.r) f.x = width + f.r;\n\n        const alpha = 0.22 + f.depth * 0.72;\n        ctx.beginPath();\n        ctx.arc(f.x, f.y, f.r, 0, Math.PI * 2);\n        ctx.fillStyle = `rgba(255, 255, 255, ${alpha.toFixed(3)})`;\n        ctx.fill();\n      }\n\n      rafId = requestAnimationFrame(render);\n    };\n\n    rafId = requestAnimationFrame(render);\n    return () => {\n      cancelAnimationFrame(rafId);\n      window.removeEventListener(\"resize\", handleResize);\n    };\n  }, [flakeCount, activeSpeed, activeWind, maxSize]);\n\n  return (\n    <div\n      data-fullscreen-scroll\n      className={cn(\n        \"relative flex min-h-[360px] w-full flex-col justify-between overflow-hidden rounded-3xl border border-neutral-800 bg-gradient-to-b from-[#060B16] via-[#0B1528] to-[#16243E] p-6 text-white shadow-sm\",\n        className\n      )}\n    >\n      <canvas\n        ref={canvasRef}\n        aria-hidden=\"true\"\n        className=\"pointer-events-none absolute inset-0 h-full w-full\"\n      />\n\n      <div className=\"relative z-10 flex flex-1 flex-col justify-between\">\n        {children ?? (\n          <>\n            <div className=\"flex items-center justify-between gap-2\">\n              <span className=\"inline-flex items-center gap-1.5 rounded-full border border-white/15 bg-white/10 px-3 py-1 font-mono text-[11px] font-medium text-white backdrop-blur-md\">\n                <Snowflake className=\"h-3.5 w-3.5 text-sky-200\" />\n                Snowfall · Depth Parallax\n              </span>\n\n              <button\n                type=\"button\"\n                onClick={() => setBlizzard((b) => !b)}\n                className=\"rounded-full border border-white/15 bg-white/10 px-3 py-1 font-mono text-[11px] text-white backdrop-blur-md transition-colors hover:bg-white/20\"\n              >\n                Mode: {blizzard ? \"Winter Gale\" : \"Gentle Flurry\"}\n              </button>\n            </div>\n\n            <div className=\"my-auto max-w-md py-8\">\n              <h3 className=\"text-2xl font-bold tracking-tight text-white sm:text-3xl\">\n                Depth-Sorted Snowfall\n              </h3>\n              <p className=\"mt-2 text-xs leading-relaxed text-white/80 sm:text-sm\">\n                Larger foreground flakes fall faster with higher opacity while\n                distant micro-flakes drift gently on horizontal sine waves.\n              </p>\n            </div>\n\n            <div className=\"font-mono text-[11px] text-white/50\">\n              {flakeCount} Particles · Sine Drift · Z-Depth Velocity\n            </div>\n          </>\n        )}\n      </div>\n    </div>\n  );\n}\n\nexport default Snowfall;\n",
          "type": "registry:ui",
          "target": "components/ui/snowfall.tsx"
        },
        {
          "path": "lib/utils.ts",
          "content": "import { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...inputs: ClassValue[]) {\n  return twMerge(clsx(inputs));\n}\n\nexport async function copyToClipboard(text: string): Promise<boolean> {\n  if (typeof window === \"undefined\") return false;\n\n  try {\n    if (navigator.clipboard && window.isSecureContext) {\n      await navigator.clipboard.writeText(text);\n      return true;\n    }\n\n    const textArea = document.createElement(\"textarea\");\n    textArea.value = text;\n    textArea.style.position = \"fixed\";\n    textArea.style.left = \"-999999px\";\n    textArea.style.top = \"-999999px\";\n    document.body.appendChild(textArea);\n    textArea.focus();\n    textArea.select();\n    const succeeded = document.execCommand(\"copy\");\n    textArea.remove();\n    return succeeded;\n  } catch {\n    return false;\n  }\n}\n",
          "type": "registry:lib",
          "target": "lib/utils.ts"
        }
      ]
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "solar-flare",
      "type": "registry:ui",
      "title": "Solar Flare",
      "author": "Rishabh Bose <https://theb0se.vercel.app/>",
      "description": "Churning solar photosphere and coronal flare background powered by a custom WebGL fragment shader with domain-warped FBM plasma convection cells, magnetic sunspots, and glowing coronal prominences.",
      "dependencies": [
        "lucide-react",
        "clsx",
        "tailwind-merge"
      ],
      "files": [
        {
          "path": "components/ui/solar-flare.tsx",
          "content": "\"use client\";\n\nimport React, { useEffect, useRef, useState } from \"react\";\nimport { Flame, Activity, Sliders, RotateCcw } from \"lucide-react\";\nimport { cn } from \"@/lib/utils\";\n\nexport interface SolarFlareProps {\n  /** Incandescent core plasma color in hex (default: \"#FFF7CC\") */\n  coreColor?: string;\n  /** Primary coronal flare and chromosphere color in hex (default: \"#FF5500\") */\n  flareColor?: string;\n  /** Domain-warping FBM turbulence intensity (default: 1.0) */\n  turbulence?: number;\n  /** Plasma convection and flare animation speed multiplier (default: 1.0) */\n  speed?: number;\n  /** Intensity of coronal mass ejections and magnetic limb loops (default: 1.0) */\n  eruptionIntensity?: number;\n  /** Optional foreground content rendered over the solar surface */\n  children?: React.ReactNode;\n  /** Additional CSS classes for the root container */\n  className?: string;\n}\n\nfunction hexToNormalizedRgb(hex: string): [number, number, number] {\n  const cleaned = hex.replace(\"#\", \"\").trim();\n  const full =\n    cleaned.length === 3\n      ? cleaned\n          .split(\"\")\n          .map((c) => c + c)\n          .join(\"\")\n      : cleaned.padEnd(6, \"0\").slice(0, 6);\n  const num = parseInt(full, 16);\n  if (Number.isNaN(num)) return [1.0, 0.33, 0.0];\n  return [\n    ((num >> 16) & 255) / 255,\n    ((num >> 8) & 255) / 255,\n    (num & 255) / 255,\n  ];\n}\n\nconst VERTEX_SHADER = `\nattribute vec2 a_position;\nvoid main() {\n  gl_Position = vec4(a_position, 0.0, 1.0);\n}\n`;\n\nconst FRAGMENT_SHADER = `\nprecision highp float;\n\nuniform vec2 u_resolution;\nuniform float u_time;\nuniform vec3 u_coreColor;\nuniform vec3 u_flareColor;\nuniform float u_turbulence;\nuniform float u_eruption;\n\nfloat hash21(vec2 p) {\n  p = fract(p * vec2(123.34, 456.21));\n  p += dot(p, p + 45.32);\n  return fract(p.x * p.y);\n}\n\nvec2 hash22(vec2 p) {\n  vec3 p3 = fract(vec3(p.xyx) * vec3(0.1031, 0.1030, 0.0973));\n  p3 += dot(p3, p3.yzx + 33.33);\n  return fract((p3.xx + p3.yz) * p3.zy);\n}\n\nfloat noise(vec2 p) {\n  vec2 i = floor(p);\n  vec2 f = fract(p);\n  vec2 u = f * f * (3.0 - 2.0 * f);\n  float a = hash21(i);\n  float b = hash21(i + vec2(1.0, 0.0));\n  float c = hash21(i + vec2(0.0, 1.0));\n  float d = hash21(i + vec2(1.0, 1.0));\n  return mix(mix(a, b, u.x), mix(c, d, u.x), u.y);\n}\n\nfloat fbm(vec2 p) {\n  float value = 0.0;\n  float amp = 0.5;\n  mat2 rot = mat2(0.8, -0.6, 0.6, 0.8);\n  for (int i = 0; i < 5; i++) {\n    value += amp * noise(p);\n    p = rot * p * 2.03 + vec2(1.7, 9.2);\n    amp *= 0.5;\n  }\n  return value;\n}\n\n// Voronoi cellular distance for realistic solar photosphere granulation\nvec2 voronoiGranules(vec2 x, float time) {\n  vec2 n = floor(x);\n  vec2 f = fract(x);\n  float d1 = 8.0;\n  float d2 = 8.0;\n  for (int j = -1; j <= 1; j++) {\n    for (int i = -1; i <= 1; i++) {\n      vec2 g = vec2(float(i), float(j));\n      vec2 o = hash22(n + g);\n      o = 0.5 + 0.42 * sin(time * 0.85 + 6.2831 * o);\n      vec2 r = g + o - f;\n      float d = dot(r, r);\n      if (d < d1) {\n        d2 = d1;\n        d1 = d;\n      } else if (d < d2) {\n        d2 = d;\n      }\n    }\n  }\n  return vec2(sqrt(d1), sqrt(d2));\n}\n\n// Compute a realistic sunspot with dark umbra, radial penumbra fibrils, and bright surrounding faculae\nvec3 evaluateSunspot(vec2 sphereUv, vec2 spotCenter, float radius, float time) {\n  vec2 delta = sphereUv - spotCenter;\n  float dist = length(delta);\n  float angle = atan(delta.y, delta.x);\n  // Irregular warped boundary\n  float warp = (noise(vec2(angle * 3.0, time * 0.15)) - 0.5) * radius * 0.28;\n  float r = dist + warp;\n\n  // Inner dark magnetic umbra\n  float umbra = 1.0 - smoothstep(radius * 0.28, radius * 0.52, r);\n  // Radial penumbra filaments surrounding umbra\n  float fibrils = 0.5 + 0.5 * sin(angle * 28.0 + noise(delta * 18.0) * 4.5);\n  float penumbraMask = smoothstep(radius * 0.35, radius * 0.55, r) *\n                       (1.0 - smoothstep(radius * 0.65, radius * 1.15, r));\n  float penumbra = penumbraMask * (0.45 + 0.45 * fibrils);\n\n  // Bright magnetic plage / faculae ring outside penumbra\n  float faculae = smoothstep(radius * 0.85, radius * 1.25, r) *\n                  (1.0 - smoothstep(radius * 1.25, radius * 2.1, r)) *\n                  fbm(sphereUv * 6.0);\n\n  return vec3(umbra, penumbra, faculae);\n}\n\nvoid main() {\n  vec2 uv = (gl_FragCoord.xy - 0.5 * u_resolution.xy) / min(u_resolution.x, u_resolution.y);\n\n  // Position solar sphere slightly below center for dramatic coronal prominence headroom\n  vec2 center = vec2(0.0, -0.05);\n  vec2 p = uv - center;\n  float r = length(p);\n  float sunRadius = 0.37;\n  float angle = atan(p.y, p.x);\n\n  vec3 col = vec3(0.008, 0.009, 0.018);\n\n  if (r < sunRadius) {\n    // 3D Spherical normal projection of the solar photosphere\n    float z = sqrt(max(0.0, sunRadius * sunRadius - r * r));\n    vec3 normal = normalize(vec3(p.x, p.y, z));\n\n    // Spherical latitude-longitude coordinates with differential solar rotation\n    float lon = atan(normal.x, normal.z) + u_time * 0.095;\n    float lat = asin(clamp(normal.y, -1.0, 1.0));\n    vec2 sphereUv = vec2(lon, lat) * 3.2;\n\n    // 1. Domain-Warped FBM + Voronoi Cellular Solar Granulation\n    vec2 q = vec2(\n      fbm(sphereUv + vec2(0.0, u_time * 0.2)),\n      fbm(sphereUv + vec2(5.2, 1.3 - u_time * 0.16))\n    );\n    vec2 warpedUv = sphereUv + 1.35 * u_turbulence * (q - 0.5);\n\n    vec2 vor = voronoiGranules(warpedUv * 4.2, u_time);\n    // Bright convex granule centers separated by darker intergranular convection lanes\n    float granuleCell = smoothstep(0.0, 0.22, vor.y - vor.x);\n    float plasmaFbm = fbm(warpedUv * 2.4 + vec2(u_time * 0.12, -u_time * 0.08));\n    float convection = mix(granuleCell, plasmaFbm, 0.52);\n\n    // 2. Active Region Magnetic Sunspots (Umbra + Radial Penumbra Fibrils + Bright Faculae)\n    vec3 spot1 = evaluateSunspot(warpedUv, vec2(0.45 + u_time * 0.095, 0.28), 0.42, u_time);\n    vec3 spot2 = evaluateSunspot(warpedUv, vec2(-0.85 + u_time * 0.095, -0.35), 0.32, u_time);\n    vec3 spot3 = evaluateSunspot(warpedUv, vec2(1.65 + u_time * 0.095, -0.18), 0.36, u_time);\n\n    float totalUmbra = clamp(spot1.x + spot2.x + spot3.x, 0.0, 1.0);\n    float totalPenumbra = clamp(spot1.y + spot2.y + spot3.y, 0.0, 1.0);\n    float totalFaculae = clamp(spot1.z + spot2.z + spot3.z, 0.0, 1.0);\n\n    // 3. Physical Eddington Spherical Limb Darkening & Chromospheric Rim Spicules\n    float mu = clamp(normal.z, 0.0, 1.0);\n    float limbDarkening = 0.32 + 0.68 * pow(mu, 0.48);\n    float limbRimBoost = pow(1.0 - mu, 2.75);\n\n    // Photosphere temperature color ramp\n    vec3 deepChromosphere = u_flareColor * 0.22;\n    vec3 midPhotosphere = u_flareColor * 1.05;\n    vec3 brightGranule = u_coreColor * 1.25;\n\n    vec3 surfaceCol = mix(deepChromosphere, midPhotosphere, smoothstep(0.12, 0.58, convection));\n    surfaceCol = mix(surfaceCol, brightGranule, smoothstep(0.55, 0.92, convection * limbDarkening));\n\n    // Apply physical limb darkening across the disc\n    surfaceCol *= limbDarkening;\n\n    // Brighten magnetic faculae networks (especially visible near the solar limb)\n    float faculaeBoost = totalFaculae * (0.65 + 1.15 * (1.0 - mu));\n    surfaceCol += u_coreColor * faculaeBoost * 0.85;\n\n    // Darken radial penumbra filaments & deep magnetic umbra cores\n    surfaceCol = mix(surfaceCol, u_flareColor * 0.32, totalPenumbra * 0.72);\n    surfaceCol = mix(surfaceCol, vec3(0.03, 0.01, 0.005), totalUmbra * 0.92);\n\n    // Incandescent chromospheric spicules & magnetic filaments right along the limb edge\n    float spiculeNoise = fbm(vec2(angle * 24.0, u_time * 0.45));\n    surfaceCol += mix(u_flareColor, u_coreColor, 0.65) * limbRimBoost * (0.45 + 0.55 * spiculeNoise);\n\n    col = surfaceCol;\n  } else {\n    // 4. Exterior Coronal Magnetic Loops, Arched Prominences & Solar Wind Streamers\n    float distFromLimb = r - sunRadius;\n\n    // Arched magnetic flux loop geometry around the solar limb\n    float loopFreq = angle * 5.0 + sin(distFromLimb * 18.0 - u_time * 0.9) * 0.45;\n    float archEnvelope = pow(max(0.0, sin(loopFreq)), 3.0) * exp(-distFromLimb * 11.5);\n    // Hollow magnetic arch core (bright along the loop arch, darker inside the arch)\n    float archRing = exp(-pow((distFromLimb - 0.038 * (0.6 + 0.4 * sin(angle * 3.0 + u_time * 0.3))) * 28.0, 2.0));\n    float magneticLoop = archEnvelope * (0.45 + 0.95 * archRing);\n\n    // Turbulent plasma eruptions & coronal mass ejection plumes\n    vec2 coronaCoord = vec2(angle * 3.8, distFromLimb * 8.5 - u_time * 0.62);\n    float loopNoise = fbm(coronaCoord * u_turbulence);\n    float loopArch = fbm(vec2(angle * 7.5 + sin(distFromLimb * 15.0), distFromLimb * 5.8 - u_time * 0.42));\n\n    float prominence = (pow(max(0.0, loopNoise * loopArch * 1.72), 1.75) + magneticLoop * loopNoise * 1.4) * u_eruption;\n    float falloff = exp(-distFromLimb * 6.8);\n    float innerChromosphereRim = exp(-distFromLimb * 38.0);\n\n    // Fine radial coronal helmet streamers extending into deep space\n    float streamerNoise = fbm(vec2(angle * 16.0, distFromLimb * 1.8 - u_time * 0.2));\n    float rays = pow(streamerNoise, 1.6) * exp(-distFromLimb * 3.6) * 0.55 * u_eruption;\n\n    vec3 coronaGlow = u_flareColor * (falloff * 0.88 + prominence * falloff * 2.85 + rays);\n    coronaGlow += u_coreColor * (innerChromosphereRim * 1.15 + prominence * exp(-distFromLimb * 13.0) * 1.45);\n\n    col += coronaGlow;\n  }\n\n  // HDR ACES-inspired filmic tone mapping & anti-banding dither\n  col = (col * (2.51 * col + 0.03)) / (col * (2.43 * col + 0.59) + 0.14);\n  col = pow(clamp(col, 0.0, 1.0), vec3(0.92));\n  col += (hash21(gl_FragCoord.xy + fract(u_time)) - 0.5) / 255.0;\n\n  gl_FragColor = vec4(col, 1.0);\n}\n`;\n\nconst SOLAR_PRESETS = [\n  {\n    name: \"G-Type Photosphere\",\n    coreColor: \"#FFF7CC\",\n    flareColor: \"#FF5500\",\n    turbulence: 1.0,\n    eruptionIntensity: 1.0,\n  },\n  {\n    name: \"Blue Hypergiant\",\n    coreColor: \"#E0F2FE\",\n    flareColor: \"#0284C7\",\n    turbulence: 1.35,\n    eruptionIntensity: 1.4,\n  },\n  {\n    name: \"Red Magnetar\",\n    coreColor: \"#FECDD3\",\n    flareColor: \"#E11D48\",\n    turbulence: 1.5,\n    eruptionIntensity: 1.65,\n  },\n] as const;\n\nexport function SolarFlare({\n  coreColor = \"#FFF7CC\",\n  flareColor = \"#FF5500\",\n  turbulence = 1.0,\n  speed = 1.0,\n  eruptionIntensity = 1.0,\n  children,\n  className,\n}: SolarFlareProps) {\n  const containerRef = useRef<HTMLDivElement>(null);\n  const canvasRef = useRef<HTMLCanvasElement>(null);\n\n  const [activeCore, setActiveCore] = useState(coreColor);\n  const [activeFlare, setActiveFlare] = useState(flareColor);\n  const [activeTurb, setActiveTurb] = useState(turbulence);\n  const [activeSpeed, setActiveSpeed] = useState(speed);\n  const [activeEruption, setActiveEruption] = useState(eruptionIntensity);\n  useEffect(() => {\n    setActiveCore(coreColor);\n  }, [coreColor]);\n  useEffect(() => {\n    setActiveFlare(flareColor);\n  }, [flareColor]);\n  useEffect(() => {\n    setActiveTurb(turbulence);\n  }, [turbulence]);\n  useEffect(() => {\n    setActiveSpeed(speed);\n  }, [speed]);\n  useEffect(() => {\n    setActiveEruption(eruptionIntensity);\n  }, [eruptionIntensity]);\n\n  const paramsRef = useRef({\n    core: hexToNormalizedRgb(activeCore),\n    flare: hexToNormalizedRgb(activeFlare),\n    turbulence: activeTurb,\n    speed: activeSpeed,\n    eruption: activeEruption,\n  });\n\n  useEffect(() => {\n    paramsRef.current = {\n      core: hexToNormalizedRgb(activeCore),\n      flare: hexToNormalizedRgb(activeFlare),\n      turbulence: activeTurb,\n      speed: activeSpeed,\n      eruption: activeEruption,\n    };\n  }, [activeCore, activeFlare, activeTurb, activeSpeed, activeEruption]);\n\n  useEffect(() => {\n    const container = containerRef.current;\n    const canvas = canvasRef.current;\n    if (!container || !canvas) return;\n\n    const gl = canvas.getContext(\"webgl\", {\n      alpha: false,\n      antialias: false,\n      preserveDrawingBuffer: false,\n    });\n\n    if (!gl) return;\n\n    const compileShader = (type: number, source: string) => {\n      const shader = gl.createShader(type);\n      if (!shader) return null;\n      gl.shaderSource(shader, source);\n      gl.compileShader(shader);\n      if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {\n        gl.deleteShader(shader);\n        return null;\n      }\n      return shader;\n    };\n\n    const vs = compileShader(gl.VERTEX_SHADER, VERTEX_SHADER);\n    const fs = compileShader(gl.FRAGMENT_SHADER, FRAGMENT_SHADER);\n    if (!vs || !fs) return;\n\n    const program = gl.createProgram();\n    if (!program) return;\n    gl.attachShader(program, vs);\n    gl.attachShader(program, fs);\n    gl.linkProgram(program);\n\n    if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {\n      gl.deleteProgram(program);\n      return;\n    }\n\n    gl.useProgram(program);\n\n    const buffer = gl.createBuffer();\n    gl.bindBuffer(gl.ARRAY_BUFFER, buffer);\n    gl.bufferData(\n      gl.ARRAY_BUFFER,\n      new Float32Array([-1, -1, 1, -1, -1, 1, -1, 1, 1, -1, 1, 1]),\n      gl.STATIC_DRAW\n    );\n\n    const posLoc = gl.getAttribLocation(program, \"a_position\");\n    gl.enableVertexAttribArray(posLoc);\n    gl.vertexAttribPointer(posLoc, 2, gl.FLOAT, false, 0, 0);\n\n    const uResolution = gl.getUniformLocation(program, \"u_resolution\");\n    const uTime = gl.getUniformLocation(program, \"u_time\");\n    const uCoreColor = gl.getUniformLocation(program, \"u_coreColor\");\n    const uFlareColor = gl.getUniformLocation(program, \"u_flareColor\");\n    const uTurbulence = gl.getUniformLocation(program, \"u_turbulence\");\n    const uEruption = gl.getUniformLocation(program, \"u_eruption\");\n\n    const resize = () => {\n      if (!container || !canvas) return;\n      const dpr = Math.min(window.devicePixelRatio || 1, 1.75);\n      const w = Math.max(1, Math.floor((container.clientWidth || 800) * dpr));\n      const h = Math.max(1, Math.floor((container.clientHeight || 520) * dpr));\n      canvas.width = w;\n      canvas.height = h;\n      gl.viewport(0, 0, w, h);\n    };\n\n    resize();\n    const observer = new ResizeObserver(resize);\n    observer.observe(container);\n\n    let rafId = 0;\n    let accumTime = 0;\n    let lastNow = performance.now();\n\n    const render = (now: number) => {\n      const dt = Math.min(0.1, (now - lastNow) * 0.001);\n      lastNow = now;\n      const p = paramsRef.current;\n      accumTime += dt * p.speed;\n\n      gl.uniform2f(uResolution, canvas.width, canvas.height);\n      gl.uniform1f(uTime, accumTime);\n      gl.uniform3f(uCoreColor, p.core[0], p.core[1], p.core[2]);\n      gl.uniform3f(uFlareColor, p.flare[0], p.flare[1], p.flare[2]);\n      gl.uniform1f(uTurbulence, p.turbulence);\n      gl.uniform1f(uEruption, p.eruption);\n\n      gl.drawArrays(gl.TRIANGLES, 0, 6);\n      rafId = requestAnimationFrame(render);\n    };\n\n    rafId = requestAnimationFrame(render);\n\n    return () => {\n      cancelAnimationFrame(rafId);\n      observer.disconnect();\n      gl.deleteBuffer(buffer);\n      gl.deleteProgram(program);\n      gl.deleteShader(vs);\n      gl.deleteShader(fs);\n    };\n  }, []);\n\n  return (\n    <div\n      ref={containerRef}\n      data-fullscreen-scroll\n      className={cn(\n        \"relative w-full min-h-[520px] overflow-hidden rounded-2xl bg-[#040308] text-white select-none\",\n        className\n      )}\n    >\n      <canvas\n        ref={canvasRef}\n        aria-hidden=\"true\"\n        className=\"pointer-events-none absolute inset-0 h-full w-full\"\n      />\n\n      {children && (\n        <div className=\"relative z-10 flex min-h-[520px] w-full flex-col\">\n          {children}\n        </div>\n      )}\n    </div>\n  );\n}\n\nexport default SolarFlare;\n",
          "type": "registry:ui",
          "target": "components/ui/solar-flare.tsx"
        },
        {
          "path": "lib/utils.ts",
          "content": "import { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...inputs: ClassValue[]) {\n  return twMerge(clsx(inputs));\n}\n\nexport async function copyToClipboard(text: string): Promise<boolean> {\n  if (typeof window === \"undefined\") return false;\n\n  try {\n    if (navigator.clipboard && window.isSecureContext) {\n      await navigator.clipboard.writeText(text);\n      return true;\n    }\n\n    const textArea = document.createElement(\"textarea\");\n    textArea.value = text;\n    textArea.style.position = \"fixed\";\n    textArea.style.left = \"-999999px\";\n    textArea.style.top = \"-999999px\";\n    document.body.appendChild(textArea);\n    textArea.focus();\n    textArea.select();\n    const succeeded = document.execCommand(\"copy\");\n    textArea.remove();\n    return succeeded;\n  } catch {\n    return false;\n  }\n}\n",
          "type": "registry:lib",
          "target": "lib/utils.ts"
        }
      ]
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "split-button",
      "type": "registry:ui",
      "title": "Split Button",
      "author": "Rishabh Bose <https://theb0se.vercel.app/>",
      "description": "A primary action fused with a chevron trigger that reveals related actions in a spring-timed dropdown, sharing a single pill silhouette.",
      "dependencies": [
        "framer-motion",
        "lucide-react",
        "clsx",
        "tailwind-merge"
      ],
      "files": [
        {
          "path": "components/ui/split-button.tsx",
          "content": "'use client';\n\nimport React, {\n  useCallback,\n  useEffect,\n  useLayoutEffect,\n  useRef,\n  useState,\n} from 'react';\nimport { AnimatePresence, motion, useReducedMotion } from 'framer-motion';\nimport { ChevronDown } from 'lucide-react';\nimport { cn } from '@/lib/utils';\n\n// -----------------------------------------------------------------------------\n// Motion\n// -----------------------------------------------------------------------------\n\nconst springSnappy = {\n  type: 'spring' as const,\n  stiffness: 400,\n  damping: 25,\n  mass: 0.5,\n};\n\n// -----------------------------------------------------------------------------\n// Types\n// -----------------------------------------------------------------------------\n\nexport type SplitButtonSize = 'sm' | 'md' | 'lg';\n\nexport interface SplitButtonOption {\n  value: string;\n  label: string;\n  icon?: React.ReactNode;\n  disabled?: boolean;\n  onSelect?: () => void;\n}\n\nexport interface SplitButtonProps\n  extends Omit<React.ButtonHTMLAttributes<HTMLButtonElement>, 'onClick'> {\n  /** Label for the primary (left) action. */\n  label?: string;\n\n  /** Called when the primary action is pressed. */\n  onClick?: () => void;\n\n  /** Dropdown options revealed by the chevron trigger. */\n  options?: SplitButtonOption[];\n\n  size?: SplitButtonSize;\n\n  /**\n   * `primary` matches the light accent CTA.\n   * `secondary` matches the raised control style.\n   */\n  variant?: 'primary' | 'secondary' | 'danger' | 'info';\n\n  disabled?: boolean;\n  className?: string;\n}\n\n// -----------------------------------------------------------------------------\n// Styles\n// -----------------------------------------------------------------------------\n\nconst SIZE_STYLES: Record<\n  SplitButtonSize,\n  {\n    primary: string;\n    chevron: string;\n    radius: string;\n    menuText: string;\n  }\n> = {\n  sm: {\n    primary: 'gap-1.5 px-3.5 py-1.5 text-xs',\n    chevron: 'px-2 py-1.5',\n    radius: 'rounded-[8px]',\n    menuText: 'text-xs',\n  },\n\n  md: {\n    primary: 'gap-2 px-5 py-2.5 text-sm',\n    chevron: 'px-2.5 py-2.5',\n    radius: 'rounded-[8px]',\n    menuText: 'text-sm',\n  },\n\n  lg: {\n    primary: 'gap-2.5 px-7 py-3.5 text-base',\n    chevron: 'px-3 py-3.5',\n    radius: 'rounded-[10px]',\n    menuText: 'text-sm',\n  },\n};\n\nconst TRANSITION =\n  'transition-[background-color,border-color,box-shadow,transform] duration-200 ease-out ' +\n  'active:translate-y-0 active:scale-[0.98]';\n\nconst VARIANT_STYLES: Record<'primary' | 'secondary' | 'danger' | 'info', string> = {\n  primary:\n    // light: dark pill on a light canvas · dark: light pill on a dark canvas (mirrors your existing button)\n    'bg-[#151515] text-[#F5F5F5] hover:bg-black ' +\n    'dark:bg-[#F5F5F5] dark:text-[#050505] dark:hover:bg-white ' +\n    'shadow-[0_1px_2px_rgba(0,0,0,0.08)] hover:shadow-[0_8px_20px_-6px_rgba(0,0,0,0.25)] ' +\n    'dark:shadow-[0_0_20px_-3px_rgba(255,255,255,0.15)] dark:hover:shadow-[0_0_28px_-4px_rgba(255,255,255,0.28)] ' +\n    TRANSITION,\n\n  secondary:\n    'border border-neutral-200 bg-neutral-100 text-black hover:border-neutral-300 hover:bg-neutral-200 ' +\n    'dark:border-[#262626] dark:bg-[#141414] dark:text-white ' +\n    'dark:hover:border-neutral-600 dark:hover:bg-[#1F1F1F] ' +\n    'shadow-[0_1px_2px_rgba(0,0,0,0.04)] hover:shadow-[0_6px_16px_-8px_rgba(0,0,0,0.15)] ' +\n    'dark:shadow-none dark:hover:shadow-[0_6px_16px_-8px_rgba(0,0,0,0.5)] ' +\n    TRANSITION,\n\n  danger:\n    'bg-[#DC2626] text-white hover:bg-[#E23F3F] ' +\n    'dark:bg-[#DC2626]/90 dark:hover:bg-[#EF4444] ' +\n    'shadow-[0_0_0_1px_rgba(220,38,38,0.15)] hover:shadow-[0_8px_20px_-6px_rgba(220,38,38,0.4)] ' +\n    'dark:shadow-[0_0_18px_-4px_rgba(220,38,38,0.35)] dark:hover:shadow-[0_0_26px_-6px_rgba(220,38,38,0.5)] ' +\n    TRANSITION,\n\n  info:\n    'bg-[#3B82F6] text-white hover:bg-[#529BF8] ' +\n    'dark:bg-[#3B82F6]/90 dark:hover:bg-[#60A5FA] ' +\n    'shadow-[0_0_0_1px_rgba(59,130,246,0.15)] hover:shadow-[0_8px_20px_-6px_rgba(59,130,246,0.4)] ' +\n    'dark:shadow-[0_0_18px_-4px_rgba(59,130,246,0.35)] dark:hover:shadow-[0_0_26px_-6px_rgba(59,130,246,0.5)] ' +\n    TRANSITION,\n};\n\n// -----------------------------------------------------------------------------\n// Component\n// -----------------------------------------------------------------------------\n\n/**\n * SplitButton\n *\n * A primary action fused with a secondary chevron trigger.\n *\n * Features:\n * - Primary + dropdown action split\n * - Keyboard accessible menu navigation\n * - Outside-click dismissal\n * - Escape-to-close\n * - Home / End navigation\n * - Viewport-aware dropdown placement\n * - Reduced-motion support\n * - Disabled options\n * - Framer Motion transitions\n */\nconst DEFAULT_SPLIT_OPTIONS: SplitButtonOption[] = [\n  { value: 'preview', label: 'Deploy Preview' },\n  { value: 'staging', label: 'Promote to Staging' },\n  { value: 'rollback', label: 'Rollback Production' },\n];\n\nexport function SplitButton({\n  label = 'Deploy Release',\n  onClick,\n  options = DEFAULT_SPLIT_OPTIONS,\n  size = 'md',\n  variant = 'primary',\n  disabled = false,\n  className,\n  ...props\n}: SplitButtonProps) {\n  const reduceMotion = useReducedMotion();\n\n  const [open, setOpen] = useState(false);\n  const [placement, setPlacement] = useState<'bottom' | 'top'>('bottom');\n  const [activeIndex, setActiveIndex] = useState(0);\n\n  const rootRef = useRef<HTMLDivElement>(null);\n  const chevronRef = useRef<HTMLButtonElement>(null);\n  const menuRef = useRef<HTMLDivElement>(null);\n\n  const sizeStyles = SIZE_STYLES[size];\n\n  // ---------------------------------------------------------------------------\n  // Derived state\n  // ---------------------------------------------------------------------------\n\n  const enabledIndices = options.reduce<number[]>((indices, option, index) => {\n    if (!option.disabled) {\n      indices.push(index);\n    }\n\n    return indices;\n  }, []);\n\n  const menuTransition = reduceMotion\n    ? { duration: 0 }\n    : springSnappy;\n\n  // ---------------------------------------------------------------------------\n  // Menu helpers\n  // ---------------------------------------------------------------------------\n\n  const closeMenu = useCallback(() => {\n    setOpen(false);\n    chevronRef.current?.focus();\n  }, []);\n\n  const selectOption = useCallback(\n    (option: SplitButtonOption) => {\n      if (option.disabled) {\n        return;\n      }\n\n      option.onSelect?.();\n      closeMenu();\n    },\n    [closeMenu],\n  );\n\n  // ---------------------------------------------------------------------------\n  // Outside click\n  // ---------------------------------------------------------------------------\n\n  useEffect(() => {\n    if (!open) {\n      return;\n    }\n\n    const handlePointerDown = (event: PointerEvent) => {\n      const target = event.target as Node;\n\n      if (!rootRef.current?.contains(target)) {\n        setOpen(false);\n      }\n    };\n\n    document.addEventListener('pointerdown', handlePointerDown);\n\n    return () => {\n      document.removeEventListener('pointerdown', handlePointerDown);\n    };\n  }, [open]);\n\n  // ---------------------------------------------------------------------------\n  // Viewport-aware placement\n  // ---------------------------------------------------------------------------\n\n  useLayoutEffect(() => {\n    if (!open || !chevronRef.current) {\n      return;\n    }\n\n    const triggerRect = chevronRef.current.getBoundingClientRect();\n\n    // Approximate menu height:\n    // option height + menu vertical padding.\n    const estimatedMenuHeight = options.length * 36 + 16;\n\n    const spaceBelow = window.innerHeight - triggerRect.bottom;\n    const spaceAbove = triggerRect.top;\n\n    const shouldFlip =\n      spaceBelow < estimatedMenuHeight &&\n      spaceAbove > estimatedMenuHeight;\n\n    setPlacement(shouldFlip ? 'top' : 'bottom');\n  }, [open, options.length]);\n\n  // ---------------------------------------------------------------------------\n  // Reset active option when opening\n  // ---------------------------------------------------------------------------\n\n  useEffect(() => {\n    if (!open) {\n      return;\n    }\n\n    setActiveIndex(enabledIndices[0] ?? 0);\n  }, [open, enabledIndices]);\n\n  // ---------------------------------------------------------------------------\n  // Focus menu when opened\n  // ---------------------------------------------------------------------------\n\n  useEffect(() => {\n    if (!open) {\n      return;\n    }\n\n    requestAnimationFrame(() => {\n      menuRef.current?.focus();\n    });\n  }, [open]);\n\n  // ---------------------------------------------------------------------------\n  // Keyboard navigation\n  // ---------------------------------------------------------------------------\n\n  const handleMenuKeyDown = useCallback(\n    (event: React.KeyboardEvent<HTMLDivElement>) => {\n      if (!enabledIndices.length) {\n        if (event.key === 'Escape' || event.key === 'Tab') {\n          event.preventDefault();\n\n          if (event.key === 'Escape') {\n            closeMenu();\n          } else {\n            setOpen(false);\n          }\n        }\n\n        return;\n      }\n\n      const currentPosition = enabledIndices.indexOf(activeIndex);\n\n      switch (event.key) {\n        case 'ArrowDown': {\n          event.preventDefault();\n\n          const nextPosition =\n            currentPosition < 0\n              ? 0\n              : (currentPosition + 1) % enabledIndices.length;\n\n          setActiveIndex(enabledIndices[nextPosition]);\n          break;\n        }\n\n        case 'ArrowUp': {\n          event.preventDefault();\n\n          const previousPosition =\n            currentPosition < 0\n              ? enabledIndices.length - 1\n              : (currentPosition - 1 + enabledIndices.length) %\n                enabledIndices.length;\n\n          setActiveIndex(enabledIndices[previousPosition]);\n          break;\n        }\n\n        case 'Home': {\n          event.preventDefault();\n          setActiveIndex(enabledIndices[0]);\n          break;\n        }\n\n        case 'End': {\n          event.preventDefault();\n          setActiveIndex(enabledIndices[enabledIndices.length - 1]);\n          break;\n        }\n\n        case 'Enter':\n        case ' ': {\n          event.preventDefault();\n\n          const activeOption = options[activeIndex];\n\n          if (activeOption) {\n            selectOption(activeOption);\n          }\n\n          break;\n        }\n\n        case 'Escape': {\n          event.preventDefault();\n          closeMenu();\n          break;\n        }\n\n        case 'Tab': {\n          setOpen(false);\n          break;\n        }\n\n        default:\n          break;\n      }\n    },\n    [\n      activeIndex,\n      closeMenu,\n      enabledIndices,\n      options,\n      selectOption,\n    ],\n  );\n\n  // ---------------------------------------------------------------------------\n  // Render\n  // ---------------------------------------------------------------------------\n\n  return (\n    <div\n      ref={rootRef}\n      className={cn('relative inline-flex', className)}\n    >\n      {/* ---------------------------------------------------------------------\n          Button group\n      --------------------------------------------------------------------- */}\n\n      <div\n        className={cn(\n          'inline-flex overflow-hidden',\n          sizeStyles.radius,\n          disabled && 'pointer-events-none opacity-30',\n        )}\n      >\n        {/* -------------------------------------------------------------------\n            Primary action\n        ------------------------------------------------------------------- */}\n\n        <button\n          type=\"button\"\n          onClick={onClick}\n          disabled={disabled}\n          className={cn(\n            'relative inline-flex items-center justify-center',\n            'select-none font-medium',\n            'cursor-pointer',\n            'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-black dark:focus-visible:ring-white',\n            'transition-colors duration-200',\n            'disabled:cursor-not-allowed',\n            sizeStyles.primary,\n            VARIANT_STYLES[variant],\n          )}\n          {...props}\n        >\n          {label}\n        </button>\n\n        {/* -------------------------------------------------------------------\n            Divider\n        ------------------------------------------------------------------- */}\n\n        <span\n          aria-hidden=\"true\"\n          className={cn(\n            'my-1.5 w-px self-stretch',\n            variant === 'primary'\n              ? 'bg-white/20 dark:bg-black/15'\n              : 'bg-neutral-300 dark:bg-[#262626]',\n          )}\n        />\n\n        {/* -------------------------------------------------------------------\n            Dropdown trigger\n        ------------------------------------------------------------------- */}\n\n        <button\n          ref={chevronRef}\n          type=\"button\"\n          aria-haspopup=\"menu\"\n          aria-expanded={open}\n          aria-label={`More ${label} options`}\n          disabled={disabled}\n          onClick={() => setOpen((previous) => !previous)}\n          className={cn(\n            'relative inline-flex items-center justify-center',\n            'select-none',\n            'cursor-pointer',\n            'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-black dark:focus-visible:ring-white',\n            'transition-colors duration-200',\n            'disabled:cursor-not-allowed',\n            sizeStyles.chevron,\n            VARIANT_STYLES[variant],\n          )}\n        >\n          <motion.span\n            aria-hidden=\"true\"\n            animate={{\n              rotate: open ? 180 : 0,\n            }}\n            transition={menuTransition}\n            className=\"flex items-center justify-center\"\n          >\n            <ChevronDown\n              className=\"h-4 w-4\"\n              strokeWidth={2}\n            />\n          </motion.span>\n        </button>\n      </div>\n\n      {/* -----------------------------------------------------------------------\n          Dropdown menu\n      ----------------------------------------------------------------------- */}\n\n      <AnimatePresence>\n        {open && (\n          <motion.div\n            ref={menuRef}\n            role=\"menu\"\n            aria-label={`${label} options`}\n            tabIndex={-1}\n            onKeyDown={handleMenuKeyDown}\n            initial={{\n              opacity: 0,\n              scale: 0.96,\n              y: placement === 'bottom' ? -4 : 4,\n            }}\n            animate={{\n              opacity: 1,\n              scale: 1,\n              y: 0,\n            }}\n            exit={{\n              opacity: 0,\n              scale: 0.97,\n              transition: reduceMotion\n                ? { duration: 0 }\n                : { duration: 0.12 },\n            }}\n            transition={menuTransition}\n            className={cn(\n              'absolute right-0 z-30',\n              'min-w-[11rem]',\n              'rounded-xl',\n              'border border-neutral-200 dark:border-[#262626]',\n              'bg-white dark:bg-[#0A0A0A]',\n              'p-1',\n              'shadow-xl',\n              'origin-top-right',\n              placement === 'bottom'\n                ? 'top-[calc(100%+8px)]'\n                : 'bottom-[calc(100%+8px)]',\n            )}\n          >\n            {options.map((option, index) => {\n              const isActive =\n                index === activeIndex && !option.disabled;\n\n              return (\n                <button\n                  key={option.value}\n                  type=\"button\"\n                  role=\"menuitem\"\n                  disabled={option.disabled}\n                  aria-disabled={\n                    option.disabled || undefined\n                  }\n                  onClick={() => selectOption(option)}\n                  onMouseEnter={() => {\n                    if (!option.disabled) {\n                      setActiveIndex(index);\n                    }\n                  }}\n                  className={cn(\n                    'flex w-full items-center gap-2',\n                    'rounded-lg',\n                    'px-3 py-2',\n                    'text-left',\n                    'font-medium',\n                    'select-none',\n                    'transition-colors duration-150',\n                    sizeStyles.menuText,\n\n                    option.disabled\n                      ? [\n                          'cursor-not-allowed',\n                          'text-neutral-400 dark:text-neutral-600',\n                        ]\n                      : [\n                          'cursor-pointer',\n                          'text-neutral-600 dark:text-neutral-400',\n                          'hover:bg-neutral-100 dark:hover:bg-[#141414]',\n                          'hover:text-black dark:hover:text-white',\n                        ],\n\n                    isActive && [\n                      'bg-neutral-100 dark:bg-[#141414]',\n                      'text-black dark:text-white',\n                    ],\n                  )}\n                >\n                  {option.icon && (\n                    <span\n                      aria-hidden=\"true\"\n                      className={cn(\n                        'flex shrink-0 items-center justify-center',\n                        '[&_svg]:h-3.5',\n                        '[&_svg]:w-3.5',\n                      )}\n                    >\n                      {option.icon}\n                    </span>\n                  )}\n\n                  <span className=\"min-w-0 truncate\">\n                    {option.label}\n                  </span>\n                </button>\n              );\n            })}\n          </motion.div>\n        )}\n      </AnimatePresence>\n    </div>\n  );\n}\n\nexport default SplitButton;",
          "type": "registry:ui",
          "target": "components/ui/split-button.tsx"
        },
        {
          "path": "lib/utils.ts",
          "content": "import { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...inputs: ClassValue[]) {\n  return twMerge(clsx(inputs));\n}\n\nexport async function copyToClipboard(text: string): Promise<boolean> {\n  if (typeof window === \"undefined\") return false;\n\n  try {\n    if (navigator.clipboard && window.isSecureContext) {\n      await navigator.clipboard.writeText(text);\n      return true;\n    }\n\n    const textArea = document.createElement(\"textarea\");\n    textArea.value = text;\n    textArea.style.position = \"fixed\";\n    textArea.style.left = \"-999999px\";\n    textArea.style.top = \"-999999px\";\n    document.body.appendChild(textArea);\n    textArea.focus();\n    textArea.select();\n    const succeeded = document.execCommand(\"copy\");\n    textArea.remove();\n    return succeeded;\n  } catch {\n    return false;\n  }\n}\n",
          "type": "registry:lib",
          "target": "lib/utils.ts"
        }
      ]
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "split-flap-text",
      "type": "registry:ui",
      "title": "Split Flap Text",
      "author": "Rishabh Bose <https://theb0se.vercel.app/>",
      "description": "Mechanical departure-board split-flap display that cycles character tiles with staggered 3D rotateX spring hinges.",
      "dependencies": [
        "framer-motion",
        "lucide-react",
        "clsx",
        "tailwind-merge"
      ],
      "files": [
        {
          "path": "components/ui/split-flap-text.tsx",
          "content": "\"use client\";\n\nimport React, { useState } from \"react\";\nimport { AnimatePresence, motion, useReducedMotion } from \"framer-motion\";\nimport { RotateCw } from \"lucide-react\";\nimport { cn } from \"@/lib/utils\";\n\nexport interface SplitFlapTextProps {\n  /** Array of preset words of similar length to cycle through. */\n  words?: string[];\n  /** Spring stiffness coefficient for 3D flap rotation. Default: 380 */\n  stiffness?: number;\n  /** Spring damping coefficient for 3D flap rotation. Default: 24 */\n  damping?: number;\n  className?: string;\n}\n\nconst DEFAULT_WORDS = [\"KINETIC\", \"PHYSICS\", \"SPRINGS\", \"MINIMAL\"];\n\nexport function SplitFlapText({\n  words = DEFAULT_WORDS,\n  stiffness = 380,\n  damping = 24,\n  className,\n}: SplitFlapTextProps) {\n  const shouldReduceMotion = useReducedMotion() ?? false;\n  const [wordIndex, setWordIndex] = useState(0);\n\n  const activeWord = words[wordIndex % words.length] || \"KINETIC\";\n  const maxLen = Math.max(...words.map((w) => w.length), activeWord.length);\n  const paddedChars = activeWord.padEnd(maxLen, \" \").split(\"\");\n\n  const cycleNext = () => {\n    setWordIndex((prev) => (prev + 1) % words.length);\n  };\n\n  return (\n    <div\n      className={cn(\n        \"inline-flex flex-col items-center gap-3 rounded-2xl border border-neutral-200 bg-white p-5 shadow-sm dark:border-[#222222] dark:bg-[#0A0A0A]\",\n        className\n      )}\n    >\n      {/* Screen-reader live readout */}\n      <span className=\"sr-only\" role=\"status\" aria-live=\"polite\">\n        {activeWord}\n      </span>\n\n      <button\n        type=\"button\"\n        onClick={cycleNext}\n        aria-label={`Split-flap display showing ${activeWord}. Click to flip to next word.`}\n        style={{ perspective: \"900px\" }}\n        className=\"group flex items-center gap-1.5 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-black dark:focus-visible:ring-white\"\n      >\n        {paddedChars.map((char, idx) => (\n          <div\n            key={idx}\n            aria-hidden=\"true\"\n            className=\"relative flex h-12 w-9 items-center justify-center overflow-hidden rounded-xl border border-neutral-800 bg-neutral-950 font-mono text-lg font-bold text-white shadow-inner dark:border-neutral-200 dark:bg-white dark:text-black\"\n          >\n            {/* Mechanical Horizontal Split Hinge Line */}\n            <div className=\"pointer-events-none absolute inset-x-0 top-1/2 z-20 h-[1px] bg-black/40 dark:bg-neutral-300\" />\n\n            <AnimatePresence mode=\"popLayout\" initial={false}>\n              <motion.span\n                key={`${wordIndex}-${idx}-${char}`}\n                initial={\n                  shouldReduceMotion\n                    ? { opacity: 0 }\n                    : { rotateX: -90, opacity: 0, y: -6 }\n                }\n                animate={{ rotateX: 0, opacity: 1, y: 0 }}\n                exit={\n                  shouldReduceMotion\n                    ? { opacity: 0 }\n                    : { rotateX: 90, opacity: 0, y: 6 }\n                }\n                transition={\n                  shouldReduceMotion\n                    ? { duration: 0.01 }\n                    : {\n                        type: \"spring\",\n                        stiffness,\n                        damping,\n                        delay: idx * 0.035,\n                      }\n                }\n                className=\"relative z-10 inline-block\"\n              >\n                {char}\n              </motion.span>\n            </AnimatePresence>\n          </div>\n        ))}\n      </button>\n\n      <div className=\"flex items-center gap-1.5 text-[11px] text-neutral-400\">\n        <RotateCw className=\"h-3 w-3\" />\n        <span>Click board to cycle mechanical split-flap</span>\n      </div>\n    </div>\n  );\n}\n\nexport default SplitFlapText;\n",
          "type": "registry:ui",
          "target": "components/ui/split-flap-text.tsx"
        },
        {
          "path": "lib/utils.ts",
          "content": "import { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...inputs: ClassValue[]) {\n  return twMerge(clsx(inputs));\n}\n\nexport async function copyToClipboard(text: string): Promise<boolean> {\n  if (typeof window === \"undefined\") return false;\n\n  try {\n    if (navigator.clipboard && window.isSecureContext) {\n      await navigator.clipboard.writeText(text);\n      return true;\n    }\n\n    const textArea = document.createElement(\"textarea\");\n    textArea.value = text;\n    textArea.style.position = \"fixed\";\n    textArea.style.left = \"-999999px\";\n    textArea.style.top = \"-999999px\";\n    document.body.appendChild(textArea);\n    textArea.focus();\n    textArea.select();\n    const succeeded = document.execCommand(\"copy\");\n    textArea.remove();\n    return succeeded;\n  } catch {\n    return false;\n  }\n}\n",
          "type": "registry:lib",
          "target": "lib/utils.ts"
        }
      ]
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "spotlight-card",
      "type": "registry:ui",
      "title": "Spotlight Card",
      "author": "Rishabh Bose <https://theb0se.vercel.app/>",
      "description": "Minimal surface card with GPU-composited radial cursor illumination, 1px CSS mask border reveal, and optional 3D perspective tilt.",
      "dependencies": [
        "framer-motion",
        "clsx",
        "tailwind-merge"
      ],
      "files": [
        {
          "path": "components/ui/spotlight-card.tsx",
          "content": "\"use client\";\n\nimport React, { useRef, useState } from \"react\";\nimport {\n  motion,\n  useMotionTemplate,\n  useMotionValue,\n  useSpring,\n  useReducedMotion,\n  type HTMLMotionProps,\n} from \"framer-motion\";\nimport { cn } from \"@/lib/utils\";\n\nexport interface SpotlightCardProps extends HTMLMotionProps<\"div\"> {\n  children: React.ReactNode;\n  /** Primary radial spotlight color. Default: \"rgba(128, 128, 128, 0.14)\" */\n  spotlightColor?: string;\n  /** Border highlight color on pointer proximity. Default: \"rgba(128, 128, 128, 0.55)\" */\n  borderColor?: string;\n  /** Radius of the radial spotlight in pixels. Default: 320 */\n  spotlightRadius?: number;\n  /** Enable subtle 3D tilt when moving pointer across card. Default: false */\n  enableTilt?: boolean;\n}\n\nexport function SpotlightCard({\n  children,\n  className,\n  spotlightColor = \"rgba(128, 128, 128, 0.14)\",\n  borderColor = \"rgba(128, 128, 128, 0.55)\",\n  spotlightRadius = 320,\n  enableTilt = false,\n  onMouseMove,\n  onMouseEnter,\n  onMouseLeave,\n  ...props\n}: SpotlightCardProps) {\n  const cardRef = useRef<HTMLDivElement>(null);\n  const shouldReduceMotion = useReducedMotion();\n  const [isHovered, setIsHovered] = useState(false);\n\n  const mouseX = useMotionValue(-1000);\n  const mouseY = useMotionValue(-1000);\n\n  const smoothX = useSpring(mouseX, { stiffness: 320, damping: 28, mass: 0.25 });\n  const smoothY = useSpring(mouseY, { stiffness: 320, damping: 28, mass: 0.25 });\n\n  const rotateX = useSpring(useMotionValue(0), { stiffness: 200, damping: 22 });\n  const rotateY = useSpring(useMotionValue(0), { stiffness: 200, damping: 22 });\n\n  const handleMouseMove = (e: React.MouseEvent<HTMLDivElement>) => {\n    if (!cardRef.current) return;\n    const rect = cardRef.current.getBoundingClientRect();\n    const x = e.clientX - rect.left;\n    const y = e.clientY - rect.top;\n\n    mouseX.set(x);\n    mouseY.set(y);\n\n    if (enableTilt && !shouldReduceMotion) {\n      const pctX = (x / rect.width - 0.5) * 2;\n      const pctY = (y / rect.height - 0.5) * 2;\n      rotateX.set(-pctY * 4);\n      rotateY.set(pctX * 4);\n    }\n\n    onMouseMove?.(e);\n  };\n\n  const handleMouseEnter = (e: React.MouseEvent<HTMLDivElement>) => {\n    setIsHovered(true);\n    onMouseEnter?.(e);\n  };\n\n  const handleMouseLeave = (e: React.MouseEvent<HTMLDivElement>) => {\n    setIsHovered(false);\n    rotateX.set(0);\n    rotateY.set(0);\n    onMouseLeave?.(e);\n  };\n\n  const activeX = shouldReduceMotion ? mouseX : smoothX;\n  const activeY = shouldReduceMotion ? mouseY : smoothY;\n\n  const surfaceBackground = useMotionTemplate`radial-gradient(${spotlightRadius}px circle at ${activeX}px ${activeY}px, ${spotlightColor}, transparent 80%)`;\n  const borderBackground = useMotionTemplate`radial-gradient(${\n    spotlightRadius * 0.75\n  }px circle at ${activeX}px ${activeY}px, ${borderColor}, transparent 100%)`;\n\n  return (\n    <motion.div\n      ref={cardRef}\n      onMouseMove={handleMouseMove}\n      onMouseEnter={handleMouseEnter}\n      onMouseLeave={handleMouseLeave}\n      style={{\n        rotateX: enableTilt && !shouldReduceMotion ? rotateX : 0,\n        rotateY: enableTilt && !shouldReduceMotion ? rotateY : 0,\n        transformPerspective: 1000,\n      }}\n      className={cn(\n        \"group relative overflow-hidden rounded-2xl border border-neutral-200 bg-white p-6 transition-colors duration-300 hover:border-neutral-400 dark:border-[#222222] dark:bg-[#0A0A0A] dark:hover:border-[#383838]\",\n        className\n      )}\n      {...props}\n    >\n      {/* Dynamic illuminated 1px border overlay */}\n      <motion.div\n        aria-hidden=\"true\"\n        className=\"pointer-events-none absolute -inset-px rounded-2xl transition-opacity duration-300\"\n        style={{\n          opacity: isHovered ? 1 : 0,\n          background: borderBackground,\n          WebkitMask:\n            \"linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0)\",\n          WebkitMaskComposite: \"xor\",\n          maskComposite: \"exclude\",\n          padding: \"1px\",\n        }}\n      />\n\n      {/* Ambient surface spotlight */}\n      <motion.div\n        aria-hidden=\"true\"\n        className=\"pointer-events-none absolute inset-0 rounded-2xl transition-opacity duration-300\"\n        style={{\n          opacity: isHovered ? 1 : 0,\n          background: surfaceBackground,\n        }}\n      />\n\n      <div className=\"relative z-10\">{children}</div>\n    </motion.div>\n  );\n}\n",
          "type": "registry:ui",
          "target": "components/ui/spotlight-card.tsx"
        },
        {
          "path": "lib/utils.ts",
          "content": "import { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...inputs: ClassValue[]) {\n  return twMerge(clsx(inputs));\n}\n\nexport async function copyToClipboard(text: string): Promise<boolean> {\n  if (typeof window === \"undefined\") return false;\n\n  try {\n    if (navigator.clipboard && window.isSecureContext) {\n      await navigator.clipboard.writeText(text);\n      return true;\n    }\n\n    const textArea = document.createElement(\"textarea\");\n    textArea.value = text;\n    textArea.style.position = \"fixed\";\n    textArea.style.left = \"-999999px\";\n    textArea.style.top = \"-999999px\";\n    document.body.appendChild(textArea);\n    textArea.focus();\n    textArea.select();\n    const succeeded = document.execCommand(\"copy\");\n    textArea.remove();\n    return succeeded;\n  } catch {\n    return false;\n  }\n}\n",
          "type": "registry:lib",
          "target": "lib/utils.ts"
        }
      ]
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "spring-pin-input",
      "type": "registry:ui",
      "title": "Spring Pin Input",
      "author": "Rishabh Bose <https://theb0se.vercel.app/>",
      "description": "Tactile OTP verification code input with per-digit spring impulse bounce, staggered completion wave, and harmonic error shake.",
      "dependencies": [
        "framer-motion",
        "lucide-react",
        "clsx",
        "tailwind-merge"
      ],
      "files": [
        {
          "path": "components/ui/spring-pin-input.tsx",
          "content": "\"use client\";\n\nimport React, { useRef, useState } from \"react\";\nimport { motion, useReducedMotion } from \"framer-motion\";\nimport { ShieldCheck, RotateCcw } from \"lucide-react\";\nimport { cn } from \"@/lib/utils\";\n\nexport interface SpringPinInputProps {\n  /** Number of OTP verification digits. Default: 6 */\n  length?: number;\n  /** Initial digits string for preview convenience. Default: \"482\" */\n  defaultValue?: string;\n  /** Spring stiffness coefficient for keystroke slot bounce. Default: 420 */\n  stiffness?: number;\n  /** Spring damping coefficient for keystroke slot bounce. Default: 22 */\n  damping?: number;\n  /** Callback fired when all digits are filled */\n  onComplete?: (code: string) => void;\n  className?: string;\n}\n\nexport function SpringPinInput({\n  length = 6,\n  defaultValue = \"482\",\n  stiffness = 420,\n  damping = 22,\n  onComplete,\n  className,\n}: SpringPinInputProps) {\n  const shouldReduceMotion = useReducedMotion() ?? false;\n  const [digits, setDigits] = useState<string[]>(() => {\n    const arr = Array.from({ length }, (_, i) => defaultValue[i] || \"\");\n    return arr;\n  });\n  const [focusedIndex, setFocusedIndex] = useState<number | null>(null);\n  const [shakeCount, setShakeCount] = useState(0);\n  const inputRefs = useRef<Array<HTMLInputElement | null>>([]);\n\n  const isComplete = digits.every((d) => d !== \"\");\n\n  const updateDigit = (index: number, char: string) => {\n    if (!/^[0-9]?$/.test(char)) {\n      setShakeCount((c) => c + 1);\n      return;\n    }\n\n    const next = [...digits];\n    next[index] = char;\n    setDigits(next);\n\n    if (char && index < length - 1) {\n      inputRefs.current[index + 1]?.focus();\n    }\n\n    if (next.every((d) => d !== \"\")) {\n      onComplete?.(next.join(\"\"));\n    }\n  };\n\n  const handleKeyDown = (\n    index: number,\n    e: React.KeyboardEvent<HTMLInputElement>\n  ) => {\n    if (e.key === \"Backspace\") {\n      e.preventDefault();\n      if (digits[index]) {\n        updateDigit(index, \"\");\n      } else if (index > 0) {\n        updateDigit(index - 1, \"\");\n        inputRefs.current[index - 1]?.focus();\n      }\n    } else if (e.key === \"ArrowLeft\" && index > 0) {\n      e.preventDefault();\n      inputRefs.current[index - 1]?.focus();\n    } else if (e.key === \"ArrowRight\" && index < length - 1) {\n      e.preventDefault();\n      inputRefs.current[index + 1]?.focus();\n    }\n  };\n\n  const handlePaste = (e: React.ClipboardEvent<HTMLInputElement>) => {\n    e.preventDefault();\n    const pasted = e.clipboardData\n      .getData(\"text\")\n      .replace(/\\D/g, \"\")\n      .slice(0, length);\n    if (!pasted) {\n      setShakeCount((c) => c + 1);\n      return;\n    }\n    const next = Array.from({ length }, (_, i) => pasted[i] || \"\");\n    setDigits(next);\n    const focusIdx = Math.min(pasted.length, length - 1);\n    inputRefs.current[focusIdx]?.focus();\n    if (next.every((d) => d !== \"\")) {\n      onComplete?.(next.join(\"\"));\n    }\n  };\n\n  const resetPin = () => {\n    setDigits(Array.from({ length }, () => \"\"));\n    inputRefs.current[0]?.focus();\n  };\n\n  return (\n    <motion.div\n      key={shakeCount}\n      animate={\n        shakeCount > 0 && !shouldReduceMotion\n          ? { x: [0, -8, 8, -5, 5, 0] }\n          : { x: 0 }\n      }\n      transition={{ duration: 0.32 }}\n      className={cn(\n        \"inline-flex flex-col items-center gap-3 rounded-2xl border border-neutral-200 bg-white p-5 dark:border-[#222222] dark:bg-[#0A0A0A]\",\n        className\n      )}\n    >\n      <div className=\"flex w-full items-center justify-between text-xs\">\n        <span className=\"inline-flex items-center gap-1.5 font-semibold text-black dark:text-white\">\n          <ShieldCheck className=\"h-4 w-4\" />\n          <span>{isComplete ? \"Code Verified\" : \"Verification Code\"}</span>\n        </span>\n        <button\n          type=\"button\"\n          onClick={resetPin}\n          aria-label=\"Clear verification digits\"\n          className=\"inline-flex items-center gap-1 text-[11px] text-neutral-400 transition-colors hover:text-black dark:hover:text-white\"\n        >\n          <RotateCcw className=\"h-3 w-3\" />\n          Clear\n        </button>\n      </div>\n\n      <div\n        role=\"group\"\n        aria-label=\"One-time verification code digits\"\n        className=\"flex items-center gap-2\"\n      >\n        {digits.map((digit, idx) => {\n          const isFocused = focusedIndex === idx;\n          const isFilled = digit !== \"\";\n\n          return (\n            <motion.div\n              key={idx}\n              animate={\n                shouldReduceMotion\n                  ? {}\n                  : {\n                      y: isComplete ? [0, -6, 0] : isFilled ? -2 : 0,\n                      scale: isFocused ? 1.07 : isFilled ? 1.02 : 1,\n                    }\n              }\n              transition={{\n                type: \"spring\",\n                stiffness,\n                damping,\n                delay: isComplete ? idx * 0.035 : 0,\n              }}\n              className=\"relative\"\n            >\n              <input\n                ref={(el) => {\n                  inputRefs.current[idx] = el;\n                }}\n                type=\"text\"\n                inputMode=\"numeric\"\n                maxLength={1}\n                value={digit}\n                aria-label={`Digit ${idx + 1} of ${length}`}\n                onFocus={(e) => {\n                  setFocusedIndex(idx);\n                  e.target.select();\n                }}\n                onBlur={() => setFocusedIndex(null)}\n                onChange={(e) => updateDigit(idx, e.target.value.slice(-1))}\n                onKeyDown={(e) => handleKeyDown(idx, e)}\n                onPaste={handlePaste}\n                className={cn(\n                  \"h-12 w-10 rounded-xl border text-center font-mono text-base font-bold transition-colors focus:outline-none\",\n                  isFocused\n                    ? \"border-black bg-white text-black ring-2 ring-black/15 dark:border-white dark:bg-[#121212] dark:text-white dark:ring-white/15\"\n                    : isFilled\n                      ? \"border-neutral-400 bg-neutral-50 text-black dark:border-[#383838] dark:bg-[#141414] dark:text-white\"\n                      : \"border-neutral-200 bg-white text-neutral-400 dark:border-[#222222] dark:bg-[#0D0D0D]\"\n                )}\n              />\n            </motion.div>\n          );\n        })}\n      </div>\n\n      <div className=\"text-[11px] text-neutral-400 dark:text-neutral-500\">\n        Type digits, paste code, or press non-numeric key to test shake\n      </div>\n    </motion.div>\n  );\n}\n\nexport default SpringPinInput;\n",
          "type": "registry:ui",
          "target": "components/ui/spring-pin-input.tsx"
        },
        {
          "path": "lib/utils.ts",
          "content": "import { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...inputs: ClassValue[]) {\n  return twMerge(clsx(inputs));\n}\n\nexport async function copyToClipboard(text: string): Promise<boolean> {\n  if (typeof window === \"undefined\") return false;\n\n  try {\n    if (navigator.clipboard && window.isSecureContext) {\n      await navigator.clipboard.writeText(text);\n      return true;\n    }\n\n    const textArea = document.createElement(\"textarea\");\n    textArea.value = text;\n    textArea.style.position = \"fixed\";\n    textArea.style.left = \"-999999px\";\n    textArea.style.top = \"-999999px\";\n    document.body.appendChild(textArea);\n    textArea.focus();\n    textArea.select();\n    const succeeded = document.execCommand(\"copy\");\n    textArea.remove();\n    return succeeded;\n  } catch {\n    return false;\n  }\n}\n",
          "type": "registry:lib",
          "target": "lib/utils.ts"
        }
      ]
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "starry-night",
      "type": "registry:ui",
      "title": "Starry Night",
      "author": "Rishabh Bose <https://theb0se.vercel.app/>",
      "description": "Canvas 2D night sky rendering 100 to 350 depth-layered stars that twinkle via independent sine-wave phases and shift smoothly on pointer move.",
      "dependencies": [
        "lucide-react",
        "clsx",
        "tailwind-merge"
      ],
      "files": [
        {
          "path": "components/ui/starry-night.tsx",
          "content": "\"use client\";\n\nimport React, { useEffect, useRef, useState } from \"react\";\nimport { Sparkles } from \"lucide-react\";\nimport { cn } from \"@/lib/utils\";\n\nexport interface StarryNightProps {\n  /** Number of stars rendered on the canvas (100 to 350). Default: 200 */\n  density?: number;\n  /** Enable sine-wave alpha twinkling per star. Default: true */\n  twinkle?: boolean;\n  /** Mouse-move parallax shift intensity in pixels. Default: 24 */\n  parallax?: number;\n  /** Optional foreground content */\n  children?: React.ReactNode;\n  className?: string;\n}\n\ninterface StarParticle {\n  x: number;\n  y: number;\n  radius: number;\n  baseAlpha: number;\n  phase: number;\n  speed: number;\n  depth: number; // 0.2 (far) to 1.0 (near)\n}\n\nexport function StarryNight({\n  density = 200,\n  twinkle = true,\n  parallax = 24,\n  children,\n  className,\n}: StarryNightProps) {\n  const canvasRef = useRef<HTMLCanvasElement>(null);\n  const pointerRef = useRef({ x: 0, y: 0, targetX: 0, targetY: 0 });\n  const [twinkleOn, setTwinkleOn] = useState(twinkle);\n\n  useEffect(() => {\n    setTwinkleOn(twinkle);\n  }, [twinkle]);\n\n  useEffect(() => {\n    const canvas = canvasRef.current;\n    if (!canvas) return;\n    const ctx = canvas.getContext(\"2d\");\n    if (!ctx) return;\n\n    let rafId: number;\n    let width = (canvas.width = canvas.offsetWidth || 600);\n    let height = (canvas.height = canvas.offsetHeight || 360);\n\n    const count = Math.max(40, Math.min(400, density));\n    const stars: StarParticle[] = Array.from({ length: count }, () => {\n      const depth = 0.2 + Math.random() * 0.8;\n      return {\n        x: Math.random() * width,\n        y: Math.random() * height,\n        radius: 0.5 + depth * 1.4,\n        baseAlpha: 0.35 + Math.random() * 0.65,\n        phase: Math.random() * Math.PI * 2,\n        speed: 1.2 + Math.random() * 2.8,\n        depth,\n      };\n    });\n\n    const handleResize = () => {\n      if (!canvas) return;\n      width = canvas.width = canvas.offsetWidth || 600;\n      height = canvas.height = canvas.offsetHeight || 360;\n    };\n\n    window.addEventListener(\"resize\", handleResize);\n\n    const render = (now: number) => {\n      const t = now * 0.001;\n      // Smooth lerp pointer parallax\n      pointerRef.current.x +=\n        (pointerRef.current.targetX - pointerRef.current.x) * 0.08;\n      pointerRef.current.y +=\n        (pointerRef.current.targetY - pointerRef.current.y) * 0.08;\n\n      ctx.clearRect(0, 0, width, height);\n\n      for (let i = 0; i < stars.length; i++) {\n        const s = stars[i];\n        const alpha = twinkleOn\n          ? s.baseAlpha * (0.45 + 0.55 * Math.sin(t * s.speed + s.phase))\n          : s.baseAlpha;\n\n        const drawX =\n          (s.x + pointerRef.current.x * s.depth * parallax + width) % width;\n        const drawY =\n          (s.y + pointerRef.current.y * s.depth * parallax + height) % height;\n\n        ctx.beginPath();\n        ctx.arc(drawX, drawY, s.radius, 0, Math.PI * 2);\n        ctx.fillStyle = `rgba(255, 255, 255, ${alpha.toFixed(3)})`;\n        ctx.fill();\n      }\n\n      rafId = requestAnimationFrame(render);\n    };\n\n    rafId = requestAnimationFrame(render);\n    return () => {\n      cancelAnimationFrame(rafId);\n      window.removeEventListener(\"resize\", handleResize);\n    };\n  }, [density, parallax, twinkleOn]);\n\n  return (\n    <div\n      data-fullscreen-scroll\n      onMouseMove={(e) => {\n        const rect = e.currentTarget.getBoundingClientRect();\n        const nx = ((e.clientX - rect.left) / rect.width - 0.5) * 2;\n        const ny = ((e.clientY - rect.top) / rect.height - 0.5) * 2;\n        pointerRef.current.targetX = -nx;\n        pointerRef.current.targetY = -ny;\n      }}\n      onMouseLeave={() => {\n        pointerRef.current.targetX = 0;\n        pointerRef.current.targetY = 0;\n      }}\n      className={cn(\n        \"relative flex min-h-[360px] w-full flex-col justify-between overflow-hidden rounded-3xl border border-neutral-800 bg-gradient-to-b from-[#03050C] via-[#070B19] to-[#0F172A] p-6 text-white shadow-sm\",\n        className\n      )}\n    >\n      <canvas\n        ref={canvasRef}\n        aria-hidden=\"true\"\n        className=\"pointer-events-none absolute inset-0 h-full w-full\"\n      />\n\n      <div className=\"relative z-10 flex flex-1 flex-col justify-between\">\n        {children ?? (\n          <>\n            <div className=\"flex items-center justify-between gap-2\">\n              <span className=\"inline-flex items-center gap-1.5 rounded-full border border-white/15 bg-white/10 px-3 py-1 font-mono text-[11px] font-medium text-white backdrop-blur-md\">\n                <Sparkles className=\"h-3.5 w-3.5 text-sky-300\" />\n                Starry Night · {density} Stars\n              </span>\n\n              <button\n                type=\"button\"\n                onClick={() => setTwinkleOn((v) => !v)}\n                className=\"rounded-full border border-white/15 bg-white/10 px-3 py-1 font-mono text-[11px] text-white/85 backdrop-blur-md transition-colors hover:bg-white/20\"\n              >\n                Twinkle: {twinkleOn ? \"ON\" : \"OFF\"}\n              </button>\n            </div>\n\n            <div className=\"my-auto max-w-md py-8\">\n              <h3 className=\"text-2xl font-bold tracking-tight text-white sm:text-3xl\">\n                Deep Space Starfield\n              </h3>\n              <p className=\"mt-2 text-xs leading-relaxed text-white/75 sm:text-sm\">\n                Move your cursor to experience multi-plane depth parallax while\n                each star oscillates on an independent sine-wave phase.\n              </p>\n            </div>\n\n            <div className=\"font-mono text-[11px] text-white/50\">\n              Canvas 2D · Sine-Wave Alpha · 3D Depth Parallax\n            </div>\n          </>\n        )}\n      </div>\n    </div>\n  );\n}\n\nexport default StarryNight;\n",
          "type": "registry:ui",
          "target": "components/ui/starry-night.tsx"
        },
        {
          "path": "lib/utils.ts",
          "content": "import { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...inputs: ClassValue[]) {\n  return twMerge(clsx(inputs));\n}\n\nexport async function copyToClipboard(text: string): Promise<boolean> {\n  if (typeof window === \"undefined\") return false;\n\n  try {\n    if (navigator.clipboard && window.isSecureContext) {\n      await navigator.clipboard.writeText(text);\n      return true;\n    }\n\n    const textArea = document.createElement(\"textarea\");\n    textArea.value = text;\n    textArea.style.position = \"fixed\";\n    textArea.style.left = \"-999999px\";\n    textArea.style.top = \"-999999px\";\n    document.body.appendChild(textArea);\n    textArea.focus();\n    textArea.select();\n    const succeeded = document.execCommand(\"copy\");\n    textArea.remove();\n    return succeeded;\n  } catch {\n    return false;\n  }\n}\n",
          "type": "registry:lib",
          "target": "lib/utils.ts"
        }
      ]
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "stepper",
      "type": "registry:ui",
      "title": "Stepper Wizard",
      "author": "Rishabh Bose <https://theb0se.vercel.app/>",
      "description": "Multi-step onboarding and checkout progress wizard with spring-animated connector bars, clickable step indicators, and directional panel transitions.",
      "dependencies": [
        "framer-motion",
        "lucide-react",
        "clsx",
        "tailwind-merge"
      ],
      "files": [
        {
          "path": "components/ui/stepper.tsx",
          "content": "\"use client\";\n\nimport React, { useState } from \"react\";\nimport { AnimatePresence, motion, useReducedMotion } from \"framer-motion\";\nimport { Check, ChevronRight, ChevronLeft, RotateCcw } from \"lucide-react\";\nimport { cn } from \"@/lib/utils\";\n\nexport interface StepItem {\n  id: string;\n  title: string;\n  description: string;\n  detail?: string;\n}\n\nexport interface StepperProps {\n  /** Array of steps to render in the wizard */\n  steps?: StepItem[];\n  /** Controlled active step index (0-based) */\n  activeStep?: number;\n  /** Initial active step index for uncontrolled mode. Default: 0 */\n  defaultStep?: number;\n  /** Callback fired when active step changes */\n  onStepChange?: (stepIndex: number) => void;\n  /** Callback fired when the final step is completed */\n  onComplete?: () => void;\n  /** Allow clicking directly on step circles to jump between steps. Default: true */\n  allowStepClick?: boolean;\n  className?: string;\n}\n\nconst DEFAULT_STEPS: StepItem[] = [\n  {\n    id: \"workspace\",\n    title: \"Workspace\",\n    description: \"Configure your project name and repository region.\",\n    detail: \"Connected to us-east-1 production cluster with automatic backups enabled.\",\n  },\n  {\n    id: \"tokens\",\n    title: \"Design Tokens\",\n    description: \"Sync Tailwind CSS colors, radius, and typography scales.\",\n    detail: \"Monochrome light & dark CSS variables verified in globals.css.\",\n  },\n  {\n    id: \"deploy\",\n    title: \"Ship & Verify\",\n    description: \"Run pre-flight checks and publish your component registry.\",\n    detail: \"All TypeScript checks passed. Ready to deploy to production.\",\n  },\n];\n\nexport function Stepper({\n  steps = DEFAULT_STEPS,\n  activeStep: controlledStep,\n  defaultStep = 0,\n  onStepChange,\n  onComplete,\n  allowStepClick = true,\n  className,\n}: StepperProps) {\n  const shouldReduceMotion = useReducedMotion() ?? false;\n  const isControlled = controlledStep !== undefined;\n\n  const [internalStep, setInternalStep] = useState(defaultStep);\n  const [direction, setDirection] = useState<1 | -1>(1);\n\n  const currentStep = isControlled ? controlledStep : internalStep;\n  const totalSteps = steps.length;\n  const isComplete = currentStep >= totalSteps;\n\n  const goToStep = (next: number) => {\n    const clamped = Math.max(0, Math.min(totalSteps, next));\n    setDirection(clamped >= currentStep ? 1 : -1);\n    if (!isControlled) {\n      setInternalStep(clamped);\n    }\n    onStepChange?.(clamped);\n    if (clamped === totalSteps) {\n      onComplete?.();\n    }\n  };\n\n  const progressPct =\n    totalSteps <= 1\n      ? 100\n      : Math.min(100, (Math.min(currentStep, totalSteps - 1) / (totalSteps - 1)) * 100);\n\n  const activeItem = steps[Math.min(currentStep, totalSteps - 1)];\n\n  return (\n    <div\n      className={cn(\n        \"w-full max-w-md rounded-2xl border border-neutral-200 bg-white p-5 shadow-sm dark:border-[#262626] dark:bg-[#0A0A0A]\",\n        className\n      )}\n    >\n      {/* Step Header Track */}\n      <div className=\"relative mb-6\">\n        {/* Background Connector Line */}\n        <div className=\"absolute left-4 right-4 top-4 h-0.5 bg-neutral-200 dark:bg-[#222222]\" />\n\n        {/* Animated Progress Fill Line */}\n        <motion.div\n          initial={false}\n          animate={{ width: `calc(${progressPct}% - 16px)` }}\n          transition={\n            shouldReduceMotion\n              ? { duration: 0 }\n              : { type: \"spring\", stiffness: 320, damping: 30 }\n          }\n          className=\"absolute left-4 top-4 h-0.5 bg-black dark:bg-white\"\n        />\n\n        {/* Step Nodes */}\n        <div className=\"relative z-10 flex items-center justify-between\">\n          {steps.map((step, index) => {\n            const isCompleted = currentStep > index;\n            const isCurrent = currentStep === index;\n\n            return (\n              <div key={step.id} className=\"flex flex-col items-center gap-1.5\">\n                <button\n                  type=\"button\"\n                  disabled={!allowStepClick}\n                  onClick={() => allowStepClick && goToStep(index)}\n                  aria-current={isCurrent ? \"step\" : undefined}\n                  className={cn(\n                    \"flex h-8 w-8 items-center justify-center rounded-full border text-xs font-semibold transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-black dark:focus-visible:ring-white\",\n                    allowStepClick ? \"cursor-pointer\" : \"cursor-default\",\n                    isCompleted || isCurrent\n                      ? \"border-black bg-black text-white dark:border-white dark:bg-white dark:text-black\"\n                      : \"border-neutral-300 bg-white text-neutral-400 dark:border-[#262626] dark:bg-[#0A0A0A] dark:text-neutral-500\"\n                  )}\n                >\n                  <AnimatePresence mode=\"wait\" initial={false}>\n                    {isCompleted ? (\n                      <motion.span\n                        key=\"check\"\n                        initial={{ scale: 0.5, opacity: 0 }}\n                        animate={{ scale: 1, opacity: 1 }}\n                        exit={{ scale: 0.5, opacity: 0 }}\n                        transition={{ duration: 0.15 }}\n                      >\n                        <Check className=\"h-3.5 w-3.5 stroke-[2.5]\" />\n                      </motion.span>\n                    ) : (\n                      <motion.span\n                        key=\"num\"\n                        initial={{ scale: 0.8, opacity: 0 }}\n                        animate={{ scale: 1, opacity: 1 }}\n                        exit={{ scale: 0.8, opacity: 0 }}\n                        transition={{ duration: 0.15 }}\n                        className=\"font-mono\"\n                      >\n                        {index + 1}\n                      </motion.span>\n                    )}\n                  </AnimatePresence>\n                </button>\n                <span\n                  className={cn(\n                    \"text-[11px] font-medium transition-colors\",\n                    isCurrent || isCompleted\n                      ? \"text-black dark:text-white\"\n                      : \"text-neutral-400 dark:text-neutral-500\"\n                  )}\n                >\n                  {step.title}\n                </span>\n              </div>\n            );\n          })}\n        </div>\n      </div>\n\n      {/* Step Body Content */}\n      <div className=\"min-h-[108px] overflow-hidden rounded-xl border border-neutral-200/80 bg-neutral-50/70 p-4 dark:border-[#1F1F1F] dark:bg-[#111111]\">\n        <AnimatePresence mode=\"wait\" initial={false} custom={direction}>\n          {isComplete ? (\n            <motion.div\n              key=\"completed-state\"\n              initial={\n                shouldReduceMotion ? { opacity: 0 } : { opacity: 0, y: 8 }\n              }\n              animate={{ opacity: 1, y: 0 }}\n              exit={\n                shouldReduceMotion ? { opacity: 0 } : { opacity: 0, y: -8 }\n              }\n              transition={{ type: \"spring\", stiffness: 380, damping: 30 }}\n              className=\"flex flex-col items-start gap-1.5\"\n            >\n              <div className=\"inline-flex items-center gap-1.5 rounded-full bg-black px-2.5 py-0.5 font-mono text-[10px] font-semibold uppercase tracking-wider text-white dark:bg-white dark:text-black\">\n                <Check className=\"h-3 w-3\" />\n                All Steps Complete\n              </div>\n              <h4 className=\"text-sm font-semibold text-black dark:text-white\">\n                Setup Finished Successfully\n              </h4>\n              <p className=\"text-xs leading-relaxed text-neutral-600 dark:text-neutral-400\">\n                Your configuration is live and ready. You can review any previous step or reset the wizard.\n              </p>\n            </motion.div>\n          ) : (\n            <motion.div\n              key={activeItem.id}\n              initial={\n                shouldReduceMotion\n                  ? { opacity: 0 }\n                  : { opacity: 0, x: direction * 18 }\n              }\n              animate={{ opacity: 1, x: 0 }}\n              exit={\n                shouldReduceMotion\n                  ? { opacity: 0 }\n                  : { opacity: 0, x: direction * -18 }\n              }\n              transition={{ type: \"spring\", stiffness: 380, damping: 30 }}\n              className=\"flex flex-col gap-1.5\"\n            >\n              <div className=\"flex items-center justify-between\">\n                <span className=\"font-mono text-[10px] font-semibold uppercase tracking-wider text-neutral-400 dark:text-neutral-500\">\n                  Step {currentStep + 1} of {totalSteps}\n                </span>\n              </div>\n              <h4 className=\"text-sm font-semibold text-black dark:text-white\">\n                {activeItem.title}\n              </h4>\n              <p className=\"text-xs leading-relaxed text-neutral-600 dark:text-neutral-400\">\n                {activeItem.description}\n              </p>\n              {activeItem.detail && (\n                <p className=\"mt-1 rounded-lg border border-neutral-200 bg-white px-2.5 py-1.5 font-mono text-[11px] text-neutral-500 dark:border-[#222222] dark:bg-[#0A0A0A] dark:text-neutral-400\">\n                  {activeItem.detail}\n                </p>\n              )}\n            </motion.div>\n          )}\n        </AnimatePresence>\n      </div>\n\n      {/* Footer Controls */}\n      <div className=\"mt-4 flex items-center justify-between\">\n        <button\n          type=\"button\"\n          disabled={currentStep === 0}\n          onClick={() => goToStep(currentStep - 1)}\n          className=\"inline-flex h-9 items-center gap-1 rounded-xl border border-neutral-200 px-3 text-xs font-medium text-neutral-700 transition-colors hover:bg-neutral-100 disabled:pointer-events-none disabled:opacity-40 dark:border-[#262626] dark:text-neutral-300 dark:hover:bg-[#161616]\"\n        >\n          <ChevronLeft className=\"h-3.5 w-3.5\" />\n          Back\n        </button>\n\n        {isComplete ? (\n          <button\n            type=\"button\"\n            onClick={() => goToStep(0)}\n            className=\"inline-flex h-9 items-center gap-1.5 rounded-xl border border-neutral-200 bg-neutral-100 px-3.5 text-xs font-semibold text-black transition-colors hover:bg-neutral-200 dark:border-[#262626] dark:bg-[#161616] dark:text-white dark:hover:bg-[#222222]\"\n          >\n            <RotateCcw className=\"h-3.5 w-3.5\" />\n            Reset Wizard\n          </button>\n        ) : (\n          <button\n            type=\"button\"\n            onClick={() => goToStep(currentStep + 1)}\n            className=\"inline-flex h-9 items-center gap-1 rounded-xl bg-black px-4 text-xs font-semibold text-white transition-opacity hover:opacity-90 dark:bg-white dark:text-black\"\n          >\n            <span>{currentStep === totalSteps - 1 ? \"Complete\" : \"Continue\"}</span>\n            <ChevronRight className=\"h-3.5 w-3.5\" />\n          </button>\n        )}\n      </div>\n    </div>\n  );\n}\n\nexport default Stepper;\n",
          "type": "registry:ui",
          "target": "components/ui/stepper.tsx"
        },
        {
          "path": "lib/utils.ts",
          "content": "import { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...inputs: ClassValue[]) {\n  return twMerge(clsx(inputs));\n}\n\nexport async function copyToClipboard(text: string): Promise<boolean> {\n  if (typeof window === \"undefined\") return false;\n\n  try {\n    if (navigator.clipboard && window.isSecureContext) {\n      await navigator.clipboard.writeText(text);\n      return true;\n    }\n\n    const textArea = document.createElement(\"textarea\");\n    textArea.value = text;\n    textArea.style.position = \"fixed\";\n    textArea.style.left = \"-999999px\";\n    textArea.style.top = \"-999999px\";\n    document.body.appendChild(textArea);\n    textArea.focus();\n    textArea.select();\n    const succeeded = document.execCommand(\"copy\");\n    textArea.remove();\n    return succeeded;\n  } catch {\n    return false;\n  }\n}\n",
          "type": "registry:lib",
          "target": "lib/utils.ts"
        }
      ]
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "stepper-slider-control",
      "type": "registry:ui",
      "title": "Stepper & Slider",
      "author": "Rishabh Bose <https://theb0se.vercel.app/>",
      "description": "Synchronized precision control pairing a thin-track slider and large round thumb with a tactile (− / +) segmented stepper pill.",
      "dependencies": [
        "framer-motion",
        "lucide-react",
        "clsx",
        "tailwind-merge"
      ],
      "files": [
        {
          "path": "components/ui/stepper-slider-control.tsx",
          "content": "\"use client\";\n\nimport React, { useState, useRef } from \"react\";\nimport { motion, useReducedMotion } from \"framer-motion\";\nimport { Minus, Plus } from \"lucide-react\";\nimport { cn } from \"@/lib/utils\";\n\nexport interface StepperSliderControlProps {\n  /** Label for the control */\n  label?: string;\n  /** Controlled numeric value */\n  value?: number;\n  /** Initial value for uncontrolled mode. Default: 60 */\n  defaultValue?: number;\n  /** Minimum value. Default: 0 */\n  min?: number;\n  /** Maximum value. Default: 100 */\n  max?: number;\n  /** Step increment for both slider and (− / +) buttons. Default: 5 */\n  step?: number;\n  /** Optional unit suffix (e.g. \"%\", \"px\", \"dB\"). Default: \"%\" */\n  unit?: string;\n  /** Callback fired when value changes */\n  onChange?: (value: number) => void;\n  /** Disable interactions */\n  disabled?: boolean;\n  className?: string;\n}\n\nexport function StepperSliderControl({\n  label = \"Display Brightness\",\n  value: controlledValue,\n  defaultValue = 65,\n  min = 0,\n  max = 100,\n  step = 5,\n  unit = \"%\",\n  onChange,\n  disabled = false,\n  className,\n}: StepperSliderControlProps) {\n  const shouldReduceMotion = useReducedMotion() ?? false;\n  const trackRef = useRef<HTMLDivElement>(null);\n  const isControlled = controlledValue !== undefined;\n\n  const [internalVal, setInternalVal] = useState(defaultValue);\n  const [isDragging, setIsDragging] = useState(false);\n\n  const currentVal = isControlled ? controlledValue : internalVal;\n\n  const clampAndSnap = (raw: number) => {\n    const snapped = Math.round((raw - min) / step) * step + min;\n    return Math.max(min, Math.min(max, Number(snapped.toFixed(4))));\n  };\n\n  const updateValue = (next: number) => {\n    if (disabled) return;\n    const clamped = clampAndSnap(next);\n    if (!isControlled) {\n      setInternalVal(clamped);\n    }\n    onChange?.(clamped);\n  };\n\n  const pct =\n    max > min ? Math.max(0, Math.min(100, ((currentVal - min) / (max - min)) * 100)) : 0;\n\n  const updateFromPointer = (clientX: number) => {\n    if (!trackRef.current || disabled) return;\n    const rect = trackRef.current.getBoundingClientRect();\n    const ratio = Math.max(0, Math.min(1, (clientX - rect.left) / rect.width));\n    const rawValue = min + ratio * (max - min);\n    updateValue(rawValue);\n  };\n\n  const handlePointerDown = (e: React.PointerEvent<HTMLDivElement>) => {\n    if (disabled) return;\n    e.currentTarget.setPointerCapture(e.pointerId);\n    setIsDragging(true);\n    updateFromPointer(e.clientX);\n  };\n\n  const handlePointerMove = (e: React.PointerEvent<HTMLDivElement>) => {\n    if (!isDragging || disabled) return;\n    updateFromPointer(e.clientX);\n  };\n\n  const handlePointerUp = () => {\n    setIsDragging(false);\n  };\n\n  return (\n    <div\n      className={cn(\n        \"w-full max-w-sm rounded-3xl border border-neutral-200 bg-white p-5 shadow-sm dark:border-neutral-800 dark:bg-[#0A0A0A]\",\n        disabled && \"opacity-50\",\n        className\n      )}\n    >\n      {/* Top Row: Label + Value Readout */}\n      <div className=\"flex items-center justify-between\">\n        <span className=\"text-xs font-semibold text-neutral-950 dark:text-white\">\n          {label}\n        </span>\n        <span className=\"font-mono text-sm font-bold tracking-tight text-neutral-950 dark:text-white\">\n          {currentVal}\n          {unit}\n        </span>\n      </div>\n\n      {/* Thin-Track Slider with Large Round Thumb */}\n      <div\n        ref={trackRef}\n        role=\"slider\"\n        tabIndex={disabled ? -1 : 0}\n        aria-label={label}\n        aria-valuemin={min}\n        aria-valuemax={max}\n        aria-valuenow={currentVal}\n        onPointerDown={handlePointerDown}\n        onPointerMove={handlePointerMove}\n        onPointerUp={handlePointerUp}\n        onPointerCancel={handlePointerUp}\n        onKeyDown={(e) => {\n          if (disabled) return;\n          if (e.key === \"ArrowRight\" || e.key === \"ArrowUp\") {\n            e.preventDefault();\n            updateValue(currentVal + step);\n          } else if (e.key === \"ArrowLeft\" || e.key === \"ArrowDown\") {\n            e.preventDefault();\n            updateValue(currentVal - step);\n          } else if (e.key === \"Home\") {\n            e.preventDefault();\n            updateValue(min);\n          } else if (e.key === \"End\") {\n            e.preventDefault();\n            updateValue(max);\n          }\n        }}\n        className=\"relative my-5 flex h-7 cursor-pointer touch-none select-none items-center focus-visible:outline-none\"\n      >\n        {/* Thin Background Track */}\n        <div className=\"relative h-1.5 w-full overflow-hidden rounded-full bg-neutral-200 dark:bg-neutral-800\">\n          <motion.div\n            animate={{ width: `${pct}%` }}\n            transition={\n              isDragging || shouldReduceMotion\n                ? { duration: 0 }\n                : { type: \"spring\", stiffness: 420, damping: 32 }\n            }\n            className=\"h-full rounded-full bg-neutral-900 dark:bg-white\"\n          />\n        </div>\n\n        {/* Large Round Thumb */}\n        <motion.div\n          animate={{\n            left: `calc(${pct}% - 12px)`,\n            scale: isDragging && !shouldReduceMotion ? 1.15 : 1,\n          }}\n          transition={\n            isDragging || shouldReduceMotion\n              ? { duration: 0 }\n              : { type: \"spring\", stiffness: 420, damping: 32 }\n          }\n          className=\"pointer-events-none absolute h-6 w-6 rounded-full border-2 border-neutral-900 bg-white shadow-md dark:border-white dark:bg-neutral-950\"\n        />\n      </div>\n\n      {/* Bottom Row: Minimal Stepper (− / +) & Fine-Tune Controls */}\n      <div className=\"flex items-center justify-between border-t border-neutral-100 pt-3.5 dark:border-neutral-900\">\n        <span className=\"font-mono text-[11px] text-neutral-400\">\n          Step: {step}\n          {unit}\n        </span>\n\n        {/* Apple-Style Segmented Pill Stepper (− | +) */}\n        <div className=\"inline-flex h-9 items-center overflow-hidden rounded-xl border border-neutral-200 bg-neutral-100/80 dark:border-neutral-800 dark:bg-neutral-900\">\n          <button\n            type=\"button\"\n            aria-label={`Decrease ${label}`}\n            disabled={disabled || currentVal <= min}\n            onClick={() => updateValue(currentVal - step)}\n            className=\"flex h-full w-11 items-center justify-center text-neutral-700 transition-colors hover:bg-neutral-200/70 active:scale-95 disabled:cursor-not-allowed disabled:opacity-35 dark:text-neutral-200 dark:hover:bg-neutral-800\"\n          >\n            <Minus className=\"h-3.5 w-3.5 stroke-[2.2]\" />\n          </button>\n\n          <span\n            aria-hidden=\"true\"\n            className=\"h-4 w-px bg-neutral-300 dark:bg-neutral-700\"\n          />\n\n          <button\n            type=\"button\"\n            aria-label={`Increase ${label}`}\n            disabled={disabled || currentVal >= max}\n            onClick={() => updateValue(currentVal + step)}\n            className=\"flex h-full w-11 items-center justify-center text-neutral-700 transition-colors hover:bg-neutral-200/70 active:scale-95 disabled:cursor-not-allowed disabled:opacity-35 dark:text-neutral-200 dark:hover:bg-neutral-800\"\n          >\n            <Plus className=\"h-3.5 w-3.5 stroke-[2.2]\" />\n          </button>\n        </div>\n      </div>\n    </div>\n  );\n}\n\nexport default StepperSliderControl;\n",
          "type": "registry:ui",
          "target": "components/ui/stepper-slider-control.tsx"
        },
        {
          "path": "lib/utils.ts",
          "content": "import { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...inputs: ClassValue[]) {\n  return twMerge(clsx(inputs));\n}\n\nexport async function copyToClipboard(text: string): Promise<boolean> {\n  if (typeof window === \"undefined\") return false;\n\n  try {\n    if (navigator.clipboard && window.isSecureContext) {\n      await navigator.clipboard.writeText(text);\n      return true;\n    }\n\n    const textArea = document.createElement(\"textarea\");\n    textArea.value = text;\n    textArea.style.position = \"fixed\";\n    textArea.style.left = \"-999999px\";\n    textArea.style.top = \"-999999px\";\n    document.body.appendChild(textArea);\n    textArea.focus();\n    textArea.select();\n    const succeeded = document.execCommand(\"copy\");\n    textArea.remove();\n    return succeeded;\n  } catch {\n    return false;\n  }\n}\n",
          "type": "registry:lib",
          "target": "lib/utils.ts"
        }
      ]
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "sticky-scroll-story",
      "type": "registry:ui",
      "title": "Sticky Scroll Storytelling",
      "author": "Rishabh Bose <https://theb0se.vercel.app/>",
      "description": "Pinned split-screen storytelling layout where scrolling through text chapters on the left animates the sticky media stage on the right in real time.",
      "dependencies": [
        "framer-motion",
        "lucide-react",
        "clsx",
        "tailwind-merge"
      ],
      "files": [
        {
          "path": "components/ui/sticky-scroll-story.tsx",
          "content": "\"use client\";\n\nimport React, { useState, useRef } from \"react\";\nimport { AnimatePresence, motion, useReducedMotion } from \"framer-motion\";\nimport { Layers, Shield, Zap, Sparkles } from \"lucide-react\";\nimport { cn } from \"@/lib/utils\";\n\nexport interface StorySection {\n  id: string;\n  badge: string;\n  title: string;\n  description: string;\n  metricLabel: string;\n  metricValue: string;\n}\n\nexport interface StickyScrollStoryProps {\n  /** Array of storytelling chapters */\n  sections?: StorySection[];\n  /** Optional header title above the storytelling container */\n  heading?: string;\n  className?: string;\n}\n\nconst DEFAULT_SECTIONS: StorySection[] = [\n  {\n    id: \"design\",\n    badge: \"01 · Design System\",\n    title: \"Machined from a single block of tokens.\",\n    description:\n      \"Every border, surface, and shadow shares a unified monochrome scale that adapts seamlessly between daylight and OLED dark mode.\",\n    metricLabel: \"Contrast Ratio\",\n    metricValue: \"18.4 : 1 AAA\",\n  },\n  {\n    id: \"motion\",\n    badge: \"02 · Spring Physics\",\n    title: \"Interruptible motion that respects momentum.\",\n    description:\n      \"Unlike fixed-duration CSS curves, spring animations preserve velocity when redirected mid-flight for natural tactile feedback.\",\n    metricLabel: \"Response Latency\",\n    metricValue: \"< 1.2 ms\",\n  },\n  {\n    id: \"shipping\",\n    badge: \"03 · Zero Lock-In\",\n    title: \"Own every line of code in your repository.\",\n    description:\n      \"Install via CLI or copy the TypeScript file directly. No black-box npm wrapper, no CSS conflicts, and full control over markup.\",\n    metricLabel: \"Runtime Overhead\",\n    metricValue: \"0 KB External\",\n  },\n];\n\nexport function StickyScrollStory({\n  sections = DEFAULT_SECTIONS,\n  heading = \"Scroll inside the container or click any chapter\",\n  className,\n}: StickyScrollStoryProps) {\n  const shouldReduceMotion = useReducedMotion() ?? false;\n  const [activeIndex, setActiveIndex] = useState(0);\n  const scrollContainerRef = useRef<HTMLDivElement>(null);\n\n  const handleScroll = (e: React.UIEvent<HTMLDivElement>) => {\n    const el = e.currentTarget;\n    const maxScroll = el.scrollHeight - el.clientHeight;\n    if (maxScroll <= 0) return;\n    const progress = el.scrollTop / maxScroll;\n    const idx = Math.min(\n      sections.length - 1,\n      Math.max(0, Math.round(progress * (sections.length - 1)))\n    );\n    if (idx !== activeIndex) {\n      setActiveIndex(idx);\n    }\n  };\n\n  const scrollToChapter = (index: number) => {\n    setActiveIndex(index);\n    const el = scrollContainerRef.current;\n    if (!el) return;\n    const maxScroll = el.scrollHeight - el.clientHeight;\n    const targetTop =\n      sections.length > 1 ? (index / (sections.length - 1)) * maxScroll : 0;\n    el.scrollTo({ top: targetTop, behavior: \"smooth\" });\n  };\n\n  const activeSection = sections[activeIndex] ?? sections[0];\n\n  const icons = [\n    <Layers key=\"layers\" className=\"h-5 w-5\" />,\n    <Zap key=\"zap\" className=\"h-5 w-5\" />,\n    <Shield key=\"shield\" className=\"h-5 w-5\" />,\n    <Sparkles key=\"sparkles\" className=\"h-5 w-5\" />,\n  ];\n\n  return (\n    <div\n      className={cn(\n        \"w-full max-w-2xl overflow-hidden rounded-3xl border border-neutral-200 bg-white shadow-sm dark:border-neutral-800 dark:bg-[#0A0A0A]\",\n        className\n      )}\n    >\n      {/* Top Status Bar */}\n      <div className=\"flex items-center justify-between border-b border-neutral-200 bg-neutral-50/70 px-5 py-2.5 dark:border-neutral-800 dark:bg-neutral-900/50\">\n        <span className=\"font-mono text-[11px] text-neutral-500 dark:text-neutral-400\">\n          {heading}\n        </span>\n        <div className=\"flex items-center gap-1.5\">\n          {sections.map((sec, idx) => (\n            <button\n              key={sec.id}\n              type=\"button\"\n              aria-label={`Jump to chapter ${idx + 1}`}\n              onClick={() => scrollToChapter(idx)}\n              className={cn(\n                \"h-1.5 rounded-full transition-all\",\n                idx === activeIndex\n                  ? \"w-5 bg-neutral-900 dark:bg-white\"\n                  : \"w-1.5 bg-neutral-300 hover:bg-neutral-400 dark:bg-neutral-700\"\n              )}\n            />\n          ))}\n        </div>\n      </div>\n\n      {/* Split Scrollable Text + Sticky Synced Media */}\n      <div\n        ref={scrollContainerRef}\n        data-fullscreen-scroll\n        onScroll={handleScroll}\n        className=\"grid max-h-[340px] grid-cols-1 gap-6 overflow-y-auto p-6 sm:grid-cols-12\"\n      >\n        {/* Left Scrolling Chapters */}\n        <div className=\"space-y-24 py-6 pb-28 sm:col-span-7\">\n          {sections.map((section, idx) => {\n            const isActive = idx === activeIndex;\n            return (\n              <div\n                key={section.id}\n                onClick={() => scrollToChapter(idx)}\n                className={cn(\n                  \"cursor-pointer rounded-2xl p-4 transition-all duration-300\",\n                  isActive\n                    ? \"bg-neutral-100/80 opacity-100 dark:bg-neutral-900/80\"\n                    : \"opacity-40 hover:opacity-70\"\n                )}\n              >\n                <span className=\"font-mono text-[11px] font-semibold uppercase tracking-wider text-neutral-500 dark:text-neutral-400\">\n                  {section.badge}\n                </span>\n                <h3 className=\"mt-1.5 text-base font-bold tracking-tight text-neutral-950 dark:text-white sm:text-lg\">\n                  {section.title}\n                </h3>\n                <p className=\"mt-2 text-xs leading-relaxed text-neutral-600 dark:text-neutral-400\">\n                  {section.description}\n                </p>\n              </div>\n            );\n          })}\n        </div>\n\n        {/* Right Sticky Media Stage */}\n        <div className=\"sm:col-span-5\">\n          <div className=\"sticky top-2 flex h-[240px] flex-col justify-between overflow-hidden rounded-2xl border border-neutral-200 bg-neutral-50 p-5 dark:border-neutral-800 dark:bg-[#111111]\">\n            <AnimatePresence mode=\"wait\">\n              <motion.div\n                key={activeSection.id}\n                initial={\n                  shouldReduceMotion\n                    ? { opacity: 0 }\n                    : { opacity: 0, y: 14, scale: 0.96 }\n                }\n                animate={{ opacity: 1, y: 0, scale: 1 }}\n                exit={\n                  shouldReduceMotion\n                    ? { opacity: 0 }\n                    : { opacity: 0, y: -14, scale: 0.96 }\n                }\n                transition={{ type: \"spring\", stiffness: 360, damping: 28 }}\n                className=\"flex h-full flex-col justify-between\"\n              >\n                <div className=\"flex items-center justify-between\">\n                  <div className=\"flex h-10 w-10 items-center justify-center rounded-xl bg-neutral-900 text-white dark:bg-white dark:text-black\">\n                    {icons[activeIndex % icons.length]}\n                  </div>\n                  <span className=\"rounded-full border border-neutral-200 bg-white px-2.5 py-0.5 font-mono text-[10px] font-semibold text-neutral-600 dark:border-neutral-800 dark:bg-neutral-950 dark:text-neutral-300\">\n                    Step {activeIndex + 1}/{sections.length}\n                  </span>\n                </div>\n\n                {/* Center Visual Graphic */}\n                <div className=\"my-auto rounded-xl border border-neutral-200/80 bg-white p-3.5 shadow-2xs dark:border-neutral-800 dark:bg-[#0A0A0A]\">\n                  <div className=\"font-mono text-[10px] uppercase tracking-wider text-neutral-400\">\n                    {activeSection.metricLabel}\n                  </div>\n                  <div className=\"mt-1 font-mono text-lg font-bold tracking-tight text-neutral-950 dark:text-white\">\n                    {activeSection.metricValue}\n                  </div>\n                  <div className=\"mt-2.5 h-1.5 w-full overflow-hidden rounded-full bg-neutral-100 dark:bg-neutral-900\">\n                    <motion.div\n                      initial={{ width: \"20%\" }}\n                      animate={{\n                        width: `${((activeIndex + 1) / sections.length) * 100}%`,\n                      }}\n                      transition={{ type: \"spring\", stiffness: 300, damping: 28 }}\n                      className=\"h-full rounded-full bg-neutral-900 dark:bg-white\"\n                    />\n                  </div>\n                </div>\n\n                <div className=\"font-mono text-[10px] text-neutral-400\">\n                  Synced Sticky Stage\n                </div>\n              </motion.div>\n            </AnimatePresence>\n          </div>\n        </div>\n      </div>\n    </div>\n  );\n}\n\nexport default StickyScrollStory;\n",
          "type": "registry:ui",
          "target": "components/ui/sticky-scroll-story.tsx"
        },
        {
          "path": "lib/utils.ts",
          "content": "import { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...inputs: ClassValue[]) {\n  return twMerge(clsx(inputs));\n}\n\nexport async function copyToClipboard(text: string): Promise<boolean> {\n  if (typeof window === \"undefined\") return false;\n\n  try {\n    if (navigator.clipboard && window.isSecureContext) {\n      await navigator.clipboard.writeText(text);\n      return true;\n    }\n\n    const textArea = document.createElement(\"textarea\");\n    textArea.value = text;\n    textArea.style.position = \"fixed\";\n    textArea.style.left = \"-999999px\";\n    textArea.style.top = \"-999999px\";\n    document.body.appendChild(textArea);\n    textArea.focus();\n    textArea.select();\n    const succeeded = document.execCommand(\"copy\");\n    textArea.remove();\n    return succeeded;\n  } catch {\n    return false;\n  }\n}\n",
          "type": "registry:lib",
          "target": "lib/utils.ts"
        }
      ]
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "sticky-sub-nav",
      "type": "registry:ui",
      "title": "Sticky Sub-Nav",
      "author": "Rishabh Bose <https://theb0se.vercel.app/>",
      "description": "Product-level frosted sticky sub-navigation bar that smoothly slides into view once the hero section scrolls out, pairing the product title on the left with a 'Buy' CTA pill on the right.",
      "dependencies": [
        "framer-motion",
        "lucide-react",
        "clsx",
        "tailwind-merge"
      ],
      "files": [
        {
          "path": "components/ui/sticky-sub-nav.tsx",
          "content": "\"use client\";\n\nimport React, { useState, useRef } from \"react\";\nimport { AnimatePresence, motion, useReducedMotion } from \"framer-motion\";\nimport { Check, ArrowDown, Monitor, Cpu, Sparkles, Layers } from \"lucide-react\";\nimport { cn } from \"@/lib/utils\";\n\nexport interface SubNavLink {\n  id: string;\n  label: string;\n}\n\nexport interface StickySubNavProps {\n  /** Product title shown on the left of the sub-nav */\n  productTitle?: string;\n  /** Price or subtitle shown next to the CTA */\n  priceLabel?: string;\n  /** Label for the right-hand primary action button */\n  ctaLabel?: string;\n  /** Navigation links inside the bar */\n  links?: SubNavLink[];\n  /** Callback fired when the Buy / CTA button is clicked */\n  onBuy?: () => void;\n  className?: string;\n}\n\nconst DEFAULT_LINKS: SubNavLink[] = [\n  { id: \"overview\", label: \"Overview\" },\n  { id: \"specs\", label: \"Tech Specs\" },\n  { id: \"compare\", label: \"Compare\" },\n];\n\nexport function StickySubNav({\n  productTitle = \"Studio Display Pro\",\n  priceLabel = \"$1,599\",\n  ctaLabel = \"Buy\",\n  links = DEFAULT_LINKS,\n  onBuy,\n  className,\n}: StickySubNavProps) {\n  const shouldReduceMotion = useReducedMotion() ?? false;\n  const [isStuck, setIsStuck] = useState(false);\n  const [activeTab, setActiveTab] = useState(links[0]?.id ?? \"overview\");\n  const [purchased, setPurchased] = useState(false);\n  const scrollRef = useRef<HTMLDivElement>(null);\n\n  const handleScroll = (e: React.UIEvent<HTMLDivElement>) => {\n    const scrollTop = e.currentTarget.scrollTop;\n    setIsStuck(scrollTop > 110);\n  };\n\n  const handleBuyClick = () => {\n    setPurchased(true);\n    onBuy?.();\n    setTimeout(() => setPurchased(false), 1800);\n  };\n\n  return (\n    <div\n      className={cn(\n        \"relative w-full max-w-xl overflow-hidden rounded-3xl border border-neutral-200 bg-white shadow-sm dark:border-neutral-800 dark:bg-[#0A0A0A]\",\n        className\n      )}\n    >\n      {/* Floating / Sticky Product Sub-Nav that reveals once Hero scrolls out */}\n      <AnimatePresence>\n        {isStuck && (\n          <motion.header\n            initial={\n              shouldReduceMotion ? { opacity: 0 } : { opacity: 0, y: -48 }\n            }\n            animate={{ opacity: 1, y: 0 }}\n            exit={shouldReduceMotion ? { opacity: 0 } : { opacity: 0, y: -48 }}\n            transition={{ type: \"spring\", stiffness: 420, damping: 32 }}\n            className=\"absolute inset-x-0 top-0 z-30 flex h-12 items-center justify-between border-b border-neutral-200/80 bg-white/85 px-5 backdrop-blur-xl dark:border-neutral-800/80 dark:bg-[#0A0A0A]/85\"\n          >\n            {/* Left: Product Title */}\n            <div className=\"flex items-center gap-2\">\n              <span className=\"text-sm font-bold tracking-tight text-neutral-950 dark:text-white\">\n                {productTitle}\n              </span>\n            </div>\n\n            {/* Center: Section Links */}\n            <nav className=\"hidden items-center gap-5 sm:flex\">\n              {links.map((link) => (\n                <button\n                  key={link.id}\n                  type=\"button\"\n                  onClick={() => setActiveTab(link.id)}\n                  className={cn(\n                    \"text-xs transition-colors\",\n                    activeTab === link.id\n                      ? \"font-semibold text-neutral-950 dark:text-white\"\n                      : \"text-neutral-500 hover:text-neutral-900 dark:text-neutral-400 dark:hover:text-white\"\n                  )}\n                >\n                  {link.label}\n                </button>\n              ))}\n            </nav>\n\n            {/* Right: Price + Buy Pill */}\n            <div className=\"flex items-center gap-3\">\n              <span className=\"hidden font-mono text-xs text-neutral-500 dark:text-neutral-400 sm:inline\">\n                {priceLabel}\n              </span>\n              <button\n                type=\"button\"\n                onClick={handleBuyClick}\n                className=\"inline-flex h-7 items-center gap-1 rounded-full bg-neutral-900 px-3.5 text-xs font-semibold text-white transition-transform active:scale-95 dark:bg-white dark:text-black\"\n              >\n                {purchased ? (\n                  <>\n                    <Check className=\"h-3 w-3\" />\n                    <span>Added</span>\n                  </>\n                ) : (\n                  <span>{ctaLabel}</span>\n                )}\n              </button>\n            </div>\n          </motion.header>\n        )}\n      </AnimatePresence>\n\n      {/* Scrollable Demo Viewport */}\n      <div\n        ref={scrollRef}\n        data-fullscreen-scroll\n        onScroll={handleScroll}\n        className=\"max-h-[320px] overflow-y-auto\"\n      >\n        {/* Hero Section */}\n        <div className=\"flex flex-col items-center justify-center border-b border-neutral-100 bg-neutral-50/60 px-6 py-12 text-center dark:border-neutral-900 dark:bg-[#111111]\">\n          <span className=\"rounded-full border border-neutral-200 bg-white px-2.5 py-0.5 font-mono text-[10px] font-semibold uppercase tracking-wider text-neutral-500 dark:border-neutral-800 dark:bg-neutral-950 dark:text-neutral-400\">\n            5K Retina XDR Display\n          </span>\n          <h2 className=\"mt-2.5 text-2xl font-bold tracking-tight text-neutral-950 dark:text-white sm:text-3xl\">\n            {productTitle}\n          </h2>\n          <p className=\"mt-1.5 text-xs text-neutral-500 dark:text-neutral-400 sm:text-sm\">\n            From {priceLabel} · Scroll down to reveal the sticky product sub-nav\n          </p>\n          <div className=\"mt-4 inline-flex items-center gap-1.5 text-[11px] font-medium text-neutral-400\">\n            <ArrowDown className=\"h-3.5 w-3.5 animate-bounce\" />\n            <span>Scroll down</span>\n          </div>\n        </div>\n\n        {/* Product Details Content (tall enough to scroll in both compact and full-screen viewports) */}\n        <div className=\"grid grid-cols-1 gap-4 p-6 pb-32 sm:grid-cols-2\">\n          {[\n            {\n              icon: <Monitor className=\"h-4 w-4\" />,\n              title: \"True-to-Life 1600 Nits Peak HDR\",\n              body: \"Anti-reflective nano-texture glass scatters ambient light to minimize glare in bright studio environments.\",\n            },\n            {\n              icon: <Cpu className=\"h-4 w-4\" />,\n              title: \"Thunderbolt 4 Single-Cable Hub\",\n              body: \"Delivers 96W host charging plus three downstream USB-C ports for high-speed studio peripherals.\",\n            },\n            {\n              icon: <Sparkles className=\"h-4 w-4\" />,\n              title: \"12MP Ultra Wide Camera with Center Stage\",\n              body: \"Machine-learning camera framing keeps you centered automatically as you move around your workspace.\",\n            },\n            {\n              icon: <Layers className=\"h-4 w-4\" />,\n              title: \"Machined Aluminum Tilt & Height Stand\",\n              body: \"Counterbalanced arm lets you adjust angle and elevation with effortless one-finger precision.\",\n            },\n            {\n              icon: <Monitor className=\"h-4 w-4\" />,\n              title: \"Reference Modes for Color Grading\",\n              body: \"Factory-calibrated P3 wide color gamut with 10-bit depth for broadcast video and print workflows.\",\n            },\n            {\n              icon: <Cpu className=\"h-4 w-4\" />,\n              title: \"Six-Speaker Spatial Audio Array\",\n              body: \"Four force-cancelling woofers produce rich, distortion-free bass and crystal-clear dialogue.\",\n            },\n          ].map((block) => (\n            <div\n              key={block.title}\n              className=\"rounded-2xl border border-neutral-200/80 bg-neutral-50/50 p-5 dark:border-neutral-800/80 dark:bg-neutral-900/40\"\n            >\n              <div className=\"mb-2.5 flex h-8 w-8 items-center justify-center rounded-lg border border-neutral-200 bg-white text-neutral-700 dark:border-neutral-800 dark:bg-neutral-950 dark:text-neutral-300\">\n                {block.icon}\n              </div>\n              <h4 className=\"text-sm font-semibold text-neutral-950 dark:text-white\">\n                {block.title}\n              </h4>\n              <p className=\"mt-1.5 text-xs leading-relaxed text-neutral-600 dark:text-neutral-400\">\n                {block.body}\n              </p>\n            </div>\n          ))}\n        </div>\n      </div>\n    </div>\n  );\n}\n\nexport default StickySubNav;\n",
          "type": "registry:ui",
          "target": "components/ui/sticky-sub-nav.tsx"
        },
        {
          "path": "lib/utils.ts",
          "content": "import { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...inputs: ClassValue[]) {\n  return twMerge(clsx(inputs));\n}\n\nexport async function copyToClipboard(text: string): Promise<boolean> {\n  if (typeof window === \"undefined\") return false;\n\n  try {\n    if (navigator.clipboard && window.isSecureContext) {\n      await navigator.clipboard.writeText(text);\n      return true;\n    }\n\n    const textArea = document.createElement(\"textarea\");\n    textArea.value = text;\n    textArea.style.position = \"fixed\";\n    textArea.style.left = \"-999999px\";\n    textArea.style.top = \"-999999px\";\n    document.body.appendChild(textArea);\n    textArea.focus();\n    textArea.select();\n    const succeeded = document.execCommand(\"copy\");\n    textArea.remove();\n    return succeeded;\n  } catch {\n    return false;\n  }\n}\n",
          "type": "registry:lib",
          "target": "lib/utils.ts"
        }
      ]
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "streak-counter",
      "type": "registry:ui",
      "title": "Streak Counter",
      "author": "Rishabh Bose <https://theb0se.vercel.app/>",
      "description": "Duolingo-style gamified streak counter featuring a pulsing animated flame avatar with floating sparks, 7-day calendar circle row with completion checks, freeze shield, and celebratory confetti explosion.",
      "dependencies": [
        "framer-motion",
        "lucide-react",
        "clsx",
        "tailwind-merge"
      ],
      "files": [
        {
          "path": "components/ui/streak-counter.tsx",
          "content": "\"use client\";\n\nimport React, { useState } from \"react\";\nimport { motion, AnimatePresence } from \"framer-motion\";\nimport {\n  Flame,\n  Shield,\n  Check,\n  Sparkles,\n  Trophy,\n  Zap,\n  RotateCcw,\n  Calendar,\n  ChevronRight,\n  Lock,\n} from \"lucide-react\";\nimport { cn } from \"@/lib/utils\";\n\nexport interface DayStatus {\n  day: string; // e.g. \"M\", \"T\", \"W\"\n  label: string; // e.g. \"Mon\"\n  completed: boolean;\n  isToday?: boolean;\n}\n\nexport interface StreakCounterProps {\n  /** Initial streak length in days */\n  initialStreak?: number;\n  /** Whether today's streak is already claimed */\n  initialClaimed?: boolean;\n  /** Whether a streak freeze shield is equipped */\n  hasStreakFreeze?: boolean;\n  /** Callback fired when streak is claimed */\n  onClaim?: (newStreak: number) => void;\n  /** Extra container className */\n  className?: string;\n}\n\nconst DEFAULT_DAYS: DayStatus[] = [\n  { day: \"M\", label: \"Mon\", completed: true },\n  { day: \"T\", label: \"Tue\", completed: true },\n  { day: \"W\", label: \"Wed\", completed: true },\n  { day: \"T\", label: \"Thu\", completed: true },\n  { day: \"F\", label: \"Fri\", completed: true },\n  { day: \"S\", label: \"Sat\", completed: false, isToday: true },\n  { day: \"S\", label: \"Sun\", completed: false },\n];\n\nconst CONFETTI_COLORS = [\n  \"#FF9600\", // Duolingo Orange\n  \"#FF4B4B\", // Duolingo Coral\n  \"#58CC02\", // Duolingo Green\n  \"#1CB0F6\", // Duolingo Sky\n  \"#FFD900\", // Gold\n  \"#CE82FF\", // Purple\n];\n\nexport function StreakCounter({\n  initialStreak = 14,\n  initialClaimed = false,\n  hasStreakFreeze = true,\n  onClaim,\n  className,\n}: StreakCounterProps) {\n  const [streak, setStreak] = useState(initialStreak);\n  const [isClaimedToday, setIsClaimedToday] = useState(initialClaimed);\n  const [freezeEquipped, setFreezeEquipped] = useState(hasStreakFreeze);\n  const [confettiActive, setConfettiActive] = useState(false);\n  const [days, setDays] = useState<DayStatus[]>(DEFAULT_DAYS);\n\n  // Milestone progression calculation\n  const nextMilestone = streak < 7 ? 7 : streak < 21 ? 21 : streak < 30 ? 30 : streak < 50 ? 50 : 100;\n  const progressPercent = Math.min(100, Math.round((streak / nextMilestone) * 100));\n\n  const handleClaimStreak = () => {\n    if (isClaimedToday) return;\n\n    const newStreak = streak + 1;\n    setStreak(newStreak);\n    setIsClaimedToday(true);\n    setConfettiActive(true);\n\n    // Mark today as completed in calendar\n    setDays((prev) =>\n      prev.map((d) => (d.isToday ? { ...d, completed: true } : d))\n    );\n\n    onClaim?.(newStreak);\n\n    setTimeout(() => {\n      setConfettiActive(false);\n    }, 2500);\n  };\n\n  const handleReset = () => {\n    setStreak(initialStreak);\n    setIsClaimedToday(false);\n    setDays(DEFAULT_DAYS);\n    setConfettiActive(false);\n  };\n\n  return (\n    <div\n      data-fullscreen-scroll\n      className={cn(\n        \"relative flex min-h-[520px] w-full flex-col justify-between overflow-hidden rounded-2xl border border-neutral-200 bg-neutral-50/70 p-4 sm:p-8 dark:border-neutral-800 dark:bg-neutral-950\",\n        className\n      )}\n    >\n      {/* Background warm flame glow */}\n      <div\n        aria-hidden=\"true\"\n        className=\"pointer-events-none absolute left-1/2 top-1/3 -translate-x-1/2 -translate-y-1/2 h-80 w-80 rounded-full bg-amber-500/10 blur-[100px] dark:bg-amber-500/15\"\n      />\n\n      {/* Header bar */}\n      <div className=\"relative z-10 flex flex-wrap items-center justify-between gap-3 pb-2\">\n        <div className=\"flex items-center gap-3\">\n          <div className=\"flex h-9 w-9 items-center justify-center rounded-xl bg-orange-500/10 text-orange-600 dark:bg-orange-500/20 dark:text-orange-400\">\n            <Flame className=\"h-5 w-5 fill-current\" />\n          </div>\n          <div>\n            <div className=\"flex items-center gap-2\">\n              <span className=\"text-sm font-semibold tracking-tight text-neutral-900 dark:text-neutral-100\">\n                Duolingo Gamified Streak Counter\n              </span>\n              <span className=\"rounded-full bg-orange-500/10 px-2 py-0.5 text-[10px] font-semibold text-orange-600 dark:text-orange-400\">\n                Habit Loop\n              </span>\n            </div>\n            <p className=\"text-xs text-neutral-500 dark:text-neutral-400\">\n              Pulsing flame engine, 7-day calendar row, freeze shield, and confetti explosion\n            </p>\n          </div>\n        </div>\n\n        <div className=\"flex items-center gap-2\">\n          {/* Streak Freeze Badge */}\n          <button\n            type=\"button\"\n            onClick={() => setFreezeEquipped(!freezeEquipped)}\n            className={cn(\n              \"flex items-center gap-1.5 rounded-full border px-3 py-1 text-xs font-semibold transition shadow-xs\",\n              freezeEquipped\n                ? \"border-sky-500/30 bg-sky-500/10 text-sky-600 dark:text-sky-400\"\n                : \"border-neutral-300 bg-white text-neutral-400 dark:border-neutral-700 dark:bg-neutral-900\"\n            )}\n          >\n            <Shield className={cn(\"h-3.5 w-3.5\", freezeEquipped && \"fill-current\")} />\n            <span>{freezeEquipped ? \"Freeze Equipped\" : \"Freeze Inactive\"}</span>\n          </button>\n        </div>\n      </div>\n\n      {/* Main Center Gamification Card */}\n      <div className=\"relative z-10 my-auto flex flex-col items-center justify-center py-6\">\n        <div className=\"relative w-full max-w-md rounded-3xl border border-neutral-200/90 bg-white p-6 shadow-xl shadow-neutral-950/5 dark:border-neutral-800/90 dark:bg-neutral-900 sm:p-8 dark:shadow-black/40 text-center\">\n          {/* Confetti Explosion particles */}\n          <AnimatePresence>\n            {confettiActive && (\n              <div className=\"pointer-events-none absolute inset-0 overflow-hidden rounded-3xl z-30\">\n                {Array.from({ length: 36 }).map((_, i) => {\n                  const angle = (i * 360) / 36;\n                  const rad = (angle * Math.PI) / 180;\n                  const distance = 80 + (i % 6) * 28;\n                  const x = Math.cos(rad) * distance;\n                  const y = Math.sin(rad) * distance - 30;\n                  const color = CONFETTI_COLORS[i % CONFETTI_COLORS.length];\n\n                  return (\n                    <motion.div\n                      key={`confetti-${i}`}\n                      initial={{ scale: 0, x: 0, y: 0, opacity: 1, rotate: 0 }}\n                      animate={{\n                        scale: [0, 1.2, 0.8],\n                        x,\n                        y: [0, y, y + 60],\n                        opacity: [1, 1, 0],\n                        rotate: [0, 180, 360],\n                      }}\n                      transition={{ duration: 1.8, ease: \"easeOut\" }}\n                      style={{\n                        position: \"absolute\",\n                        left: \"50%\",\n                        top: \"30%\",\n                        width: i % 2 === 0 ? 8 : 12,\n                        height: i % 2 === 0 ? 8 : 6,\n                        backgroundColor: color,\n                        borderRadius: i % 3 === 0 ? \"50%\" : \"2px\",\n                      }}\n                    />\n                  );\n                })}\n              </div>\n            )}\n          </AnimatePresence>\n\n          {/* PULSING FLAME ICON AVATAR */}\n          <div className=\"relative mx-auto mb-3 flex h-24 w-24 items-center justify-center\">\n            {/* Outer heat pulse wave */}\n            <motion.div\n              animate={{\n                scale: [1, 1.25, 1],\n                opacity: [0.3, 0.6, 0.3],\n              }}\n              transition={{\n                duration: 2.2,\n                repeat: Infinity,\n                ease: \"easeInOut\",\n              }}\n              className=\"absolute inset-0 rounded-full bg-gradient-to-tr from-amber-500/30 to-orange-600/30 blur-lg\"\n            />\n\n            {/* Floating Sparks */}\n            <motion.div\n              animate={{\n                y: [-6, -22, -6],\n                opacity: [0, 1, 0],\n                scale: [0.5, 1, 0.5],\n              }}\n              transition={{ duration: 1.6, repeat: Infinity, ease: \"easeOut\" }}\n              className=\"absolute -top-1 left-7 text-amber-400\"\n            >\n              <Sparkles className=\"h-4 w-4\" />\n            </motion.div>\n            <motion.div\n              animate={{\n                y: [-4, -18, -4],\n                opacity: [0, 1, 0],\n                scale: [0.4, 0.9, 0.4],\n              }}\n              transition={{ duration: 1.4, repeat: Infinity, delay: 0.5, ease: \"easeOut\" }}\n              className=\"absolute -top-2 right-6 text-orange-400\"\n            >\n              <Sparkles className=\"h-3 w-3\" />\n            </motion.div>\n\n            {/* Core Animated Flame */}\n            <motion.div\n              animate={{\n                scale: [1, 1.07, 0.98, 1.05, 1],\n                rotate: [0, -3, 3, -1, 0],\n              }}\n              transition={{\n                duration: 2.4,\n                repeat: Infinity,\n                ease: \"easeInOut\",\n              }}\n              className=\"relative flex h-20 w-20 items-center justify-center rounded-2xl bg-gradient-to-tr from-orange-600 via-amber-500 to-yellow-400 shadow-xl shadow-orange-500/30\"\n            >\n              <Flame className=\"h-12 w-12 text-white fill-white drop-shadow-md\" />\n            </motion.div>\n          </div>\n\n          {/* LARGE STREAK NUMBER */}\n          <div className=\"space-y-0.5\">\n            <div className=\"flex items-center justify-center gap-2\">\n              <AnimatePresence mode=\"popLayout\" initial={false}>\n                <motion.span\n                  key={streak}\n                  initial={{ y: 15, opacity: 0, scale: 0.8 }}\n                  animate={{ y: 0, opacity: 1, scale: 1 }}\n                  exit={{ y: -15, opacity: 0 }}\n                  transition={{ type: \"spring\", stiffness: 450, damping: 25 }}\n                  className=\"font-mono text-4xl font-black tracking-tight text-neutral-900 dark:text-white sm:text-5xl\"\n                >\n                  {streak}\n                </motion.span>\n              </AnimatePresence>\n              <span className=\"text-xl font-bold uppercase tracking-wider text-orange-500 sm:text-2xl\">\n                DAYS\n              </span>\n            </div>\n            <p className=\"text-xs font-semibold text-neutral-500 dark:text-neutral-400\">\n              {isClaimedToday\n                ? \"You've extended your streak today! Keep the flame alive.\"\n                : \"Practice now to lock in today's streak!\"}\n            </p>\n          </div>\n\n          {/* 7-DAY CALENDAR ROW */}\n          <div className=\"my-6 rounded-2xl border border-neutral-100 bg-neutral-50/80 p-3.5 dark:border-neutral-800 dark:bg-neutral-950/60\">\n            <div className=\"mb-2.5 flex items-center justify-between text-[11px] font-semibold text-neutral-500\">\n              <span className=\"flex items-center gap-1\">\n                <Calendar className=\"h-3 w-3\" />\n                This Week\n              </span>\n              <span>\n                {days.filter((d) => d.completed).length} / 7 days\n              </span>\n            </div>\n\n            <div className=\"grid grid-cols-7 gap-2\">\n              {days.map((item, idx) => {\n                return (\n                  <div key={idx} className=\"flex flex-col items-center gap-1.5\">\n                    <span className=\"font-mono text-[10px] font-bold text-neutral-400\">\n                      {item.day}\n                    </span>\n\n                    <motion.div\n                      whileHover={{ scale: 1.1 }}\n                      className={cn(\n                        \"relative flex h-8 w-8 sm:h-9 sm:w-9 items-center justify-center rounded-full font-bold transition-all shadow-xs\",\n                        item.completed\n                          ? \"bg-gradient-to-tr from-orange-500 to-amber-400 text-white shadow-orange-500/20\"\n                          : item.isToday\n                          ? \"border-2 border-orange-500 bg-orange-500/10 text-orange-600 dark:text-orange-400 ring-2 ring-orange-500/20 animate-pulse\"\n                          : \"border border-neutral-200 bg-white text-neutral-400 dark:border-neutral-800 dark:bg-neutral-900\"\n                      )}\n                    >\n                      {item.completed ? (\n                        <Check className=\"h-4 w-4 stroke-[3]\" />\n                      ) : item.isToday ? (\n                        <Flame className=\"h-4 w-4 fill-current\" />\n                      ) : (\n                        <Lock className=\"h-3 w-3 opacity-40\" />\n                      )}\n                    </motion.div>\n                  </div>\n                );\n              })}\n            </div>\n          </div>\n\n          {/* MILESTONE PROGRESSION BAR */}\n          <div className=\"mb-6 space-y-1.5 text-left\">\n            <div className=\"flex items-center justify-between text-xs font-semibold\">\n              <span className=\"flex items-center gap-1.5 text-neutral-800 dark:text-neutral-200\">\n                <Trophy className=\"h-3.5 w-3.5 text-amber-500\" />\n                Next Goal: {nextMilestone}-Day Club\n              </span>\n              <span className=\"font-mono text-[11px] text-neutral-400\">\n                {nextMilestone - streak} days left\n              </span>\n            </div>\n            <div className=\"h-2 w-full overflow-hidden rounded-full bg-neutral-100 dark:bg-neutral-800\">\n              <motion.div\n                initial={{ width: 0 }}\n                animate={{ width: `${progressPercent}%` }}\n                transition={{ duration: 0.8, ease: \"easeOut\" }}\n                className=\"h-full rounded-full bg-gradient-to-r from-orange-500 to-amber-400\"\n              />\n            </div>\n          </div>\n\n          {/* PRIMARY INTERACTIVE CLAIM / PRACTICE BUTTON */}\n          <motion.button\n            type=\"button\"\n            whileHover={{ scale: 1.02 }}\n            whileTap={{ scale: 0.96 }}\n            onClick={handleClaimStreak}\n            disabled={isClaimedToday}\n            className={cn(\n              \"flex w-full items-center justify-center gap-2 rounded-2xl py-3.5 text-sm font-bold uppercase tracking-wider shadow-lg transition\",\n              isClaimedToday\n                ? \"bg-neutral-100 text-neutral-400 border border-neutral-200 dark:bg-neutral-800 dark:text-neutral-500 dark:border-neutral-700 cursor-default\"\n                : \"bg-gradient-to-r from-orange-500 via-amber-500 to-orange-600 text-white shadow-orange-500/30 hover:brightness-105 active:brightness-95\"\n            )}\n          >\n            {isClaimedToday ? (\n              <>\n                <Check className=\"h-4 w-4 stroke-[3]\" />\n                <span>Streak Protected Today</span>\n              </>\n            ) : (\n              <>\n                <Zap className=\"h-4 w-4 fill-white\" />\n                <span>Claim Today&apos;s Streak</span>\n              </>\n            )}\n          </motion.button>\n        </div>\n      </div>\n\n      {/* Footer Interactive Stage Controls */}\n      <div className=\"relative z-10 flex flex-wrap items-center justify-between gap-3 border-t border-neutral-200/80 pt-4 dark:border-neutral-800/80\">\n        <div className=\"flex flex-wrap items-center gap-2 text-xs text-neutral-500\">\n          <span>Set Streak:</span>\n          {[7, 14, 30, 100].map((count) => (\n            <button\n              key={count}\n              type=\"button\"\n              onClick={() => {\n                setStreak(count);\n                setIsClaimedToday(false);\n              }}\n              className={cn(\n                \"rounded-md px-2 py-0.5 text-[11px] font-mono font-medium transition\",\n                streak === count\n                  ? \"bg-orange-500 text-white\"\n                  : \"bg-neutral-200/60 text-neutral-700 hover:bg-neutral-200 dark:bg-neutral-800 dark:text-neutral-300 dark:hover:bg-neutral-700\"\n              )}\n            >\n              {count}d\n            </button>\n          ))}\n        </div>\n\n        <button\n          type=\"button\"\n          onClick={handleReset}\n          className=\"flex items-center gap-1 text-xs text-neutral-500 underline transition hover:text-neutral-900 dark:text-neutral-400 dark:hover:text-white\"\n        >\n          <RotateCcw className=\"h-3 w-3\" />\n          <span>Reset Streak Demo</span>\n        </button>\n      </div>\n    </div>\n  );\n}\n\nexport default StreakCounter;\n",
          "type": "registry:ui",
          "target": "components/ui/streak-counter.tsx"
        },
        {
          "path": "lib/utils.ts",
          "content": "import { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...inputs: ClassValue[]) {\n  return twMerge(clsx(inputs));\n}\n\nexport async function copyToClipboard(text: string): Promise<boolean> {\n  if (typeof window === \"undefined\") return false;\n\n  try {\n    if (navigator.clipboard && window.isSecureContext) {\n      await navigator.clipboard.writeText(text);\n      return true;\n    }\n\n    const textArea = document.createElement(\"textarea\");\n    textArea.value = text;\n    textArea.style.position = \"fixed\";\n    textArea.style.left = \"-999999px\";\n    textArea.style.top = \"-999999px\";\n    document.body.appendChild(textArea);\n    textArea.focus();\n    textArea.select();\n    const succeeded = document.execCommand(\"copy\");\n    textArea.remove();\n    return succeeded;\n  } catch {\n    return false;\n  }\n}\n",
          "type": "registry:lib",
          "target": "lib/utils.ts"
        }
      ]
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "sunrise-horizon",
      "type": "registry:ui",
      "title": "Sunrise Horizon",
      "author": "Rishabh Bose <https://theb0se.vercel.app/>",
      "description": "Layered atmospheric sky background that interpolates zenith, horizon, and solar glow gradients along a continuous solar arc from dawn to noon to dusk.",
      "dependencies": [
        "lucide-react",
        "clsx",
        "tailwind-merge"
      ],
      "files": [
        {
          "path": "components/ui/sunrise-horizon.tsx",
          "content": "\"use client\";\n\nimport React, { useState, useEffect } from \"react\";\nimport { Sun, Play, Pause } from \"lucide-react\";\nimport { cn } from \"@/lib/utils\";\n\nexport type TimePreset = \"dawn\" | \"noon\" | \"dusk\";\n\nexport interface SunriseHorizonProps {\n  /** Time of day from 0 (dawn) to 0.5 (noon) to 1 (dusk), or named preset. Default: \"dawn\" */\n  time?: number | TimePreset;\n  /** Continuously cycle through dawn, noon, and dusk. Default: true */\n  autoplay?: boolean;\n  /** Diameter of the sun orb in pixels. Default: 96 */\n  sunSize?: number;\n  /** Overlay subtle atmospheric film grain. Default: true */\n  grain?: boolean;\n  /** Optional foreground content */\n  children?: React.ReactNode;\n  className?: string;\n}\n\nconst PRESET_TO_TIME: Record<TimePreset, number> = {\n  dawn: 0.18,\n  noon: 0.5,\n  dusk: 0.84,\n};\n\nfunction lerpColor(hexA: string, hexB: string, t: number): string {\n  const a = parseInt(hexA.slice(1), 16);\n  const b = parseInt(hexB.slice(1), 16);\n  const r1 = (a >> 16) & 255;\n  const g1 = (a >> 8) & 255;\n  const b1 = a & 255;\n  const r2 = (b >> 16) & 255;\n  const g2 = (b >> 8) & 255;\n  const b2 = b & 255;\n  const r = Math.round(r1 + (r2 - r1) * t);\n  const g = Math.round(g1 + (g2 - g1) * t);\n  const bl = Math.round(b1 + (b2 - b1) * t);\n  return `rgb(${r}, ${g}, ${bl})`;\n}\n\nfunction getSkyPalette(t: number) {\n  // Keyframes: 0 = deep night/dawn, 0.25 = sunrise, 0.5 = bright noon, 0.8 = golden dusk, 1 = night\n  const stops = [\n    {\n      pos: 0,\n      zenith: \"#070B19\",\n      mid: \"#1E1B4B\",\n      horizon: \"#7C2D12\",\n      glow: \"#F97316\",\n      sun: \"#FDBA74\",\n    },\n    {\n      pos: 0.22,\n      zenith: \"#0F172A\",\n      mid: \"#581C87\",\n      horizon: \"#EA580C\",\n      glow: \"#FBBF24\",\n      sun: \"#FEF08A\",\n    },\n    {\n      pos: 0.5,\n      zenith: \"#0284C7\",\n      mid: \"#38BDF8\",\n      horizon: \"#BAE6FD\",\n      glow: \"#FEF9C3\",\n      sun: \"#FFFFFF\",\n    },\n    {\n      pos: 0.82,\n      zenith: \"#0F172A\",\n      mid: \"#4C1D95\",\n      horizon: \"#E11D48\",\n      glow: \"#FB923C\",\n      sun: \"#FDE047\",\n    },\n    {\n      pos: 1,\n      zenith: \"#050814\",\n      mid: \"#1E1B4B\",\n      horizon: \"#431407\",\n      glow: \"#EA580C\",\n      sun: \"#FDBA74\",\n    },\n  ];\n\n  const clamped = Math.max(0, Math.min(1, t));\n  let lower = stops[0];\n  let upper = stops[stops.length - 1];\n\n  for (let i = 0; i < stops.length - 1; i++) {\n    if (clamped >= stops[i].pos && clamped <= stops[i + 1].pos) {\n      lower = stops[i];\n      upper = stops[i + 1];\n      break;\n    }\n  }\n\n  const span = upper.pos - lower.pos || 1;\n  const localT = (clamped - lower.pos) / span;\n\n  return {\n    zenith: lerpColor(lower.zenith, upper.zenith, localT),\n    mid: lerpColor(lower.mid, upper.mid, localT),\n    horizon: lerpColor(lower.horizon, upper.horizon, localT),\n    glow: lerpColor(lower.glow, upper.glow, localT),\n    sun: lerpColor(lower.sun, upper.sun, localT),\n  };\n}\n\nexport function SunriseHorizon({\n  time = \"dawn\",\n  autoplay = true,\n  sunSize = 92,\n  grain = true,\n  children,\n  className,\n}: SunriseHorizonProps) {\n  const initialNumeric =\n    typeof time === \"number\" ? time : PRESET_TO_TIME[time] ?? 0.2;\n\n  const [currentTime, setCurrentTime] = useState(initialNumeric);\n  const [isPlaying, setIsPlaying] = useState(autoplay);\n\n  useEffect(() => {\n    setCurrentTime(\n      typeof time === \"number\" ? time : PRESET_TO_TIME[time] ?? 0.2\n    );\n  }, [time]);\n\n  useEffect(() => {\n    setIsPlaying(autoplay);\n  }, [autoplay]);\n\n  useEffect(() => {\n    if (!isPlaying) return;\n    let rafId: number;\n    let last = performance.now();\n\n    const tick = (now: number) => {\n      const dt = (now - last) / 1000;\n      last = now;\n      setCurrentTime((prev) => (prev + dt * 0.055) % 1);\n      rafId = requestAnimationFrame(tick);\n    };\n\n    rafId = requestAnimationFrame(tick);\n    return () => cancelAnimationFrame(rafId);\n  }, [isPlaying]);\n\n  const palette = getSkyPalette(currentTime);\n\n  // Sun arc trajectory: X goes from 18% to 82%, Y rises in an arc (sin(pi * t))\n  const sunX = 18 + currentTime * 64;\n  const arcHeight = Math.sin(currentTime * Math.PI); // 0 at edges, 1 at noon\n  const sunBottomPct = 14 + arcHeight * 54;\n\n  return (\n    <div\n      data-fullscreen-scroll\n      style={\n        {\n          \"--time\": currentTime.toFixed(3),\n          background: `linear-gradient(180deg, ${palette.zenith} 0%, ${palette.mid} 48%, ${palette.horizon} 85%, ${palette.glow} 100%)`,\n        } as React.CSSProperties\n      }\n      className={cn(\n        \"relative flex min-h-[360px] w-full flex-col justify-between overflow-hidden rounded-3xl border border-neutral-200 shadow-sm dark:border-neutral-800\",\n        className\n      )}\n    >\n      {/* Radial Horizon Glow */}\n      <div\n        aria-hidden=\"true\"\n        style={{\n          left: `${sunX}%`,\n          bottom: `${Math.max(8, sunBottomPct - 10)}%`,\n          width: sunSize * 3.8,\n          height: sunSize * 3.8,\n          background: `radial-gradient(circle, ${palette.glow} 0%, transparent 70%)`,\n          opacity: 0.75,\n        }}\n        className=\"pointer-events-none absolute -translate-x-1/2 translate-y-1/2 rounded-full blur-2xl\"\n      />\n\n      {/* Sun Orb */}\n      <div\n        aria-hidden=\"true\"\n        style={{\n          left: `${sunX}%`,\n          bottom: `${sunBottomPct}%`,\n          width: sunSize,\n          height: sunSize,\n          background: `radial-gradient(circle, ${palette.sun} 0%, ${palette.glow} 85%)`,\n          boxShadow: `0 0 ${sunSize * 0.7}px ${palette.glow}`,\n        }}\n        className=\"pointer-events-none absolute -translate-x-1/2 translate-y-1/2 rounded-full\"\n      />\n\n      {/* Optional Film Grain */}\n      {grain && (\n        <div\n          aria-hidden=\"true\"\n          className=\"pointer-events-none absolute inset-0 opacity-[0.14] mix-blend-overlay [background-image:radial-gradient(rgba(255,255,255,0.6)_1px,transparent_0)] [background-size:3px_3px]\"\n        />\n      )}\n\n      {/* Layered Mountain / Ocean Silhouettes */}\n      <svg\n        aria-hidden=\"true\"\n        viewBox=\"0 0 1200 220\"\n        preserveAspectRatio=\"none\"\n        className=\"pointer-events-none absolute inset-x-0 bottom-0 h-32 w-full\"\n      >\n        {/* Distant Ridge */}\n        <path\n          d=\"M0,140 C220,75 410,165 650,95 C880,35 1040,125 1200,85 L1200,220 L0,220 Z\"\n          fill=\"rgba(10, 10, 24, 0.45)\"\n        />\n        {/* Mid Ridge */}\n        <path\n          d=\"M0,165 C280,120 520,185 820,125 C990,95 1110,150 1200,135 L1200,220 L0,220 Z\"\n          fill=\"rgba(8, 8, 18, 0.72)\"\n        />\n        {/* Foreground Silhouette */}\n        <path\n          d=\"M0,190 C340,165 690,205 1200,175 L1200,220 L0,220 Z\"\n          fill=\"#05050A\"\n        />\n      </svg>\n\n      {/* Foreground Content or Interactive Time Controller */}\n      <div className=\"relative z-10 flex flex-1 flex-col justify-between p-6\">\n        {children ?? (\n          <>\n            <div className=\"flex flex-wrap items-center justify-between gap-2\">\n              <span className=\"inline-flex items-center gap-1.5 rounded-full border border-white/20 bg-black/30 px-3 py-1 font-mono text-[11px] font-medium text-white backdrop-blur-md\">\n                <Sun className=\"h-3.5 w-3.5 text-amber-300\" />\n                Sunrise Horizon · --time: {currentTime.toFixed(2)}\n              </span>\n\n              <div className=\"flex items-center gap-1.5 rounded-full border border-white/20 bg-black/30 p-1 backdrop-blur-md\">\n                {([\"dawn\", \"noon\", \"dusk\"] as TimePreset[]).map((preset) => (\n                  <button\n                    key={preset}\n                    type=\"button\"\n                    onClick={() => {\n                      setIsPlaying(false);\n                      setCurrentTime(PRESET_TO_TIME[preset]);\n                    }}\n                    className={cn(\n                      \"rounded-full px-2.5 py-0.5 font-mono text-[10px] font-semibold uppercase transition-colors\",\n                      Math.abs(currentTime - PRESET_TO_TIME[preset]) < 0.08\n                        ? \"bg-white text-black\"\n                        : \"text-white/80 hover:text-white\"\n                    )}\n                  >\n                    {preset}\n                  </button>\n                ))}\n                <button\n                  type=\"button\"\n                  aria-label={isPlaying ? \"Pause cycle\" : \"Play cycle\"}\n                  onClick={() => setIsPlaying((p) => !p)}\n                  className=\"ml-1 flex h-5 w-5 items-center justify-center rounded-full bg-white/20 text-white hover:bg-white/30\"\n                >\n                  {isPlaying ? (\n                    <Pause className=\"h-2.5 w-2.5\" />\n                  ) : (\n                    <Play className=\"h-2.5 w-2.5\" />\n                  )}\n                </button>\n              </div>\n            </div>\n\n            <div className=\"my-auto max-w-md py-6\">\n              <h3 className=\"text-2xl font-bold tracking-tight text-white drop-shadow-sm sm:text-3xl\">\n                Dynamic Atmospheric Sky\n              </h3>\n              <p className=\"mt-1.5 text-xs leading-relaxed text-white/80 sm:text-sm\">\n                Layered zenith, horizon, and solar radial gradients interpolated\n                smoothly along a solar arc.\n              </p>\n            </div>\n\n            {/* Scrubber Bar */}\n            <div className=\"flex items-center gap-3 rounded-2xl border border-white/15 bg-black/35 px-4 py-2.5 backdrop-blur-md\">\n              <span className=\"font-mono text-[10px] uppercase text-white/70\">\n                Solar Arc\n              </span>\n              <input\n                type=\"range\"\n                min={0}\n                max={1}\n                step={0.01}\n                value={currentTime}\n                aria-label=\"Scrub time of day\"\n                onChange={(e) => {\n                  setIsPlaying(false);\n                  setCurrentTime(parseFloat(e.target.value));\n                }}\n                className=\"h-1.5 flex-1 cursor-pointer accent-white\"\n              />\n            </div>\n          </>\n        )}\n      </div>\n    </div>\n  );\n}\n\nexport default SunriseHorizon;\n",
          "type": "registry:ui",
          "target": "components/ui/sunrise-horizon.tsx"
        },
        {
          "path": "lib/utils.ts",
          "content": "import { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...inputs: ClassValue[]) {\n  return twMerge(clsx(inputs));\n}\n\nexport async function copyToClipboard(text: string): Promise<boolean> {\n  if (typeof window === \"undefined\") return false;\n\n  try {\n    if (navigator.clipboard && window.isSecureContext) {\n      await navigator.clipboard.writeText(text);\n      return true;\n    }\n\n    const textArea = document.createElement(\"textarea\");\n    textArea.value = text;\n    textArea.style.position = \"fixed\";\n    textArea.style.left = \"-999999px\";\n    textArea.style.top = \"-999999px\";\n    document.body.appendChild(textArea);\n    textArea.focus();\n    textArea.select();\n    const succeeded = document.execCommand(\"copy\");\n    textArea.remove();\n    return succeeded;\n  } catch {\n    return false;\n  }\n}\n",
          "type": "registry:lib",
          "target": "lib/utils.ts"
        }
      ]
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "swipe-cards",
      "type": "registry:ui",
      "title": "Swipe Cards",
      "author": "Rishabh Bose <https://theb0se.vercel.app/>",
      "description": "Tinder-style swipeable card deck with drag physics, rotational tilt proportional to delta X, floating LIKE and NOPE stamp overlays, stack scale-up, and rewind capabilities.",
      "dependencies": [
        "framer-motion",
        "lucide-react",
        "clsx",
        "tailwind-merge"
      ],
      "files": [
        {
          "path": "components/ui/swipe-cards.tsx",
          "content": "\"use client\";\n\nimport React, { useState } from \"react\";\nimport {\n  motion,\n  useMotionValue,\n  useTransform,\n  AnimatePresence,\n  PanInfo,\n} from \"framer-motion\";\nimport {\n  Heart,\n  X,\n  Star,\n  RotateCcw,\n  Zap,\n  MapPin,\n  Briefcase,\n  GraduationCap,\n  Sparkles,\n  Info,\n} from \"lucide-react\";\nimport { cn } from \"@/lib/utils\";\n\nexport interface ProfileCard {\n  id: string;\n  name: string;\n  age: number;\n  role: string;\n  location: string;\n  distance: string;\n  bio: string;\n  tags: string[];\n  gradient: string;\n  verified?: boolean;\n}\n\nexport interface SwipeCardsProps {\n  /** Array of card profiles */\n  profiles?: ProfileCard[];\n  /** Callback fired on swipe direction */\n  onSwipe?: (card: ProfileCard, direction: \"like\" | \"nope\" | \"superlike\") => void;\n  /** Extra container className */\n  className?: string;\n}\n\nconst DEFAULT_PROFILES: ProfileCard[] = [\n  {\n    id: \"card-1\",\n    name: \"Elena Rostova\",\n    age: 26,\n    role: \"Product Designer & Ceramicist\",\n    location: \"San Francisco, CA\",\n    distance: \"2 miles away\",\n    bio: \"Obsessed with Swiss typography, pour-over coffee, and hand-built stoneware. Looking for someone to explore hidden architecture spots with.\",\n    tags: [\"Design Systems\", \"Ceramics\", \"Matcha\", \"Architecture\"],\n    gradient: \"from-rose-600 via-pink-700 to-amber-600\",\n    verified: true,\n  },\n  {\n    id: \"card-2\",\n    name: \"Marcus Vance\",\n    age: 28,\n    role: \"Sound Engineer & Producer\",\n    location: \"Brooklyn, NY\",\n    distance: \"4 miles away\",\n    bio: \"Collecting vintage analog synthesizers and hunting down rare Japanese vinyl. Let's trade favorite B-sides over craft cider.\",\n    tags: [\"Vinyl Records\", \"Synthwave\", \"Hi-Fi Audio\", \"Film Photography\"],\n    gradient: \"from-indigo-600 via-purple-700 to-slate-900\",\n    verified: true,\n  },\n  {\n    id: \"card-3\",\n    name: \"Sora Takahashi\",\n    age: 25,\n    role: \"Landscape Architect\",\n    location: \"Seattle, WA\",\n    distance: \"3 miles away\",\n    bio: \"Designing botanical conservatories and green rooftop gardens. Always down for early morning bouldering or botanical garden walks.\",\n    tags: [\"Bouldering\", \"Botanicals\", \"Green Design\", \"Trail Running\"],\n    gradient: \"from-emerald-600 via-teal-700 to-cyan-900\",\n    verified: true,\n  },\n  {\n    id: \"card-4\",\n    name: \"Julian Brooks\",\n    age: 29,\n    role: \"Documentary Filmmaker\",\n    location: \"Austin, TX\",\n    distance: \"6 miles away\",\n    bio: \"Currently editing a doc on regenerative farming. Love 35mm cameras, spicy noodles, and midnight road trips with good playlists.\",\n    tags: [\"Cinema\", \"Documentaries\", \"Street Food\", \"Camping\"],\n    gradient: \"from-amber-600 via-orange-700 to-rose-900\",\n    verified: false,\n  },\n];\n\n// Single Top Card with Drag physics & Transform values\nfunction SwipeCardTop({\n  card,\n  onSwiped,\n}: {\n  card: ProfileCard;\n  onSwiped: (dir: \"like\" | \"nope\") => void;\n}) {\n  const x = useMotionValue(0);\n  const rotate = useTransform(x, [-200, 200], [-18, 18]);\n  const likeOpacity = useTransform(x, [20, 110], [0, 1]);\n  const nopeOpacity = useTransform(x, [-20, -110], [0, 1]);\n\n  const handleDragEnd = (\n    _event: MouseEvent | TouchEvent | PointerEvent,\n    info: PanInfo\n  ) => {\n    if (info.offset.x > 110 || info.velocity.x > 500) {\n      onSwiped(\"like\");\n    } else if (info.offset.x < -110 || info.velocity.x < -500) {\n      onSwiped(\"nope\");\n    }\n  };\n\n  return (\n    <motion.div\n      style={{ x, rotate, zIndex: 10 }}\n      drag=\"x\"\n      dragConstraints={{ left: 0, right: 0 }}\n      dragElastic={0.8}\n      onDragEnd={handleDragEnd}\n      whileDrag={{ scale: 1.02 }}\n      className=\"absolute inset-0 cursor-grab active:cursor-grabbing select-none rounded-3xl overflow-hidden shadow-2xl ring-1 ring-black/10 dark:ring-white/10\"\n    >\n      {/* Visual Canvas Backdrop */}\n      <div className={cn(\"relative h-full w-full bg-gradient-to-br flex flex-col justify-between p-6 text-white\", card.gradient)}>\n        {/* Stamp Overlays */}\n        <div className=\"pointer-events-none flex items-start justify-between\">\n          {/* LIKE Stamp */}\n          <motion.div\n            style={{ opacity: likeOpacity }}\n            className=\"rounded-xl border-4 border-emerald-400 bg-emerald-500/20 px-4 py-1.5 font-mono text-2xl font-black uppercase tracking-wider text-emerald-400 shadow-lg backdrop-blur-md rotate-[-12deg]\"\n          >\n            LIKE\n          </motion.div>\n\n          {/* NOPE Stamp */}\n          <motion.div\n            style={{ opacity: nopeOpacity }}\n            className=\"rounded-xl border-4 border-rose-500 bg-rose-500/20 px-4 py-1.5 font-mono text-2xl font-black uppercase tracking-wider text-rose-500 shadow-lg backdrop-blur-md rotate-[12deg]\"\n          >\n            NOPE\n          </motion.div>\n        </div>\n\n        {/* Card Metadata Bottom Sheet */}\n        <div className=\"relative z-10 rounded-2xl bg-black/40 p-4.5 backdrop-blur-md border border-white/10\">\n          <div className=\"flex items-center gap-2\">\n            <h2 className=\"text-xl font-bold tracking-tight text-white\">\n              {card.name}, <span className=\"font-normal opacity-90\">{card.age}</span>\n            </h2>\n            {card.verified && (\n              <span className=\"flex h-5 w-5 items-center justify-center rounded-full bg-sky-500 text-white\">\n                <Sparkles className=\"h-3 w-3\" />\n              </span>\n            )}\n          </div>\n\n          <div className=\"mt-1 flex flex-wrap items-center gap-3 text-xs text-white/80\">\n            <span className=\"flex items-center gap-1\">\n              <Briefcase className=\"h-3 w-3\" />\n              {card.role}\n            </span>\n            <span className=\"flex items-center gap-1\">\n              <MapPin className=\"h-3 w-3\" />\n              {card.distance}\n            </span>\n          </div>\n\n          <p className=\"mt-2 text-xs leading-relaxed text-white/90 line-clamp-2\">\n            {card.bio}\n          </p>\n\n          <div className=\"mt-2.5 flex flex-wrap gap-1.5\">\n            {card.tags.map((tag) => (\n              <span\n                key={tag}\n                className=\"rounded-full bg-white/20 px-2.5 py-0.5 text-[10px] font-medium backdrop-blur-xs text-white\"\n              >\n                {tag}\n              </span>\n            ))}\n          </div>\n        </div>\n      </div>\n    </motion.div>\n  );\n}\n\nexport function SwipeCards({\n  profiles = DEFAULT_PROFILES,\n  onSwipe,\n  className,\n}: SwipeCardsProps) {\n  const [deck, setDeck] = useState<ProfileCard[]>(profiles);\n  const [swipedHistory, setSwipedHistory] = useState<\n    Array<{ card: ProfileCard; dir: \"like\" | \"nope\" | \"superlike\" }>\n  >([]);\n  const [lastAction, setLastAction] = useState<string | null>(null);\n\n  const activeCard = deck[0];\n\n  const handleSwipeCard = (dir: \"like\" | \"nope\" | \"superlike\") => {\n    if (!activeCard) return;\n\n    setSwipedHistory((prev) => [{ card: activeCard, dir }, ...prev]);\n    setDeck((prev) => prev.slice(1));\n    setLastAction(`Swiped ${dir.toUpperCase()} on ${activeCard.name}`);\n    onSwipe?.(activeCard, dir);\n  };\n\n  const handleUndo = () => {\n    if (swipedHistory.length === 0) return;\n    const [lastSwiped, ...restHistory] = swipedHistory;\n    setSwipedHistory(restHistory);\n    setDeck((prev) => [lastSwiped.card, ...prev]);\n    setLastAction(`Restored ${lastSwiped.card.name}`);\n  };\n\n  const handleReset = () => {\n    setDeck(profiles);\n    setSwipedHistory([]);\n    setLastAction(\"Deck reset to start\");\n  };\n\n  return (\n    <div\n      data-fullscreen-scroll\n      className={cn(\n        \"relative flex min-h-[520px] w-full flex-col justify-between overflow-hidden rounded-2xl border border-neutral-200 bg-neutral-100/70 p-4 sm:p-8 dark:border-neutral-800 dark:bg-neutral-950\",\n        className\n      )}\n    >\n      {/* Header bar */}\n      <div className=\"relative z-10 flex flex-wrap items-center justify-between gap-3 pb-2\">\n        <div className=\"flex items-center gap-3\">\n          <div className=\"flex h-9 w-9 items-center justify-center rounded-xl bg-rose-500/10 text-rose-600 dark:bg-rose-500/20 dark:text-rose-400\">\n            <Heart className=\"h-4 w-4 fill-rose-500\" />\n          </div>\n          <div>\n            <div className=\"flex items-center gap-2\">\n              <span className=\"text-sm font-semibold tracking-tight text-neutral-900 dark:text-neutral-100\">\n                Tinder Swipeable Card Deck\n              </span>\n              <span className=\"rounded-full bg-neutral-200 px-2 py-0.5 text-[10px] font-medium text-neutral-700 dark:bg-neutral-800 dark:text-neutral-300\">\n                Drag Physics\n              </span>\n            </div>\n            <p className=\"text-xs text-neutral-500 dark:text-neutral-400\">\n              Rotational tilt springs, stamp overlays, stack scale-up, and rewind\n            </p>\n          </div>\n        </div>\n\n        <div className=\"flex items-center gap-2\">\n          <span className=\"font-mono text-xs text-neutral-500 dark:text-neutral-400\">\n            Remaining: <strong className=\"text-neutral-900 dark:text-white\">{deck.length}</strong>\n          </span>\n        </div>\n      </div>\n\n      {/* Main Card Deck Center Stage */}\n      <div className=\"relative z-10 my-auto flex flex-col items-center justify-center py-4\">\n        <div className=\"relative h-[380px] w-full max-w-[320px] sm:max-w-[340px]\">\n          <AnimatePresence>\n            {deck.length === 0 ? (\n              /* Empty deck state */\n              <motion.div\n                initial={{ opacity: 0, scale: 0.9 }}\n                animate={{ opacity: 1, scale: 1 }}\n                className=\"absolute inset-0 flex flex-col items-center justify-center rounded-3xl border border-dashed border-neutral-300 bg-white p-6 text-center shadow-lg dark:border-neutral-800 dark:bg-neutral-900\"\n              >\n                <div className=\"flex h-12 w-12 items-center justify-center rounded-full bg-rose-500/10 text-rose-500 mb-3\">\n                  <Sparkles className=\"h-6 w-6\" />\n                </div>\n                <h3 className=\"text-sm font-bold text-neutral-900 dark:text-white\">\n                  You&apos;ve seen everyone nearby!\n                </h3>\n                <p className=\"mt-1 text-xs text-neutral-500 dark:text-neutral-400\">\n                  Rewind your last swipe or reset the discovery stack to explore again.\n                </p>\n                <button\n                  type=\"button\"\n                  onClick={handleReset}\n                  className=\"mt-4 rounded-xl bg-rose-500 px-4 py-2 text-xs font-semibold text-white shadow-md transition hover:bg-rose-600 active:scale-95\"\n                >\n                  Reset Discovery Stack\n                </button>\n              </motion.div>\n            ) : (\n              /* Render card deck with depth scaling */\n              deck.slice(0, 3).map((card, index) => {\n                const isTop = index === 0;\n                const scale = 1 - index * 0.05;\n                const translateY = index * 12;\n                const opacity = 1 - index * 0.2;\n\n                if (isTop) {\n                  return (\n                    <SwipeCardTop\n                      key={card.id}\n                      card={card}\n                      onSwiped={(dir) => handleSwipeCard(dir)}\n                    />\n                  );\n                }\n\n                return (\n                  <motion.div\n                    key={card.id}\n                    animate={{\n                      scale,\n                      y: translateY,\n                      opacity,\n                    }}\n                    transition={{ type: \"spring\", stiffness: 350, damping: 25 }}\n                    style={{ zIndex: 10 - index }}\n                    className=\"absolute inset-0 select-none overflow-hidden rounded-3xl shadow-xl ring-1 ring-black/5 dark:ring-white/5\"\n                  >\n                    <div className={cn(\"h-full w-full bg-gradient-to-br p-6 text-white\", card.gradient)}>\n                      <div className=\"mt-auto rounded-2xl bg-black/40 p-4 backdrop-blur-md\">\n                        <div className=\"text-lg font-bold text-white\">\n                          {card.name}, {card.age}\n                        </div>\n                        <div className=\"text-xs text-white/80\">{card.role}</div>\n                      </div>\n                    </div>\n                  </motion.div>\n                );\n              })\n            )}\n          </AnimatePresence>\n        </div>\n\n        {/* Tactile Action Buttons Row */}\n        <div className=\"mt-6 flex items-center justify-center gap-3 sm:gap-4\">\n          {/* Rewind Button */}\n          <button\n            type=\"button\"\n            onClick={handleUndo}\n            disabled={swipedHistory.length === 0}\n            aria-label=\"Rewind last swipe\"\n            className=\"flex h-11 w-11 items-center justify-center rounded-full border border-neutral-200 bg-white text-amber-500 shadow-md transition hover:scale-110 active:scale-90 disabled:opacity-30 disabled:hover:scale-100 dark:border-neutral-800 dark:bg-neutral-900\"\n          >\n            <RotateCcw className=\"h-5 w-5\" />\n          </button>\n\n          {/* Pass / Nope Button */}\n          <button\n            type=\"button\"\n            onClick={() => handleSwipeCard(\"nope\")}\n            disabled={deck.length === 0}\n            aria-label=\"Pass profile\"\n            className=\"flex h-14 w-14 items-center justify-center rounded-full border border-neutral-200 bg-white text-rose-500 shadow-lg transition hover:scale-110 active:scale-90 disabled:opacity-30 disabled:hover:scale-100 dark:border-neutral-800 dark:bg-neutral-900\"\n          >\n            <X className=\"h-7 w-7\" />\n          </button>\n\n          {/* Super Like Button */}\n          <button\n            type=\"button\"\n            onClick={() => handleSwipeCard(\"superlike\")}\n            disabled={deck.length === 0}\n            aria-label=\"Super like profile\"\n            className=\"flex h-11 w-11 items-center justify-center rounded-full border border-neutral-200 bg-white text-sky-500 shadow-md transition hover:scale-110 active:scale-90 disabled:opacity-30 disabled:hover:scale-100 dark:border-neutral-800 dark:bg-neutral-900\"\n          >\n            <Star className=\"h-5 w-5\" />\n          </button>\n\n          {/* Like Button */}\n          <button\n            type=\"button\"\n            onClick={() => handleSwipeCard(\"like\")}\n            disabled={deck.length === 0}\n            aria-label=\"Like profile\"\n            className=\"flex h-14 w-14 items-center justify-center rounded-full border border-neutral-200 bg-white text-emerald-500 shadow-lg transition hover:scale-110 active:scale-90 disabled:opacity-30 disabled:hover:scale-100 dark:border-neutral-800 dark:bg-neutral-900\"\n          >\n            <Heart className=\"h-7 w-7 fill-emerald-500\" />\n          </button>\n\n          {/* Boost Button */}\n          <button\n            type=\"button\"\n            onClick={() => setLastAction(\"Boost activated for 30 minutes! ⚡\")}\n            aria-label=\"Activate boost\"\n            className=\"flex h-11 w-11 items-center justify-center rounded-full border border-neutral-200 bg-white text-purple-500 shadow-md transition hover:scale-110 active:scale-90 dark:border-neutral-800 dark:bg-neutral-900\"\n          >\n            <Zap className=\"h-5 w-5 fill-purple-500\" />\n          </button>\n        </div>\n      </div>\n\n      {/* Footer telemetry & status */}\n      <div className=\"relative z-10 flex flex-wrap items-center justify-between gap-3 border-t border-neutral-200/80 pt-4 dark:border-neutral-800/80\">\n        <div className=\"flex items-center gap-2 text-xs text-neutral-500\">\n          <Info className=\"h-3.5 w-3.5\" />\n          <span>{lastAction || \"Drag card left or right to swipe\"}</span>\n        </div>\n\n        <button\n          type=\"button\"\n          onClick={handleReset}\n          className=\"text-xs text-neutral-500 underline transition hover:text-neutral-900 dark:text-neutral-400 dark:hover:text-white\"\n        >\n          Reset Deck\n        </button>\n      </div>\n    </div>\n  );\n}\n\nexport default SwipeCards;\n",
          "type": "registry:ui",
          "target": "components/ui/swipe-cards.tsx"
        },
        {
          "path": "lib/utils.ts",
          "content": "import { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...inputs: ClassValue[]) {\n  return twMerge(clsx(inputs));\n}\n\nexport async function copyToClipboard(text: string): Promise<boolean> {\n  if (typeof window === \"undefined\") return false;\n\n  try {\n    if (navigator.clipboard && window.isSecureContext) {\n      await navigator.clipboard.writeText(text);\n      return true;\n    }\n\n    const textArea = document.createElement(\"textarea\");\n    textArea.value = text;\n    textArea.style.position = \"fixed\";\n    textArea.style.left = \"-999999px\";\n    textArea.style.top = \"-999999px\";\n    document.body.appendChild(textArea);\n    textArea.focus();\n    textArea.select();\n    const succeeded = document.execCommand(\"copy\");\n    textArea.remove();\n    return succeeded;\n  } catch {\n    return false;\n  }\n}\n",
          "type": "registry:lib",
          "target": "lib/utils.ts"
        }
      ]
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "tabbed-code-block",
      "type": "registry:ui",
      "title": "Tabbed Code Block",
      "author": "Rishabh Bose <https://theb0se.vercel.app/>",
      "description": "Multi-language developer code block featuring smooth sliding active tab underlines, syntax-token highlighting, line numbering, one-click copy, and an interactive simulated terminal runner.",
      "dependencies": [
        "framer-motion",
        "lucide-react",
        "clsx",
        "tailwind-merge"
      ],
      "files": [
        {
          "path": "components/ui/tabbed-code-block.tsx",
          "content": "\"use client\";\n\nimport React, { useState } from \"react\";\nimport { motion, AnimatePresence } from \"framer-motion\";\nimport {\n  Copy,\n  Check,\n  Play,\n  Terminal,\n  Code2,\n  ChevronRight,\n  Sparkles,\n  RotateCcw,\n  Sliders,\n  CheckCircle2,\n} from \"lucide-react\";\nimport { cn } from \"@/lib/utils\";\n\nexport interface CodeSnippet {\n  id: string;\n  name: string;\n  filename: string;\n  code: string;\n  highlightedLines?: number[];\n  tokens: {\n    line: number;\n    parts: { text: string; color: string }[];\n  }[];\n}\n\nconst SNIPPETS: Record<string, CodeSnippet> = {\n  curl: {\n    id: \"curl\",\n    name: \"cURL\",\n    filename: \"charge.sh\",\n    code: `curl https://api.pulse.dev/v1/charges \\\\\n  -u sk_test_51Mz9x8K1x4LkdI: \\\\\n  -d amount=2000 \\\\\n  -d currency=usd \\\\\n  -d source=tok_visa \\\\\n  -d description=\"Standard subscription tier\"`,\n    highlightedLines: [3, 4],\n    tokens: [\n      {\n        line: 1,\n        parts: [\n          { text: \"curl \", color: \"text-amber-400 font-bold\" },\n          { text: \"https://api.pulse.dev/v1/charges\", color: \"text-emerald-300\" },\n          { text: \" \\\\\", color: \"text-neutral-500\" },\n        ],\n      },\n      {\n        line: 2,\n        parts: [\n          { text: \"  -u \", color: \"text-cyan-400\" },\n          { text: \"sk_test_51Mz9x8K1x4LkdI:\", color: \"text-purple-300\" },\n          { text: \" \\\\\", color: \"text-neutral-500\" },\n        ],\n      },\n      {\n        line: 3,\n        parts: [\n          { text: \"  -d \", color: \"text-cyan-400\" },\n          { text: \"amount\", color: \"text-neutral-200\" },\n          { text: \"=\", color: \"text-neutral-400\" },\n          { text: \"2000\", color: \"text-orange-300\" },\n          { text: \" \\\\\", color: \"text-neutral-500\" },\n        ],\n      },\n      {\n        line: 4,\n        parts: [\n          { text: \"  -d \", color: \"text-cyan-400\" },\n          { text: \"currency\", color: \"text-neutral-200\" },\n          { text: \"=\", color: \"text-neutral-400\" },\n          { text: \"usd\", color: \"text-emerald-300\" },\n          { text: \" \\\\\", color: \"text-neutral-500\" },\n        ],\n      },\n      {\n        line: 5,\n        parts: [\n          { text: \"  -d \", color: \"text-cyan-400\" },\n          { text: \"source\", color: \"text-neutral-200\" },\n          { text: \"=\", color: \"text-neutral-400\" },\n          { text: \"tok_visa\", color: \"text-purple-300\" },\n          { text: \" \\\\\", color: \"text-neutral-500\" },\n        ],\n      },\n      {\n        line: 6,\n        parts: [\n          { text: \"  -d \", color: \"text-cyan-400\" },\n          { text: \"description\", color: \"text-neutral-200\" },\n          { text: \"=\", color: \"text-neutral-400\" },\n          { text: '\"Standard subscription tier\"', color: \"text-emerald-300\" },\n        ],\n      },\n    ],\n  },\n  node: {\n    id: \"node\",\n    name: \"Node.js\",\n    filename: \"charge.js\",\n    code: `import Pulse from \"@pulse/sdk\";\nconst pulse = new Pulse(\"sk_test_51Mz9x8K1x4LkdI\");\n\nconst charge = await pulse.charges.create({\n  amount: 2000,\n  currency: \"usd\",\n  source: \"tok_visa\",\n  description: \"Standard subscription tier\",\n});\n\nconsole.log(charge.id);`,\n    highlightedLines: [4, 5],\n    tokens: [\n      {\n        line: 1,\n        parts: [\n          { text: \"import \", color: \"text-purple-400 font-bold\" },\n          { text: \"Pulse \", color: \"text-yellow-300\" },\n          { text: \"from \", color: \"text-purple-400 font-bold\" },\n          { text: '\"@pulse/sdk\"', color: \"text-emerald-300\" },\n          { text: \";\", color: \"text-neutral-400\" },\n        ],\n      },\n      {\n        line: 2,\n        parts: [\n          { text: \"const \", color: \"text-purple-400 font-bold\" },\n          { text: \"pulse = \", color: \"text-neutral-200\" },\n          { text: \"new \", color: \"text-purple-400\" },\n          { text: \"Pulse\", color: \"text-yellow-300\" },\n          { text: '(\"sk_test_51Mz9x8K1x4LkdI\");', color: \"text-emerald-300\" },\n        ],\n      },\n      { line: 3, parts: [{ text: \"\", color: \"text-neutral-400\" }] },\n      {\n        line: 4,\n        parts: [\n          { text: \"const \", color: \"text-purple-400 font-bold\" },\n          { text: \"charge = \", color: \"text-neutral-200\" },\n          { text: \"await \", color: \"text-purple-400 font-bold\" },\n          { text: \"pulse.charges.\", color: \"text-neutral-300\" },\n          { text: \"create\", color: \"text-blue-400 font-semibold\" },\n          { text: \"({\", color: \"text-neutral-300\" },\n        ],\n      },\n      {\n        line: 5,\n        parts: [\n          { text: \"  amount: \", color: \"text-cyan-300\" },\n          { text: \"2000\", color: \"text-orange-300\" },\n          { text: \",\", color: \"text-neutral-400\" },\n        ],\n      },\n      {\n        line: 6,\n        parts: [\n          { text: \"  currency: \", color: \"text-cyan-300\" },\n          { text: '\"usd\"', color: \"text-emerald-300\" },\n          { text: \",\", color: \"text-neutral-400\" },\n        ],\n      },\n      {\n        line: 7,\n        parts: [\n          { text: \"  source: \", color: \"text-cyan-300\" },\n          { text: '\"tok_visa\"', color: \"text-emerald-300\" },\n          { text: \",\", color: \"text-neutral-400\" },\n        ],\n      },\n      {\n        line: 8,\n        parts: [\n          { text: \"  description: \", color: \"text-cyan-300\" },\n          { text: '\"Standard subscription tier\"', color: \"text-emerald-300\" },\n        ],\n      },\n      { line: 9, parts: [{ text: \"});\", color: \"text-neutral-300\" }] },\n      { line: 10, parts: [{ text: \"\", color: \"text-neutral-400\" }] },\n      {\n        line: 11,\n        parts: [\n          { text: \"console.\", color: \"text-neutral-300\" },\n          { text: \"log\", color: \"text-blue-400 font-semibold\" },\n          { text: \"(charge.id);\", color: \"text-neutral-200\" },\n        ],\n      },\n    ],\n  },\n  python: {\n    id: \"python\",\n    name: \"Python\",\n    filename: \"charge.py\",\n    code: `import pulse\n\npulse.api_key = \"sk_test_51Mz9x8K1x4LkdI\"\n\ncharge = pulse.Charge.create(\n    amount=2000,\n    currency=\"usd\",\n    source=\"tok_visa\",\n    description=\"Standard subscription tier\",\n)\n\nprint(charge.id)`,\n    highlightedLines: [5, 6],\n    tokens: [\n      {\n        line: 1,\n        parts: [\n          { text: \"import \", color: \"text-purple-400 font-bold\" },\n          { text: \"pulse\", color: \"text-yellow-300\" },\n        ],\n      },\n      { line: 2, parts: [{ text: \"\", color: \"text-neutral-400\" }] },\n      {\n        line: 3,\n        parts: [\n          { text: \"pulse.api_key = \", color: \"text-neutral-200\" },\n          { text: '\"sk_test_51Mz9x8K1x4LkdI\"', color: \"text-emerald-300\" },\n        ],\n      },\n      { line: 4, parts: [{ text: \"\", color: \"text-neutral-400\" }] },\n      {\n        line: 5,\n        parts: [\n          { text: \"charge = pulse.\", color: \"text-neutral-200\" },\n          { text: \"Charge\", color: \"text-yellow-300\" },\n          { text: \".\", color: \"text-neutral-300\" },\n          { text: \"create\", color: \"text-blue-400 font-semibold\" },\n          { text: \"(\", color: \"text-neutral-300\" },\n        ],\n      },\n      {\n        line: 6,\n        parts: [\n          { text: \"    amount=\", color: \"text-cyan-300\" },\n          { text: \"2000\", color: \"text-orange-300\" },\n          { text: \",\", color: \"text-neutral-400\" },\n        ],\n      },\n      {\n        line: 7,\n        parts: [\n          { text: \"    currency=\", color: \"text-cyan-300\" },\n          { text: '\"usd\"', color: \"text-emerald-300\" },\n          { text: \",\", color: \"text-neutral-400\" },\n        ],\n      },\n      {\n        line: 8,\n        parts: [\n          { text: \"    source=\", color: \"text-cyan-300\" },\n          { text: '\"tok_visa\"', color: \"text-emerald-300\" },\n          { text: \",\", color: \"text-neutral-400\" },\n        ],\n      },\n      {\n        line: 9,\n        parts: [\n          { text: \"    description=\", color: \"text-cyan-300\" },\n          { text: '\"Standard subscription tier\"', color: \"text-emerald-300\" },\n          { text: \",\", color: \"text-neutral-400\" },\n        ],\n      },\n      { line: 10, parts: [{ text: \")\", color: \"text-neutral-300\" }] },\n      { line: 11, parts: [{ text: \"\", color: \"text-neutral-400\" }] },\n      {\n        line: 12,\n        parts: [\n          { text: \"print\", color: \"text-blue-400 font-semibold\" },\n          { text: \"(charge.id)\", color: \"text-neutral-200\" },\n        ],\n      },\n    ],\n  },\n  go: {\n    id: \"go\",\n    name: \"Go\",\n    filename: \"charge.go\",\n    code: `package main\n\nimport (\n  \"fmt\"\n  \"github.com/pulse/pulse-go\"\n  \"github.com/pulse/pulse-go/charge\"\n)\n\nfunc main() {\n  pulse.Key = \"sk_test_51Mz9x8K1x4LkdI\"\n  params := &pulse.ChargeParams{\n    Amount:   pulse.Int64(2000),\n    Currency: pulse.String(\"usd\"),\n  }\n  ch, _ := charge.New(params)\n  fmt.Println(ch.ID)\n}`,\n    highlightedLines: [11, 12],\n    tokens: [\n      {\n        line: 1,\n        parts: [\n          { text: \"package \", color: \"text-purple-400 font-bold\" },\n          { text: \"main\", color: \"text-neutral-200\" },\n        ],\n      },\n      { line: 2, parts: [{ text: \"\", color: \"text-neutral-400\" }] },\n      {\n        line: 3,\n        parts: [{ text: \"import (\", color: \"text-purple-400 font-bold\" }],\n      },\n      {\n        line: 4,\n        parts: [\n          { text: '  \"fmt\"', color: \"text-emerald-300\" },\n        ],\n      },\n      {\n        line: 5,\n        parts: [\n          { text: '  \"github.com/pulse/pulse-go\"', color: \"text-emerald-300\" },\n        ],\n      },\n      {\n        line: 6,\n        parts: [{ text: \")\", color: \"text-purple-400 font-bold\" }],\n      },\n      { line: 7, parts: [{ text: \"\", color: \"text-neutral-400\" }] },\n      {\n        line: 8,\n        parts: [\n          { text: \"func \", color: \"text-purple-400 font-bold\" },\n          { text: \"main\", color: \"text-blue-400 font-semibold\" },\n          { text: \"() {\", color: \"text-neutral-200\" },\n        ],\n      },\n      {\n        line: 9,\n        parts: [\n          { text: \"  pulse.Key = \", color: \"text-neutral-300\" },\n          { text: '\"sk_test_51Mz9x8K1x4LkdI\"', color: \"text-emerald-300\" },\n        ],\n      },\n      {\n        line: 10,\n        parts: [\n          { text: \"  params := &pulse.ChargeParams{\", color: \"text-neutral-300\" },\n        ],\n      },\n      {\n        line: 11,\n        parts: [\n          { text: \"    Amount:   \", color: \"text-cyan-300\" },\n          { text: \"pulse.Int64(2000)\", color: \"text-orange-300\" },\n          { text: \",\", color: \"text-neutral-400\" },\n        ],\n      },\n      {\n        line: 12,\n        parts: [\n          { text: \"    Currency: \", color: \"text-cyan-300\" },\n          { text: 'pulse.String(\"usd\")', color: \"text-emerald-300\" },\n          { text: \",\", color: \"text-neutral-400\" },\n        ],\n      },\n      { line: 13, parts: [{ text: \"  }\", color: \"text-neutral-300\" }] },\n      {\n        line: 14,\n        parts: [\n          { text: \"  ch, _ := charge.New(params)\", color: \"text-neutral-200\" },\n        ],\n      },\n      {\n        line: 15,\n        parts: [\n          { text: \"  fmt.Println(ch.ID)\", color: \"text-neutral-200\" },\n        ],\n      },\n      { line: 16, parts: [{ text: \"}\", color: \"text-neutral-200\" }] },\n    ],\n  },\n};\n\nexport interface TabbedCodeBlockProps {\n  className?: string;\n  defaultLang?: string;\n  showLineNumbers?: boolean;\n}\n\nexport function TabbedCodeBlock({\n  className,\n  defaultLang = \"node\",\n  showLineNumbers = true,\n}: TabbedCodeBlockProps) {\n  const [activeLang, setActiveLang] = useState<string>(defaultLang);\n  const [hasCopied, setHasCopied] = useState(false);\n  const [lineNumbers, setLineNumbers] = useState(showLineNumbers);\n  const [highlightActive, setHighlightActive] = useState(true);\n  const [isRunning, setIsRunning] = useState(false);\n  const [terminalOpen, setTerminalOpen] = useState(true);\n  const [runResponse, setRunResponse] = useState<string | null>(null);\n\n  const snippet = SNIPPETS[activeLang] || SNIPPETS.node;\n\n  const handleCopy = () => {\n    navigator.clipboard.writeText(snippet.code);\n    setHasCopied(true);\n    setTimeout(() => setHasCopied(false), 2000);\n  };\n\n  const handleRun = () => {\n    setIsRunning(true);\n    setTerminalOpen(true);\n    setTimeout(() => {\n      setIsRunning(false);\n      setRunResponse(\n        JSON.stringify(\n          {\n            id: `ch_3Mtw12LkdIwHu7ix_${Math.random().toString(36).substring(2, 7)}`,\n            object: \"charge\",\n            amount: 2000,\n            amount_captured: 2000,\n            currency: \"usd\",\n            paid: true,\n            status: \"succeeded\",\n            outcome: {\n              network_status: \"approved_by_network\",\n              risk_level: \"normal\",\n              seller_message: \"Payment complete.\",\n            },\n            created: Math.floor(Date.now() / 1000),\n          },\n          null,\n          2\n        )\n      );\n    }, 700);\n  };\n\n  return (\n    <div\n      data-fullscreen-scroll\n      className={cn(\n        \"relative w-full min-h-[520px] overflow-hidden rounded-2xl border border-neutral-800 bg-[#080a14] p-6 text-white flex flex-col justify-between shadow-2xl selection:bg-indigo-500/30\",\n        className\n      )}\n    >\n      {/* Ambient background glow */}\n      <div className=\"pointer-events-none absolute inset-0 overflow-hidden\">\n        <div className=\"absolute top-1/4 left-1/3 h-72 w-96 rounded-full bg-indigo-600/10 blur-[120px]\" />\n        <div className=\"absolute bottom-10 right-10 h-64 w-64 rounded-full bg-emerald-500/10 blur-[100px]\" />\n      </div>\n\n      {/* Code Card Shell */}\n      <div className=\"relative z-10 w-full max-w-4xl mx-auto rounded-2xl border border-neutral-800/90 bg-[#0a0d1d]/90 shadow-2xl backdrop-blur-xl overflow-hidden\">\n        {/* Header Bar with Mac Dots, Tabs, Actions */}\n        <div className=\"flex flex-wrap items-center justify-between border-b border-neutral-800/80 px-4 py-2.5 bg-neutral-900/50\">\n          {/* Left: Window controls + Language tabs */}\n          <div className=\"flex items-center gap-4\">\n            <div className=\"flex items-center gap-1.5\">\n              <span className=\"h-3 w-3 rounded-full bg-red-500/80 inline-block\" />\n              <span className=\"h-3 w-3 rounded-full bg-yellow-500/80 inline-block\" />\n              <span className=\"h-3 w-3 rounded-full bg-emerald-500/80 inline-block\" />\n            </div>\n\n            {/* Sliding Underline Tabs */}\n            <div className=\"flex items-center space-x-1\" role=\"tablist\">\n              {Object.values(SNIPPETS).map((snip) => {\n                const isActive = activeLang === snip.id;\n                return (\n                  <button\n                    key={snip.id}\n                    onClick={() => setActiveLang(snip.id)}\n                    role=\"tab\"\n                    aria-selected={isActive}\n                    className={cn(\n                      \"relative px-3 py-1 text-xs font-mono font-medium rounded-md transition-colors\",\n                      isActive\n                        ? \"text-white\"\n                        : \"text-neutral-400 hover:text-neutral-200\"\n                    )}\n                  >\n                    {snip.name}\n                    {isActive && (\n                      <motion.div\n                        layoutId=\"activeCodeTabUnderline\"\n                        className=\"absolute bottom-0 left-1 right-1 h-0.5 bg-indigo-400 rounded-full\"\n                        transition={{ type: \"spring\", stiffness: 450, damping: 35 }}\n                      />\n                    )}\n                  </button>\n                );\n              })}\n            </div>\n          </div>\n\n          {/* Right: Filename, Copy Button & Run Button */}\n          <div className=\"flex items-center gap-2\">\n            <span className=\"hidden sm:inline font-mono text-[11px] text-neutral-400 bg-neutral-800/60 px-2 py-0.5 rounded border border-neutral-700/60\">\n              {snippet.filename}\n            </span>\n\n            <button\n              onClick={handleCopy}\n              title=\"Copy code\"\n              className=\"p-1.5 rounded-lg border border-neutral-700/70 bg-neutral-800/60 text-neutral-300 hover:text-white hover:bg-neutral-700/60 transition-colors flex items-center gap-1.5 text-xs font-mono\"\n            >\n              {hasCopied ? (\n                <>\n                  <Check className=\"h-3.5 w-3.5 text-emerald-400\" />\n                  <span className=\"text-emerald-400 text-[11px]\">Copied</span>\n                </>\n              ) : (\n                <>\n                  <Copy className=\"h-3.5 w-3.5\" />\n                  <span className=\"text-[11px]\">Copy</span>\n                </>\n              )}\n            </button>\n\n            <button\n              onClick={handleRun}\n              disabled={isRunning}\n              className=\"px-2.5 py-1.5 rounded-lg bg-indigo-600 hover:bg-indigo-500 text-white text-xs font-semibold shadow-md shadow-indigo-600/30 flex items-center gap-1.5 transition-all active:scale-95 disabled:opacity-50\"\n            >\n              <Play className=\"h-3 w-3 fill-current\" />\n              <span>Run API</span>\n            </button>\n          </div>\n        </div>\n\n        {/* Code Lines Body */}\n        <div className=\"p-4 overflow-x-auto font-mono text-[13px] leading-relaxed select-text bg-[#080b18]\">\n          <AnimatePresence mode=\"wait\">\n            <motion.div\n              key={activeLang}\n              initial={{ opacity: 0, y: 4 }}\n              animate={{ opacity: 1, y: 0 }}\n              exit={{ opacity: 0, y: -4 }}\n              transition={{ duration: 0.15 }}\n            >\n              {snippet.tokens.map((lineData) => {\n                const isHighlighted =\n                  highlightActive &&\n                  snippet.highlightedLines?.includes(lineData.line);\n\n                return (\n                  <div\n                    key={lineData.line}\n                    className={cn(\n                      \"flex items-center rounded px-2 py-0.5 transition-colors\",\n                      isHighlighted\n                        ? \"bg-indigo-950/40 border-l-2 border-indigo-400 font-medium\"\n                        : \"border-l-2 border-transparent hover:bg-white/[0.02]\"\n                    )}\n                  >\n                    {lineNumbers && (\n                      <span className=\"w-8 shrink-0 text-right pr-4 text-neutral-600 select-none text-xs\">\n                        {lineData.line}\n                      </span>\n                    )}\n                    <span className=\"flex-1 whitespace-pre\">\n                      {lineData.parts.map((p, idx) => (\n                        <span key={idx} className={p.color}>\n                          {p.text}\n                        </span>\n                      ))}\n                    </span>\n                  </div>\n                );\n              })}\n            </motion.div>\n          </AnimatePresence>\n        </div>\n\n        {/* Interactive Run Console Terminal Output */}\n        <AnimatePresence>\n          {terminalOpen && (\n            <motion.div\n              initial={{ height: 0, opacity: 0 }}\n              animate={{ height: \"auto\", opacity: 1 }}\n              exit={{ height: 0, opacity: 0 }}\n              transition={{ duration: 0.25 }}\n              className=\"border-t border-neutral-800 bg-neutral-950/95 overflow-hidden\"\n            >\n              <div className=\"flex items-center justify-between px-4 py-2 border-b border-neutral-900 bg-neutral-900/40 text-xs\">\n                <div className=\"flex items-center gap-2 text-neutral-400 font-mono\">\n                  <Terminal className=\"h-3.5 w-3.5 text-emerald-400\" />\n                  <span className=\"text-neutral-300 font-medium\">Terminal Response Output</span>\n                  <span className=\"text-[10px] text-emerald-400 bg-emerald-500/10 border border-emerald-500/20 px-1.5 py-0.5 rounded font-mono\">\n                    HTTP 200 OK\n                  </span>\n                </div>\n                <div className=\"flex items-center gap-2\">\n                  <button\n                    onClick={() => setRunResponse(null)}\n                    className=\"text-neutral-500 hover:text-neutral-300 text-[11px]\"\n                  >\n                    Clear\n                  </button>\n                  <button\n                    onClick={() => setTerminalOpen(false)}\n                    className=\"text-neutral-500 hover:text-neutral-300 text-[11px]\"\n                  >\n                    Hide\n                  </button>\n                </div>\n              </div>\n\n              <div className=\"p-4 font-mono text-xs text-neutral-300 overflow-x-auto max-h-48 overflow-y-auto\">\n                {isRunning ? (\n                  <div className=\"flex items-center gap-2 text-indigo-400 animate-pulse\">\n                    <span className=\"h-2 w-2 rounded-full bg-indigo-400 animate-ping\" />\n                    <span>Executing POST /v1/charges against sandbox cluster...</span>\n                  </div>\n                ) : runResponse ? (\n                  <pre className=\"text-emerald-300 leading-snug whitespace-pre\">\n                    {runResponse}\n                  </pre>\n                ) : (\n                  <div className=\"text-neutral-500 italic\">\n                    Press \"Run API\" above to dispatch a test charge and observe the JSON outcome.\n                  </div>\n                )}\n              </div>\n            </motion.div>\n          )}\n        </AnimatePresence>\n      </div>\n\n      {/* Interactive Stage Controls */}\n      <div className=\"relative z-20 mt-6 pt-4 border-t border-neutral-800/80 flex flex-wrap items-center justify-between gap-4 text-xs\">\n        <div className=\"flex flex-wrap items-center gap-2\">\n          <span className=\"text-neutral-400 font-medium\">Language:</span>\n          {Object.values(SNIPPETS).map((snip) => (\n            <button\n              key={snip.id}\n              onClick={() => setActiveLang(snip.id)}\n              className={cn(\n                \"px-2.5 py-1 rounded font-mono transition-colors\",\n                activeLang === snip.id\n                  ? \"bg-indigo-600 text-white font-semibold\"\n                  : \"bg-neutral-800/80 text-neutral-400 hover:text-white\"\n              )}\n            >\n              {snip.name}\n            </button>\n          ))}\n        </div>\n\n        <div className=\"flex flex-wrap items-center gap-3\">\n          <button\n            onClick={() => setLineNumbers(!lineNumbers)}\n            className={cn(\n              \"px-2.5 py-1 rounded border text-xs font-medium transition-colors\",\n              lineNumbers\n                ? \"bg-indigo-500/20 border-indigo-500/40 text-indigo-300\"\n                : \"bg-neutral-800/60 border-neutral-700 text-neutral-400\"\n            )}\n          >\n            Line Numbers: {lineNumbers ? \"ON\" : \"OFF\"}\n          </button>\n\n          <button\n            onClick={() => setHighlightActive(!highlightActive)}\n            className={cn(\n              \"px-2.5 py-1 rounded border text-xs font-medium transition-colors\",\n              highlightActive\n                ? \"bg-indigo-500/20 border-indigo-500/40 text-indigo-300\"\n                : \"bg-neutral-800/60 border-neutral-700 text-neutral-400\"\n            )}\n          >\n            Highlight Lines: {highlightActive ? \"ON\" : \"OFF\"}\n          </button>\n\n          <button\n            onClick={() => setTerminalOpen(!terminalOpen)}\n            className={cn(\n              \"px-2.5 py-1 rounded border text-xs font-medium transition-colors\",\n              terminalOpen\n                ? \"bg-emerald-500/20 border-emerald-500/40 text-emerald-300\"\n                : \"bg-neutral-800/60 border-neutral-700 text-neutral-400\"\n            )}\n          >\n            Terminal: {terminalOpen ? \"Open\" : \"Closed\"}\n          </button>\n        </div>\n      </div>\n    </div>\n  );\n}\n\nexport default TabbedCodeBlock;\n",
          "type": "registry:ui",
          "target": "components/ui/tabbed-code-block.tsx"
        },
        {
          "path": "lib/utils.ts",
          "content": "import { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...inputs: ClassValue[]) {\n  return twMerge(clsx(inputs));\n}\n\nexport async function copyToClipboard(text: string): Promise<boolean> {\n  if (typeof window === \"undefined\") return false;\n\n  try {\n    if (navigator.clipboard && window.isSecureContext) {\n      await navigator.clipboard.writeText(text);\n      return true;\n    }\n\n    const textArea = document.createElement(\"textarea\");\n    textArea.value = text;\n    textArea.style.position = \"fixed\";\n    textArea.style.left = \"-999999px\";\n    textArea.style.top = \"-999999px\";\n    document.body.appendChild(textArea);\n    textArea.focus();\n    textArea.select();\n    const succeeded = document.execCommand(\"copy\");\n    textArea.remove();\n    return succeeded;\n  } catch {\n    return false;\n  }\n}\n",
          "type": "registry:lib",
          "target": "lib/utils.ts"
        }
      ]
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "thunderstorm",
      "type": "registry:ui",
      "title": "Thunderstorm",
      "author": "Rishabh Bose <https://theb0se.vercel.app/>",
      "description": "Dramatic thunderstorm background featuring recursive midpoint-displacement branching lightning bolts, dark rolling cloud banks, and wind-driven rain streaks on Canvas 2D.",
      "dependencies": [
        "lucide-react",
        "clsx",
        "tailwind-merge"
      ],
      "files": [
        {
          "path": "components/ui/thunderstorm.tsx",
          "content": "\"use client\";\n\nimport React, { useCallback, useEffect, useRef, useState } from \"react\";\nimport { CloudLightning, CloudRain, Wind, Zap, RotateCcw } from \"lucide-react\";\nimport { cn } from \"@/lib/utils\";\n\nexport interface ThunderstormProps {\n  /** Number of wind-driven rain streaks on screen */\n  rainIntensity?: number;\n  /** Probability rate of automatic lightning strikes (0 = manual only, 1 = frequent) */\n  lightningFrequency?: number;\n  /** Wind tilt angle in degrees (-35 to 35) */\n  windAngle?: number;\n  /** Primary lightning bolt glow color in hex */\n  boltColor?: string;\n  /** Screen & cloud exposure flash intensity on strike (0 to 1) */\n  flashIntensity?: number;\n  /** Optional foreground content */\n  children?: React.ReactNode;\n  /** Additional container classes */\n  className?: string;\n}\n\ninterface Segment {\n  x1: number;\n  y1: number;\n  x2: number;\n  y2: number;\n  width: number;\n  alpha: number;\n  isMainChannel: boolean;\n  tRatio: number;\n}\n\ninterface LightningBolt {\n  segments: Segment[];\n  originX: number;\n  originY: number;\n  life: number;\n  maxLife: number;\n  restrikeFrames: [number, number];\n}\n\ninterface RainDrop {\n  x: number;\n  y: number;\n  length: number;\n  speed: number;\n  depth: number;\n  isForeground: boolean;\n}\n\ninterface SplashRipple {\n  x: number;\n  y: number;\n  vx: number;\n  vy: number;\n  life: number;\n  maxLife: number;\n}\n\ninterface CloudLobe {\n  offsetX: number;\n  offsetY: number;\n  rx: number;\n  ry: number;\n}\n\ninterface CloudCluster {\n  x: number;\n  y: number;\n  speed: number;\n  layer: number;\n  lobes: CloudLobe[];\n}\n\nfunction hexToRgb(hex: string): { r: number; g: number; b: number } {\n  const clean = hex.replace(\"#\", \"\").trim();\n  const full =\n    clean.length === 3\n      ? clean\n          .split(\"\")\n          .map((c) => c + c)\n          .join(\"\")\n      : clean;\n  const num = parseInt(full, 16);\n  if (Number.isNaN(num)) return { r: 224, g: 242, b: 254 };\n  return {\n    r: (num >> 16) & 255,\n    g: (num >> 8) & 255,\n    b: num & 255,\n  };\n}\n\nfunction generateSteppedLeaderSegments(\n  x1: number,\n  y1: number,\n  x2: number,\n  y2: number,\n  displace: number,\n  startWidth: number,\n  endWidth: number,\n  alpha: number,\n  depth: number,\n  isMainChannel: boolean,\n  t0: number,\n  t1: number,\n  out: Segment[]\n) {\n  if (depth <= 0 || displace < 1.8) {\n    out.push({\n      x1,\n      y1,\n      x2,\n      y2,\n      width: (startWidth + endWidth) * 0.5,\n      alpha,\n      isMainChannel,\n      tRatio: (t0 + t1) * 0.5,\n    });\n    return;\n  }\n\n  const tMid = (t0 + t1) * 0.5;\n  const midWidth = (startWidth + endWidth) * 0.5;\n  const jitterX = (Math.random() - 0.5) * displace;\n  const jitterY = (Math.random() - 0.5) * displace * 0.28;\n  const midX = (x1 + x2) * 0.5 + jitterX;\n  const midY = (y1 + y2) * 0.5 + jitterY;\n\n  generateSteppedLeaderSegments(\n    x1,\n    y1,\n    midX,\n    midY,\n    displace * 0.53,\n    startWidth,\n    midWidth,\n    alpha,\n    depth - 1,\n    isMainChannel,\n    t0,\n    tMid,\n    out\n  );\n  generateSteppedLeaderSegments(\n    midX,\n    midY,\n    x2,\n    y2,\n    displace * 0.53,\n    midWidth,\n    endWidth,\n    alpha,\n    depth - 1,\n    isMainChannel,\n    tMid,\n    t1,\n    out\n  );\n\n  // Secondary & hair-thin tertiary branching forks\n  const branchChance = isMainChannel ? 0.48 : 0.34;\n  if (depth >= 2 && Math.random() < branchChance) {\n    const dx = x2 - midX;\n    const dy = y2 - midY;\n    const side = Math.random() < 0.5 ? -1 : 1;\n    const angle = side * (0.32 + Math.random() * 0.52);\n    const cos = Math.cos(angle);\n    const sin = Math.sin(angle);\n    const branchScale = isMainChannel\n      ? 0.58 + Math.random() * 0.38\n      : 0.45 + Math.random() * 0.3;\n    const bx = midX + (dx * cos - dy * sin) * branchScale;\n    const by = midY + (dx * sin + dy * cos) * branchScale;\n\n    generateSteppedLeaderSegments(\n      midX,\n      midY,\n      bx,\n      by,\n      displace * 0.46,\n      midWidth * 0.58,\n      Math.max(0.25, midWidth * 0.14),\n      alpha * 0.68,\n      depth - 2,\n      false,\n      tMid,\n      Math.min(1, tMid + 0.3),\n      out\n    );\n  }\n}\n\nconst BOLT_PRESETS = [\n  { label: \"Ice Blue\", hex: \"#E0F2FE\" },\n  { label: \"Plasma Violet\", hex: \"#DDD6FE\" },\n  { label: \"Ion Cyan\", hex: \"#A5F3FC\" },\n  { label: \"Solar Amber\", hex: \"#FEF08A\" },\n];\n\nexport function Thunderstorm({\n  rainIntensity = 180,\n  lightningFrequency = 0.35,\n  windAngle = 14,\n  boltColor = \"#E0F2FE\",\n  flashIntensity = 0.6,\n  children,\n  className,\n}: ThunderstormProps) {\n  const containerRef = useRef<HTMLDivElement>(null);\n  const canvasRef = useRef<HTMLCanvasElement>(null);\n\n  const [simRain, setSimRain] = useState(rainIntensity);\n  const [simFreq, setSimFreq] = useState(lightningFrequency);\n  const [simWind, setSimWind] = useState(windAngle);\n  const [simColor, setSimColor] = useState(boltColor);\n  const [simFlash, setSimFlash] = useState(flashIntensity);\n  const [strikeCount, setStrikeCount] = useState(0);\n\n  useEffect(() => setSimRain(rainIntensity), [rainIntensity]);\n  useEffect(() => setSimFreq(lightningFrequency), [lightningFrequency]);\n  useEffect(() => setSimWind(windAngle), [windAngle]);\n  useEffect(() => setSimColor(boltColor), [boltColor]);\n  useEffect(() => setSimFlash(flashIntensity), [flashIntensity]);\n\n  const strikeTriggerRef = useRef<(customX?: number) => void>(() => {});\n\n  const handleManualStrike = useCallback(() => {\n    strikeTriggerRef.current();\n  }, []);\n\n  useEffect(() => {\n    const container = containerRef.current;\n    const canvas = canvasRef.current;\n    if (!container || !canvas) return;\n    const ctx = canvas.getContext(\"2d\");\n    if (!ctx) return;\n\n    let width = container.clientWidth || 800;\n    let height = container.clientHeight || 520;\n    let dpr = Math.min(window.devicePixelRatio || 1, 2);\n\n    const createRainDrop = (w: number, h: number, randomY = true): RainDrop => {\n      const isForeground = Math.random() < 0.28;\n      const depth = isForeground\n        ? 0.72 + Math.random() * 0.28\n        : 0.22 + Math.random() * 0.45;\n      return {\n        x: (Math.random() - 0.3) * w * 1.6,\n        y: randomY ? Math.random() * h : -35 - Math.random() * 60,\n        length: isForeground\n          ? (26 + Math.random() * 24) * depth\n          : (12 + Math.random() * 14) * depth,\n        speed: isForeground\n          ? (18 + Math.random() * 10) * depth\n          : (11 + Math.random() * 7) * depth,\n        depth,\n        isForeground,\n      };\n    };\n\n    const createCloudClusters = (w: number): CloudCluster[] => {\n      const clusters: CloudCluster[] = [];\n      const count = 18;\n      for (let i = 0; i < count; i++) {\n        const layer = i % 3;\n        const lobes: CloudLobe[] = [];\n        const lobeCount = 4 + (i % 3);\n        for (let l = 0; l < lobeCount; l++) {\n          const angle = (l / lobeCount) * Math.PI * 2;\n          lobes.push({\n            offsetX: Math.cos(angle) * (45 + (l % 2) * 35),\n            offsetY: Math.sin(angle) * (14 + (l % 2) * 12),\n            rx: 95 + ((i * 29 + l * 17) % 75),\n            ry: 38 + layer * 12 + ((l * 13) % 18),\n          });\n        }\n        clusters.push({\n          x: (i / count) * (w + 360) - 180,\n          y: 18 + layer * 42 + Math.sin(i * 2.4) * 16,\n          speed: (0.14 + layer * 0.12) * (i % 2 === 0 ? 1 : 0.82),\n          layer,\n          lobes,\n        });\n      }\n      return clusters;\n    };\n\n    let drops: RainDrop[] = Array.from({ length: simRain }, () =>\n      createRainDrop(width, height, true)\n    );\n    let clouds: CloudCluster[] = createCloudClusters(width);\n    const bolts: LightningBolt[] = [];\n    const splashes: SplashRipple[] = [];\n    let screenFlash = 0;\n    let flashCenterX = width * 0.5;\n    let flashCenterY = 55;\n    let time = 0;\n\n    const spawnBolt = (customX?: number) => {\n      const originX =\n        customX !== undefined\n          ? customX\n          : width * (0.14 + Math.random() * 0.72);\n      const originY = 18 + Math.random() * 38;\n      const targetX = originX + (Math.random() - 0.5) * 210;\n      const targetY = height * (0.78 + Math.random() * 0.22);\n\n      const segments: Segment[] = [];\n      generateSteppedLeaderSegments(\n        originX,\n        originY,\n        targetX,\n        targetY,\n        125,\n        3.4,\n        1.1,\n        1.0,\n        6,\n        true,\n        0,\n        1,\n        segments\n      );\n\n      const f1 = 4 + Math.floor(Math.random() * 3);\n      const f2 = f1 + 3 + Math.floor(Math.random() * 4);\n\n      bolts.push({\n        segments,\n        originX,\n        originY,\n        life: 0,\n        maxLife: 26 + Math.floor(Math.random() * 10),\n        restrikeFrames: [f1, f2],\n      });\n\n      screenFlash = Math.min(1.1, screenFlash + 0.92);\n      flashCenterX = originX;\n      flashCenterY = originY + 24;\n      setStrikeCount((c) => c + 1);\n    };\n\n    strikeTriggerRef.current = spawnBolt;\n\n    const updateSize = () => {\n      if (!container || !canvas) return;\n      width = container.clientWidth || 800;\n      height = container.clientHeight || 520;\n      dpr = Math.min(window.devicePixelRatio || 1, 2);\n      canvas.width = Math.floor(width * dpr);\n      canvas.height = Math.floor(height * dpr);\n      ctx.setTransform(dpr, 0, 0, dpr, 0, 0);\n      clouds = createCloudClusters(width);\n    };\n\n    updateSize();\n    const observer = new ResizeObserver(updateSize);\n    observer.observe(container);\n\n    const initialTimer = setTimeout(() => {\n      spawnBolt(width * 0.56);\n    }, 320);\n\n    let rafId = 0;\n    const rgb = hexToRgb(simColor);\n\n    const render = () => {\n      time += 0.016;\n\n      if (drops.length < simRain) {\n        while (drops.length < simRain) {\n          drops.push(createRainDrop(width, height, true));\n        }\n      } else if (drops.length > simRain) {\n        drops.length = simRain;\n      }\n\n      if (simFreq > 0 && Math.random() < simFreq * 0.022) {\n        spawnBolt();\n      }\n\n      screenFlash *= 0.87;\n      const effectiveFlash = screenFlash * simFlash;\n\n      // Deep storm atmosphere gradient\n      const skyGrad = ctx.createLinearGradient(0, 0, 0, height);\n      const boost = Math.floor(effectiveFlash * 48);\n      skyGrad.addColorStop(\n        0,\n        `rgb(${5 + boost}, ${9 + boost}, ${19 + Math.floor(boost * 1.45)})`\n      );\n      skyGrad.addColorStop(\n        0.55,\n        `rgb(${10 + boost}, ${16 + boost}, ${31 + Math.floor(boost * 1.3)})`\n      );\n      skyGrad.addColorStop(1, \"#04070f\");\n      ctx.fillStyle = skyGrad;\n      ctx.fillRect(0, 0, width, height);\n\n      // Slanted distant rain sheets (curtains)\n      const rad = (simWind * Math.PI) / 180;\n      const sinA = Math.sin(rad);\n      const cosA = Math.cos(rad);\n\n      ctx.save();\n      for (let s = 0; s < 5; s++) {\n        const sheetX =\n          (((s * 240 + time * (22 + s * 6) * (simWind >= 0 ? 1 : -1)) %\n            (width + 300)) +\n            (width + 300)) %\n            (width + 300) -\n          150;\n        const sheetGrad = ctx.createLinearGradient(\n          sheetX,\n          60,\n          sheetX + sinA * height,\n          height\n        );\n        const sheetAlpha = (0.025 + effectiveFlash * 0.045).toFixed(3);\n        sheetGrad.addColorStop(0, \"rgba(148, 163, 184, 0)\");\n        sheetGrad.addColorStop(0.4, `rgba(186, 230, 253, ${sheetAlpha})`);\n        sheetGrad.addColorStop(1, \"rgba(148, 163, 184, 0)\");\n        ctx.fillStyle = sheetGrad;\n        ctx.beginPath();\n        ctx.moveTo(sheetX - 75, 40);\n        ctx.lineTo(sheetX + 75, 40);\n        ctx.lineTo(sheetX + 75 + sinA * height, height);\n        ctx.lineTo(sheetX - 75 + sinA * height, height);\n        ctx.closePath();\n        ctx.fill();\n      }\n      ctx.restore();\n\n      // Volumetric textured storm cloud banks with internal cyan-violet scattering\n      const windFactor = simWind / 14;\n      for (const cluster of clouds) {\n        cluster.x += cluster.speed * (0.65 + windFactor * 0.45);\n        if (cluster.x > width + 240) cluster.x = -240;\n        if (cluster.x < -240) cluster.x = width + 240;\n\n        const distToBolt = Math.hypot(\n          cluster.x - flashCenterX,\n          cluster.y - flashCenterY\n        );\n        const scatter =\n          effectiveFlash * Math.max(0, Math.exp(-distToBolt / (width * 0.36)));\n\n        for (const lobe of cluster.lobes) {\n          const lx = cluster.x + lobe.offsetX;\n          const ly = cluster.y + lobe.offsetY;\n          const cGrad = ctx.createRadialGradient(\n            lx,\n            ly - lobe.ry * 0.2,\n            lobe.ry * 0.1,\n            lx,\n            ly,\n            lobe.rx\n          );\n\n          const baseR = 11 + cluster.layer * 4;\n          const baseG = 16 + cluster.layer * 6;\n          const baseB = 28 + cluster.layer * 9;\n\n          // Internal cyan-violet subsurface cloud scattering near bolt origin\n          const r = Math.min(255, Math.round(baseR + scatter * (rgb.r * 0.65 + 45)));\n          const g = Math.min(255, Math.round(baseG + scatter * (rgb.g * 0.72 + 30)));\n          const b = Math.min(255, Math.round(baseB + scatter * (rgb.b * 0.9 + 65)));\n\n          cGrad.addColorStop(0, `rgba(${r}, ${g}, ${b}, 0.72)`);\n          cGrad.addColorStop(\n            0.55,\n            `rgba(${Math.round(r * 0.75)}, ${Math.round(g * 0.78)}, ${Math.round(\n              b * 0.85\n            )}, 0.34)`\n          );\n          cGrad.addColorStop(1, `rgba(${baseR}, ${baseG}, ${baseB}, 0)`);\n\n          ctx.fillStyle = cGrad;\n          ctx.beginPath();\n          ctx.ellipse(lx, ly, lobe.rx, lobe.ry, 0, 0, Math.PI * 2);\n          ctx.fill();\n        }\n      }\n\n      // Internal cloud discharge hotspot right around the bolt origin\n      if (effectiveFlash > 0.01) {\n        ctx.save();\n        ctx.globalCompositeOperation = \"screen\";\n        const coreGlow = ctx.createRadialGradient(\n          flashCenterX,\n          flashCenterY,\n          4,\n          flashCenterX,\n          flashCenterY,\n          width * 0.48\n        );\n        coreGlow.addColorStop(\n          0,\n          `rgba(255, 255, 255, ${(effectiveFlash * 0.85).toFixed(3)})`\n        );\n        coreGlow.addColorStop(\n          0.18,\n          `rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, ${(effectiveFlash * 0.62).toFixed(\n            3\n          )})`\n        );\n        coreGlow.addColorStop(\n          0.48,\n          `rgba(167, 139, 250, ${(effectiveFlash * 0.22).toFixed(3)})`\n        );\n        coreGlow.addColorStop(1, \"rgba(0, 0, 0, 0)\");\n        ctx.fillStyle = coreGlow;\n        ctx.fillRect(0, 0, width, height * 0.65);\n        ctx.restore();\n      }\n\n      // Active Stepped-Leader Lightning Bolts with restrike flicker & beaded decay\n      for (let i = bolts.length - 1; i >= 0; i--) {\n        const bolt = bolts[i];\n        bolt.life++;\n        if (bolt.life >= bolt.maxLife) {\n          bolts.splice(i, 1);\n          continue;\n        }\n\n        const isRestrike =\n          bolt.life === bolt.restrikeFrames[0] ||\n          bolt.life === bolt.restrikeFrames[0] + 1 ||\n          bolt.life === bolt.restrikeFrames[1];\n\n        if (bolt.life === bolt.restrikeFrames[0] || bolt.life === bolt.restrikeFrames[1]) {\n          screenFlash = Math.max(screenFlash, 0.72);\n        }\n\n        const progress = bolt.life / bolt.maxLife;\n        const mainFlicker = isRestrike\n          ? 1.0\n          : Math.pow(Math.max(0, 1 - progress), 1.65);\n        const branchFlicker = isRestrike\n          ? 0.75\n          : Math.pow(Math.max(0, 1 - progress * 1.25), 2.1);\n\n        ctx.save();\n        ctx.lineCap = \"round\";\n        ctx.lineJoin = \"round\";\n        ctx.globalCompositeOperation = \"screen\";\n\n        // Pass 1: Wide outer atmospheric HDR bloom\n        for (const seg of bolt.segments) {\n          const f = seg.isMainChannel ? mainFlicker : branchFlicker;\n          const a = seg.alpha * f;\n          if (a <= 0.02) continue;\n          ctx.strokeStyle = `rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, ${(\n            a * 0.18\n          ).toFixed(3)})`;\n          ctx.lineWidth = seg.width * 9.0;\n          ctx.beginPath();\n          ctx.moveTo(seg.x1, seg.y1);\n          ctx.lineTo(seg.x2, seg.y2);\n          ctx.stroke();\n        }\n\n        // Pass 2: Medium cyan-violet plasma sheath\n        for (const seg of bolt.segments) {\n          const f = seg.isMainChannel ? mainFlicker : branchFlicker;\n          const a = seg.alpha * f;\n          if (a <= 0.02) continue;\n          ctx.strokeStyle = `rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, ${(\n            a * 0.52\n          ).toFixed(3)})`;\n          ctx.lineWidth = seg.width * 3.2;\n          ctx.beginPath();\n          ctx.moveTo(seg.x1, seg.y1);\n          ctx.lineTo(seg.x2, seg.y2);\n          ctx.stroke();\n        }\n\n        // Pass 3: White-hot core channel (with beaded ionization decay late in life)\n        for (let sIdx = 0; sIdx < bolt.segments.length; sIdx++) {\n          const seg = bolt.segments[sIdx];\n          const f = seg.isMainChannel ? mainFlicker : branchFlicker;\n          const a = seg.alpha * f;\n          if (a <= 0.02) continue;\n          // During late decay, alternate segments create realistic beaded lightning decay\n          if (progress > 0.62 && !isRestrike && sIdx % 2 === 1) continue;\n\n          ctx.strokeStyle = `rgba(255, 255, 255, ${Math.min(1, a * 1.05).toFixed(\n            3\n          )})`;\n          ctx.lineWidth = seg.width;\n          ctx.beginPath();\n          ctx.moveTo(seg.x1, seg.y1);\n          ctx.lineTo(seg.x2, seg.y2);\n          ctx.stroke();\n        }\n\n        ctx.restore();\n      }\n\n      // Multi-layered rain streaks (distant fine curtains + fast foreground streaks)\n      ctx.lineCap = \"round\";\n      for (const d of drops) {\n        d.x += sinA * d.speed;\n        d.y += cosA * d.speed;\n\n        if (d.y > height - 4) {\n          if (d.isForeground && splashes.length < 70 && Math.random() < 0.45) {\n            splashes.push({\n              x: d.x,\n              y: height - 2 - Math.random() * 8,\n              vx: (Math.random() - 0.5) * 2.2 + sinA * 1.2,\n              vy: -(1.4 + Math.random() * 2.1),\n              life: 0,\n              maxLife: 10 + Math.floor(Math.random() * 8),\n            });\n          }\n          d.y = -30 - Math.random() * 45;\n          d.x = (Math.random() - 0.3) * width * 1.6;\n        }\n        if (d.x > width + 160) d.x = -120;\n        if (d.x < -160) d.x = width + 120;\n\n        const baseAlpha = d.isForeground\n          ? 0.24 + d.depth * 0.28\n          : 0.09 + d.depth * 0.16;\n        const alpha = baseAlpha * (1 + effectiveFlash * 0.75);\n        ctx.strokeStyle = `rgba(186, 230, 253, ${Math.min(0.88, alpha).toFixed(\n          3\n        )})`;\n        ctx.lineWidth = d.isForeground ? 1.1 + d.depth * 0.8 : 0.55 + d.depth * 0.45;\n        ctx.beginPath();\n        ctx.moveTo(d.x, d.y);\n        ctx.lineTo(d.x - sinA * d.length, d.y - cosA * d.length);\n        ctx.stroke();\n      }\n\n      // Bottom splash droplets & ground mist\n      for (let i = splashes.length - 1; i >= 0; i--) {\n        const sp = splashes[i];\n        sp.life++;\n        if (sp.life >= sp.maxLife) {\n          splashes.splice(i, 1);\n          continue;\n        }\n        sp.x += sp.vx;\n        sp.y += sp.vy;\n        sp.vy += 0.28;\n        const spAlpha = (1 - sp.life / sp.maxLife) * 0.45;\n        ctx.fillStyle = `rgba(224, 242, 254, ${spAlpha.toFixed(3)})`;\n        ctx.beginPath();\n        ctx.arc(sp.x, sp.y, 1.1, 0, Math.PI * 2);\n        ctx.fill();\n      }\n\n      const splashMist = ctx.createLinearGradient(0, height - 55, 0, height);\n      splashMist.addColorStop(0, \"rgba(15, 23, 42, 0)\");\n      splashMist.addColorStop(\n        1,\n        `rgba(148, 163, 184, ${(0.08 + effectiveFlash * 0.12).toFixed(3)})`\n      );\n      ctx.fillStyle = splashMist;\n      ctx.fillRect(0, height - 55, width, 55);\n\n      // Full-screen atmospheric exposure flash\n      if (effectiveFlash > 0.02) {\n        ctx.fillStyle = `rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, ${(\n          effectiveFlash * 0.18\n        ).toFixed(3)})`;\n        ctx.fillRect(0, 0, width, height);\n      }\n\n      rafId = requestAnimationFrame(render);\n    };\n\n    rafId = requestAnimationFrame(render);\n\n    return () => {\n      clearTimeout(initialTimer);\n      cancelAnimationFrame(rafId);\n      observer.disconnect();\n    };\n  }, [simRain, simFreq, simWind, simColor, simFlash]);\n\n  const handleCanvasClick = (e: React.MouseEvent<HTMLDivElement>) => {\n    if ((e.target as HTMLElement).closest(\"[data-hud-panel]\")) return;\n    const rect = e.currentTarget.getBoundingClientRect();\n    strikeTriggerRef.current(e.clientX - rect.left);\n  };\n\n  const resetDefaults = () => {\n    setSimRain(rainIntensity);\n    setSimFreq(lightningFrequency);\n    setSimWind(windAngle);\n    setSimColor(boltColor);\n    setSimFlash(flashIntensity);\n  };\n\n  return (\n    <div\n      ref={containerRef}\n      data-fullscreen-scroll\n      onClick={handleCanvasClick}\n      className={cn(\n        \"relative w-full min-h-[520px] overflow-hidden rounded-2xl bg-[#04070f] text-slate-100 select-none cursor-crosshair\",\n        className\n      )}\n    >\n      <canvas\n        ref={canvasRef}\n        className=\"pointer-events-none absolute inset-0 h-full w-full\"\n      />\n\n      {children && (\n        <div className=\"relative z-10 flex min-h-[520px] w-full flex-col\">\n          {children}\n        </div>\n      )}\n    </div>\n  );\n}\n\nexport default Thunderstorm;\n",
          "type": "registry:ui",
          "target": "components/ui/thunderstorm.tsx"
        },
        {
          "path": "lib/utils.ts",
          "content": "import { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...inputs: ClassValue[]) {\n  return twMerge(clsx(inputs));\n}\n\nexport async function copyToClipboard(text: string): Promise<boolean> {\n  if (typeof window === \"undefined\") return false;\n\n  try {\n    if (navigator.clipboard && window.isSecureContext) {\n      await navigator.clipboard.writeText(text);\n      return true;\n    }\n\n    const textArea = document.createElement(\"textarea\");\n    textArea.value = text;\n    textArea.style.position = \"fixed\";\n    textArea.style.left = \"-999999px\";\n    textArea.style.top = \"-999999px\";\n    document.body.appendChild(textArea);\n    textArea.focus();\n    textArea.select();\n    const succeeded = document.execCommand(\"copy\");\n    textArea.remove();\n    return succeeded;\n  } catch {\n    return false;\n  }\n}\n",
          "type": "registry:lib",
          "target": "lib/utils.ts"
        }
      ]
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "tilt-credit-card3-d",
      "type": "registry:ui",
      "title": "Tilt Credit Card 3D",
      "author": "Rishabh Bose <https://theb0se.vercel.app/>",
      "description": "Revolut and Apple Card-inspired premium 3D metal card with cursor-tilt gyroscope physics, rainbow holographic foil reflection, gold EMV chip, contactless RFID waves, and dual-side flip mechanics.",
      "dependencies": [
        "framer-motion",
        "lucide-react",
        "clsx",
        "tailwind-merge"
      ],
      "files": [
        {
          "path": "components/ui/tilt-credit-card3-d.tsx",
          "content": "\"use client\";\n\nimport React, { useState, useRef, useCallback } from \"react\";\nimport { motion, useMotionValue, useSpring, useTransform } from \"framer-motion\";\nimport {\n  Wifi,\n  Eye,\n  EyeOff,\n  RotateCw,\n  Sparkles,\n  ShieldCheck,\n  CreditCard as CreditCardIcon,\n} from \"lucide-react\";\nimport { cn } from \"@/lib/utils\";\n\nexport type CardTheme = \"titanium\" | \"obsidian\" | \"rosegold\" | \"holographic\";\n\nexport interface TiltCreditCard3DProps {\n  cardHolder?: string;\n  cardNumber?: string;\n  expiry?: string;\n  cvv?: string;\n  theme?: CardTheme;\n  className?: string;\n}\n\nconst THEME_STYLES: Record<\n  CardTheme,\n  {\n    name: string;\n    bgGradient: string;\n    foilOpacity: string;\n    textColor: string;\n    chipColor: string;\n    border: string;\n  }\n> = {\n  titanium: {\n    name: \"Titanium Metal\",\n    bgGradient:\n      \"linear-gradient(135deg, #d8d8d8 0%, #b0b0b0 25%, #ececec 50%, #8c8c8c 75%, #cfcfcf 100%)\",\n    foilOpacity: \"opacity-40\",\n    textColor: \"text-neutral-900\",\n    chipColor: \"from-amber-200 via-yellow-400 to-amber-600\",\n    border: \"border-neutral-300/60 shadow-2xl shadow-neutral-900/30\",\n  },\n  obsidian: {\n    name: \"Obsidian Black\",\n    bgGradient:\n      \"linear-gradient(135deg, #18181b 0%, #09090b 45%, #27272a 75%, #09090b 100%)\",\n    foilOpacity: \"opacity-25\",\n    textColor: \"text-neutral-100\",\n    chipColor: \"from-amber-300 via-amber-500 to-yellow-600\",\n    border: \"border-neutral-700/50 shadow-2xl shadow-black/80\",\n  },\n  rosegold: {\n    name: \"Rose Gold\",\n    bgGradient:\n      \"linear-gradient(135deg, #fbcfe8 0%, #f472b6 35%, #fdf2f8 65%, #db2777 85%, #fbcfe8 100%)\",\n    foilOpacity: \"opacity-50\",\n    textColor: \"text-rose-950\",\n    chipColor: \"from-amber-200 via-amber-400 to-amber-500\",\n    border: \"border-rose-300/50 shadow-2xl shadow-rose-950/20\",\n  },\n  holographic: {\n    name: \"Holo Prism\",\n    bgGradient:\n      \"linear-gradient(135deg, #0f172a 0%, #1e1b4b 25%, #312e81 50%, #0f172a 100%)\",\n    foilOpacity: \"opacity-75\",\n    textColor: \"text-white\",\n    chipColor: \"from-amber-200 via-yellow-300 to-amber-500\",\n    border: \"border-indigo-400/40 shadow-2xl shadow-indigo-950/40\",\n  },\n};\n\nexport function TiltCreditCard3D({\n  cardHolder: initialHolder = \"ALEXANDER VANCE\",\n  cardNumber: initialNumber = \"4532 8901 2345 7892\",\n  expiry: initialExpiry = \"09/29\",\n  cvv: initialCvv = \"842\",\n  theme: initialTheme = \"titanium\",\n  className,\n}: TiltCreditCard3DProps) {\n  const [currentTheme, setCurrentTheme] = useState<CardTheme>(initialTheme);\n  const [isFlipped, setIsFlipped] = useState(false);\n  const [showSensitive, setShowSensitive] = useState(false);\n  const [holderName, setHolderName] = useState(initialHolder);\n\n  const containerRef = useRef<HTMLDivElement>(null);\n\n  // Framer Motion spring physics for mouse tilt\n  const mouseX = useMotionValue(0);\n  const mouseY = useMotionValue(0);\n\n  const springConfig = { damping: 20, stiffness: 260, mass: 0.6 };\n  const smoothMouseX = useSpring(mouseX, springConfig);\n  const smoothMouseY = useSpring(mouseY, springConfig);\n\n  const rotateX = useTransform(smoothMouseY, [-0.5, 0.5], [18, -18]);\n  const rotateY = useTransform(smoothMouseX, [-0.5, 0.5], [-22, 22]);\n\n  // Dynamic holographic reflection positioning\n  const glareX = useTransform(smoothMouseX, [-0.5, 0.5], [\"0%\", \"100%\"]);\n  const glareY = useTransform(smoothMouseY, [-0.5, 0.5], [\"0%\", \"100%\"]);\n\n  const handlePointerMove = useCallback(\n    (e: React.PointerEvent<HTMLDivElement>) => {\n      if (!containerRef.current) return;\n      const rect = containerRef.current.getBoundingClientRect();\n      const x = (e.clientX - rect.left) / rect.width - 0.5;\n      const y = (e.clientY - rect.top) / rect.height - 0.5;\n      mouseX.set(x);\n      mouseY.set(y);\n    },\n    [mouseX, mouseY]\n  );\n\n  const handlePointerLeave = useCallback(() => {\n    mouseX.set(0);\n    mouseY.set(0);\n  }, [mouseX, mouseY]);\n\n  const activeThemeConfig = THEME_STYLES[currentTheme];\n\n  const maskedNumber = showSensitive\n    ? initialNumber\n    : `•••• •••• •••• ${initialNumber.slice(-4)}`;\n\n  return (\n    <div\n      data-fullscreen-scroll\n      className={cn(\n        \"relative w-full min-h-[520px] overflow-hidden rounded-2xl border border-neutral-200/80 bg-neutral-950 p-6 text-neutral-100 shadow-xl dark:border-neutral-800 flex flex-col justify-between items-center\",\n        className\n      )}\n    >\n      {/* Background ambient lighting */}\n      <div className=\"pointer-events-none absolute -top-40 left-1/2 -translate-x-1/2 h-96 w-96 rounded-full bg-indigo-500/10 blur-[120px]\" />\n\n      {/* Top Header & Theme Selector */}\n      <div className=\"relative z-10 w-full flex flex-col sm:flex-row items-center justify-between gap-4\">\n        <div className=\"flex items-center gap-2\">\n          <CreditCardIcon className=\"h-5 w-5 text-neutral-400\" />\n          <span className=\"font-semibold text-sm tracking-wide text-neutral-200\">\n            Vault 3D Metal Card\n          </span>\n          <span className=\"rounded-full bg-emerald-500/10 border border-emerald-500/20 px-2 py-0.5 text-[10px] font-semibold text-emerald-400\">\n            EMV Certified\n          </span>\n        </div>\n\n        {/* Theme pills */}\n        <div className=\"flex items-center gap-1.5 rounded-xl border border-neutral-800 bg-neutral-900/90 p-1 backdrop-blur-md\">\n          {(Object.keys(THEME_STYLES) as CardTheme[]).map((themeKey) => {\n            const isSelected = currentTheme === themeKey;\n            return (\n              <button\n                key={themeKey}\n                type=\"button\"\n                onClick={() => setCurrentTheme(themeKey)}\n                className={cn(\n                  \"relative rounded-lg px-2.5 py-1 text-xs font-medium transition-colors\",\n                  isSelected\n                    ? \"text-white font-semibold\"\n                    : \"text-neutral-400 hover:text-neutral-200\"\n                )}\n              >\n                {isSelected && (\n                  <motion.div\n                    layoutId=\"active-card-theme\"\n                    className=\"absolute inset-0 rounded-lg bg-neutral-800\"\n                    transition={{ type: \"spring\", stiffness: 400, damping: 30 }}\n                  />\n                )}\n                <span className=\"relative z-10\">{THEME_STYLES[themeKey].name}</span>\n              </button>\n            );\n          })}\n        </div>\n      </div>\n\n      {/* 3D Perspective Card Stage */}\n      <div\n        ref={containerRef}\n        onPointerMove={handlePointerMove}\n        onPointerLeave={handlePointerLeave}\n        className=\"relative my-8 h-[250px] w-full max-w-[420px] cursor-grab active:cursor-grabbing [perspective:1200px]\"\n      >\n        <motion.div\n          style={{\n            rotateX,\n            rotateY,\n            transformStyle: \"preserve-3d\",\n          }}\n          animate={{\n            rotateY: isFlipped ? 180 : 0,\n          }}\n          transition={{\n            rotateY: { duration: 0.6, ease: [0.23, 1, 0.32, 1] },\n          }}\n          className=\"relative h-full w-full rounded-2xl select-none\"\n        >\n          {/* ================= CARD FRONT ================= */}\n          <div\n            style={{\n              backfaceVisibility: \"hidden\",\n              background: activeThemeConfig.bgGradient,\n            }}\n            className={cn(\n              \"absolute inset-0 flex flex-col justify-between overflow-hidden rounded-2xl border p-6 [transform:translateZ(1px)]\",\n              activeThemeConfig.border,\n              activeThemeConfig.textColor\n            )}\n          >\n            {/* Dynamic Holographic Foil Glare Overlay */}\n            <motion.div\n              style={{\n                background: `radial-gradient(circle at ${glareX} ${glareY}, rgba(255,255,255,0.7) 0%, rgba(255,182,255,0.3) 30%, rgba(130,220,255,0.2) 60%, transparent 80%)`,\n              }}\n              className={cn(\n                \"pointer-events-none absolute inset-0 mix-blend-overlay transition-opacity duration-300\",\n                activeThemeConfig.foilOpacity\n              )}\n            />\n\n            {/* Brushed metal line texture overlay */}\n            <div className=\"pointer-events-none absolute inset-0 opacity-15 bg-[radial-gradient(#fff_1px,transparent_1px)] [background-size:12px_12px]\" />\n\n            {/* Top row: Chip + Contactless waves + Brand */}\n            <div className=\"relative z-10 flex items-center justify-between\">\n              <div className=\"flex items-center gap-3\">\n                {/* Gold EMV Chip */}\n                <div\n                  className={cn(\n                    \"relative h-9 w-12 rounded-md border border-yellow-700/60 bg-gradient-to-br shadow-inner\",\n                    activeThemeConfig.chipColor\n                  )}\n                >\n                  <div className=\"absolute inset-x-0 top-1/2 h-px -translate-y-1/2 bg-yellow-900/40\" />\n                  <div className=\"absolute inset-y-0 left-1/3 w-px bg-yellow-900/40\" />\n                  <div className=\"absolute inset-y-0 right-1/3 w-px bg-yellow-900/40\" />\n                  <div className=\"absolute left-1/2 top-1/2 h-3.5 w-4 -translate-x-1/2 -translate-y-1/2 rounded-[3px] border border-yellow-900/40\" />\n                </div>\n\n                {/* Contactless RFID Icon */}\n                <Wifi className=\"h-5 w-5 rotate-90 opacity-80\" />\n              </div>\n\n              {/* Bank Logo / Elite Mark */}\n              <div className=\"flex items-center gap-1.5 font-bold tracking-widest text-xs uppercase opacity-90 font-mono\">\n                <Sparkles className=\"h-4 w-4\" />\n                <span>PULSE BLACK</span>\n              </div>\n            </div>\n\n            {/* Middle: Debossed Card Number */}\n            <div className=\"relative z-10 my-auto\">\n              <p className=\"font-mono text-xl sm:text-2xl font-bold tracking-[0.22em] drop-shadow-[0_1px_1px_rgba(0,0,0,0.4)]\">\n                {maskedNumber}\n              </p>\n            </div>\n\n            {/* Bottom Row: Holder Name + Expiry + Network Logo */}\n            <div className=\"relative z-10 flex items-end justify-between text-xs tracking-wider\">\n              <div>\n                <span className=\"block text-[9px] uppercase tracking-widest opacity-60 font-semibold\">\n                  Cardholder Name\n                </span>\n                <span className=\"font-mono font-bold uppercase drop-shadow-[0_1px_1px_rgba(0,0,0,0.4)]\">\n                  {holderName || \"YOUR NAME\"}\n                </span>\n              </div>\n\n              <div className=\"text-center\">\n                <span className=\"block text-[9px] uppercase tracking-widest opacity-60 font-semibold\">\n                  Valid Thru\n                </span>\n                <span className=\"font-mono font-bold drop-shadow-[0_1px_1px_rgba(0,0,0,0.4)]\">\n                  {initialExpiry}\n                </span>\n              </div>\n\n              {/* Overlapping Master Circles or Visa Stylized */}\n              <div className=\"flex items-center\">\n                <div className=\"h-7 w-7 rounded-full bg-rose-500/80 mix-blend-multiply opacity-90\" />\n                <div className=\"-ml-3 h-7 w-7 rounded-full bg-amber-400/80 mix-blend-multiply opacity-90\" />\n              </div>\n            </div>\n          </div>\n\n          {/* ================= CARD BACK ================= */}\n          <div\n            style={{\n              backfaceVisibility: \"hidden\",\n              transform: \"rotateY(180deg)\",\n              background: activeThemeConfig.bgGradient,\n            }}\n            className={cn(\n              \"absolute inset-0 flex flex-col justify-between overflow-hidden rounded-2xl border p-0 [transform:rotateY(180deg)_translateZ(1px)]\",\n              activeThemeConfig.border,\n              activeThemeConfig.textColor\n            )}\n          >\n            {/* Magnetic Stripe */}\n            <div className=\"mt-6 h-12 w-full bg-neutral-900 shadow-inner\" />\n\n            <div className=\"p-6 pt-2 flex flex-col justify-between flex-1\">\n              {/* Signature Strip & CVV Box */}\n              <div className=\"mt-2 flex items-center gap-2\">\n                <div className=\"h-10 flex-1 rounded bg-neutral-100/90 p-2 text-[10px] font-mono italic text-neutral-600 flex items-center justify-end select-none border border-neutral-300\">\n                  Authorized Signature\n                </div>\n                <div className=\"h-10 w-16 rounded bg-neutral-200/95 flex items-center justify-center font-mono font-bold text-neutral-900 border border-neutral-400 tracking-wider\">\n                  {showSensitive ? initialCvv : \"•••\"}\n                </div>\n              </div>\n\n              {/* Security info text */}\n              <div className=\"space-y-1 text-[9px] opacity-70 leading-relaxed font-mono\">\n                <p>\n                  This titanium metal card is property of Pulse Financial Inc.\n                  Unauthorized use or transfer is prohibited by law.\n                </p>\n                <div className=\"flex items-center justify-between pt-2 border-t border-current/20\">\n                  <span>24/7 Global Concierge: +1 (800) 555-PULSE</span>\n                  <div className=\"flex items-center gap-1 font-bold\">\n                    <ShieldCheck className=\"h-3.5 w-3.5\" />\n                    <span>SECURE NFC</span>\n                  </div>\n                </div>\n              </div>\n            </div>\n          </div>\n        </motion.div>\n      </div>\n    </div>\n  );\n}\n\nexport default TiltCreditCard3D;\n",
          "type": "registry:ui",
          "target": "components/ui/tilt-credit-card3-d.tsx"
        },
        {
          "path": "lib/utils.ts",
          "content": "import { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...inputs: ClassValue[]) {\n  return twMerge(clsx(inputs));\n}\n\nexport async function copyToClipboard(text: string): Promise<boolean> {\n  if (typeof window === \"undefined\") return false;\n\n  try {\n    if (navigator.clipboard && window.isSecureContext) {\n      await navigator.clipboard.writeText(text);\n      return true;\n    }\n\n    const textArea = document.createElement(\"textarea\");\n    textArea.value = text;\n    textArea.style.position = \"fixed\";\n    textArea.style.left = \"-999999px\";\n    textArea.style.top = \"-999999px\";\n    document.body.appendChild(textArea);\n    textArea.focus();\n    textArea.select();\n    const succeeded = document.execCommand(\"copy\");\n    textArea.remove();\n    return succeeded;\n  } catch {\n    return false;\n  }\n}\n",
          "type": "registry:lib",
          "target": "lib/utils.ts"
        }
      ]
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "toast-stack",
      "type": "registry:ui",
      "title": "Toast Stack",
      "author": "Rishabh Bose <https://theb0se.vercel.app/>",
      "description": "Stacked viewport notification toasts supporting 6 viewport positions (top/bottom + left/center/right), hover fan-out, and auto-dismiss.",
      "dependencies": [
        "framer-motion",
        "lucide-react",
        "clsx",
        "tailwind-merge"
      ],
      "files": [
        {
          "path": "components/ui/toast-stack.tsx",
          "content": "\"use client\";\n\nimport React, { useState, useCallback, useEffect } from \"react\";\nimport { createPortal } from \"react-dom\";\nimport { AnimatePresence, motion, useReducedMotion } from \"framer-motion\";\nimport {\n  AlertTriangle,\n  Bell,\n  CheckCircle2,\n  Info,\n  Trash2,\n  X,\n  XCircle,\n} from \"lucide-react\";\nimport { cn } from \"@/lib/utils\";\n\nexport type ToastVariant = \"default\" | \"success\" | \"error\" | \"warning\";\n\nexport type ToastPosition =\n  | \"top-left\"\n  | \"top-center\"\n  | \"top-right\"\n  | \"bottom-left\"\n  | \"bottom-center\"\n  | \"bottom-right\";\n\nexport interface ToastItem {\n  id: string;\n  title: string;\n  description?: string;\n  variant?: ToastVariant;\n  actionLabel?: string;\n  onAction?: () => void;\n}\n\nexport interface ToastStackProps {\n  /** Viewport position of the toast stack */\n  position?: ToastPosition;\n  /** Initial toast items displayed in the stack */\n  initialToasts?: ToastItem[];\n  /** Maximum visible toasts in the stack */\n  maxVisible?: number;\n  /** Automatically dismiss toasts after duration (paused on hover) */\n  autoDismiss?: boolean;\n  /** Auto-dismiss duration in milliseconds. Default: 4500 */\n  duration?: number;\n  /** Render toasts fixed to the viewport via portal (default: true) */\n  viewportPortal?: boolean;\n  /** Additional container class names */\n  className?: string;\n}\n\nconst ALL_POSITIONS: ToastPosition[] = [\n  \"top-left\",\n  \"top-center\",\n  \"top-right\",\n  \"bottom-left\",\n  \"bottom-center\",\n  \"bottom-right\",\n];\n\nconst POSITION_CLASSES: Record<ToastPosition, string> = {\n  \"top-left\": \"top-5 left-5 items-start\",\n  \"top-center\": \"top-5 left-1/2 -translate-x-1/2 items-center\",\n  \"top-right\": \"top-5 right-5 items-end\",\n  \"bottom-left\": \"bottom-5 left-5 items-start\",\n  \"bottom-center\": \"bottom-5 left-1/2 -translate-x-1/2 items-center\",\n  \"bottom-right\": \"bottom-5 right-5 items-end\",\n};\n\nfunction getVariantIcon(variant: ToastVariant = \"default\") {\n  switch (variant) {\n    case \"success\":\n      return (\n        <CheckCircle2 className=\"h-4 w-4 shrink-0 text-black dark:text-white\" />\n      );\n    case \"error\":\n      return <XCircle className=\"h-4 w-4 shrink-0 text-black dark:text-white\" />;\n    case \"warning\":\n      return (\n        <AlertTriangle className=\"h-4 w-4 shrink-0 text-black dark:text-white\" />\n      );\n    default:\n      return <Info className=\"h-4 w-4 shrink-0 text-neutral-500\" />;\n  }\n}\n\nexport function ToastStack({\n  position = \"bottom-right\",\n  initialToasts = [],\n  maxVisible = 4,\n  autoDismiss = true,\n  duration = 4500,\n  viewportPortal = true,\n  className,\n}: ToastStackProps) {\n  const shouldReduceMotion = useReducedMotion();\n  const [mounted, setMounted] = useState(false);\n  const [activePosition, setActivePosition] = useState<ToastPosition>(position);\n  const [toasts, setToasts] = useState<ToastItem[]>(initialToasts);\n  const [expanded, setExpanded] = useState(false);\n\n  useEffect(() => {\n    setMounted(true);\n  }, []);\n\n  useEffect(() => {\n    setActivePosition(position);\n  }, [position]);\n\n  // Auto-dismiss timer (pauses while user hovers the stack)\n  useEffect(() => {\n    if (!autoDismiss || expanded || toasts.length === 0) return;\n    const timer = setTimeout(() => {\n      setToasts((prev) => prev.slice(0, -1));\n    }, duration);\n    return () => clearTimeout(timer);\n  }, [autoDismiss, duration, expanded, toasts]);\n\n  const pushToast = useCallback(\n    (variant: ToastVariant, posOverride?: ToastPosition) => {\n      const targetPos = posOverride || activePosition;\n      if (posOverride) setActivePosition(posOverride);\n\n      const id = `toast-${Date.now()}-${Math.random().toString(36).slice(2, 6)}`;\n      const presets: Record<ToastVariant, { title: string; description: string }> = {\n        default: {\n          title: `Notification (${targetPos})`,\n          description: \"Hover the stack to pause auto-dismiss and expand.\",\n        },\n        success: {\n          title: \"Deployment Succeeded\",\n          description: `Anchored at ${targetPos} of your viewport.`,\n        },\n        warning: {\n          title: \"Rate Limit Approaching\",\n          description: \"85% of your hourly API quota has been used.\",\n        },\n        error: {\n          title: \"Build Failed\",\n          description: \"Check the terminal logs for details.\",\n        },\n      };\n\n      setToasts((prev) => [\n        { id, variant, ...presets[variant] },\n        ...prev.slice(0, 7),\n      ]);\n    },\n    [activePosition]\n  );\n\n  const dismissToast = useCallback((id: string) => {\n    setToasts((prev) => prev.filter((t) => t.id !== id));\n  }, []);\n\n  const visibleToasts = toasts.slice(0, maxVisible);\n  const isTop = activePosition.startsWith(\"top\");\n  const directionMultiplier = isTop ? 1 : -1;\n\n  const viewportOverlay = (\n    <div\n      role=\"region\"\n      aria-live=\"polite\"\n      aria-label=\"Viewport notifications\"\n      onMouseEnter={() => setExpanded(true)}\n      onMouseLeave={() => setExpanded(false)}\n      className={cn(\n        \"pointer-events-none fixed z-[9999] flex w-full max-w-sm flex-col px-4 sm:px-0\",\n        POSITION_CLASSES[activePosition]\n      )}\n    >\n      <div className=\"relative w-full\">\n        <AnimatePresence initial={false}>\n          {visibleToasts.map((toast, index) => {\n            const yOffset =\n              directionMultiplier * (expanded ? index * 74 : index * 12);\n            const scale = expanded ? 1 : 1 - index * 0.04;\n            const opacity = index >= maxVisible ? 0 : 1 - index * 0.15;\n\n            return (\n              <motion.div\n                key={toast.id}\n                layout\n                initial={\n                  shouldReduceMotion\n                    ? { opacity: 0 }\n                    : {\n                        opacity: 0,\n                        y: isTop ? -24 : 24,\n                        scale: 0.94,\n                      }\n                }\n                animate={{\n                  opacity,\n                  y: yOffset,\n                  scale,\n                  zIndex: maxVisible - index,\n                }}\n                exit={\n                  shouldReduceMotion\n                    ? { opacity: 0 }\n                    : {\n                        opacity: 0,\n                        scale: 0.92,\n                        transition: { duration: 0.15 },\n                      }\n                }\n                transition={{\n                  type: \"spring\",\n                  stiffness: 400,\n                  damping: 30,\n                }}\n                style={{\n                  [isTop ? \"top\" : \"bottom\"]: 0,\n                }}\n                className=\"pointer-events-auto absolute left-0 right-0 flex items-start justify-between gap-3 rounded-xl border border-neutral-200 bg-white p-3.5 text-black shadow-2xl dark:border-[#262626] dark:bg-[#0C0C0C] dark:text-white\"\n              >\n                <div className=\"flex min-w-0 items-start gap-2.5\">\n                  <div className=\"mt-0.5\">{getVariantIcon(toast.variant)}</div>\n                  <div className=\"min-w-0\">\n                    <div className=\"truncate text-xs font-semibold text-black dark:text-white\">\n                      {toast.title}\n                    </div>\n                    {toast.description && (\n                      <p className=\"mt-0.5 truncate text-[11px] text-neutral-500 dark:text-neutral-400\">\n                        {toast.description}\n                      </p>\n                    )}\n                  </div>\n                </div>\n\n                <button\n                  type=\"button\"\n                  onClick={() => dismissToast(toast.id)}\n                  aria-label=\"Dismiss notification\"\n                  className=\"shrink-0 cursor-pointer rounded-md p-1 text-neutral-400 transition-colors hover:bg-neutral-100 hover:text-black dark:hover:bg-[#1A1A1A] dark:hover:text-white\"\n                >\n                  <X className=\"h-3.5 w-3.5\" />\n                </button>\n              </motion.div>\n            );\n          })}\n        </AnimatePresence>\n      </div>\n    </div>\n  );\n\n  return (\n    <div\n      className={cn(\n        \"flex w-full max-w-md flex-col items-center gap-4\",\n        className\n      )}\n    >\n      {/* Position Selector Grid */}\n      <div className=\"w-full rounded-2xl border border-neutral-200 bg-white p-4 dark:border-[#222222] dark:bg-[#0A0A0A]\">\n        <div className=\"mb-2.5 flex items-center justify-between font-mono text-[10px] uppercase tracking-wider text-neutral-400\">\n          <span>Viewport Position ({toasts.length} active)</span>\n          <div className=\"flex items-center gap-2\">\n            {toasts.length > 0 && (\n              <button\n                type=\"button\"\n                onClick={() => setToasts([])}\n                className=\"inline-flex cursor-pointer items-center gap-1 text-neutral-400 hover:text-black dark:hover:text-white\"\n              >\n                <Trash2 className=\"h-3 w-3\" />\n                <span>Clear</span>\n              </button>\n            )}\n            <span className=\"text-black dark:text-white\">{activePosition}</span>\n          </div>\n        </div>\n\n        <div className=\"grid grid-cols-3 gap-1.5\">\n          {ALL_POSITIONS.map((pos) => {\n            const isSelected = activePosition === pos;\n            return (\n              <button\n                key={pos}\n                type=\"button\"\n                onClick={() => {\n                  setActivePosition(pos);\n                  pushToast(\"default\", pos);\n                }}\n                className={cn(\n                  \"cursor-pointer rounded-lg border px-2.5 py-2 font-mono text-[10px] transition-colors\",\n                  isSelected\n                    ? \"border-black bg-black text-white dark:border-white dark:bg-white dark:text-black\"\n                    : \"border-neutral-200 bg-neutral-50 text-neutral-600 hover:border-black hover:text-black dark:border-[#222222] dark:bg-[#111111] dark:text-neutral-400 dark:hover:border-white dark:hover:text-white\"\n                )}\n              >\n                {pos}\n              </button>\n            );\n          })}\n        </div>\n\n        {/* Variant Triggers */}\n        <div className=\"mt-3 flex flex-wrap items-center justify-between gap-1.5 border-t border-neutral-200 pt-3 dark:border-[#1F1F1F]\">\n          {([\"success\", \"default\", \"warning\", \"error\"] as ToastVariant[]).map(\n            (variant) => (\n              <button\n                key={variant}\n                type=\"button\"\n                onClick={() => pushToast(variant)}\n                className=\"inline-flex flex-1 cursor-pointer items-center justify-center gap-1 rounded-lg border border-neutral-200 bg-white px-2.5 py-1.5 font-mono text-[10px] capitalize text-black transition-colors hover:border-black dark:border-[#262626] dark:bg-[#121212] dark:text-white dark:hover:border-white\"\n              >\n                <Bell className=\"h-3 w-3 text-neutral-400\" />\n                <span>{variant}</span>\n              </button>\n            )\n          )}\n        </div>\n      </div>\n\n      {viewportPortal && mounted && createPortal(viewportOverlay, document.body)}\n    </div>\n  );\n}\n\nexport default ToastStack;\n",
          "type": "registry:ui",
          "target": "components/ui/toast-stack.tsx"
        },
        {
          "path": "lib/utils.ts",
          "content": "import { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...inputs: ClassValue[]) {\n  return twMerge(clsx(inputs));\n}\n\nexport async function copyToClipboard(text: string): Promise<boolean> {\n  if (typeof window === \"undefined\") return false;\n\n  try {\n    if (navigator.clipboard && window.isSecureContext) {\n      await navigator.clipboard.writeText(text);\n      return true;\n    }\n\n    const textArea = document.createElement(\"textarea\");\n    textArea.value = text;\n    textArea.style.position = \"fixed\";\n    textArea.style.left = \"-999999px\";\n    textArea.style.top = \"-999999px\";\n    document.body.appendChild(textArea);\n    textArea.focus();\n    textArea.select();\n    const succeeded = document.execCommand(\"copy\");\n    textArea.remove();\n    return succeeded;\n  } catch {\n    return false;\n  }\n}\n",
          "type": "registry:lib",
          "target": "lib/utils.ts"
        }
      ]
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "topographic-ripple-surface",
      "type": "registry:ui",
      "title": "Topographic Ripple Surface",
      "author": "Rishabh Bose <https://theb0se.vercel.app/>",
      "description": "Concentric contour ring background where pointer movement warps isolines with graduated spring mass and clicks emit a radial ripple.",
      "dependencies": [
        "framer-motion",
        "lucide-react",
        "clsx",
        "tailwind-merge"
      ],
      "files": [
        {
          "path": "components/ui/topographic-ripple-surface.tsx",
          "content": "\"use client\";\n\nimport React, { useRef, useState } from \"react\";\nimport {\n  motion,\n  useMotionValue,\n  useSpring,\n  useTransform,\n  useReducedMotion,\n  type MotionValue,\n} from \"framer-motion\";\nimport { Compass } from \"lucide-react\";\nimport { cn } from \"@/lib/utils\";\n\nexport interface TopographicRippleSurfaceProps {\n  /** Number of concentric contour rings. Default: 6 */\n  ringCount?: number;\n  /** Spring stiffness coefficient for contour displacement. Default: 220 */\n  stiffness?: number;\n  /** Spring damping coefficient for contour displacement. Default: 20 */\n  damping?: number;\n  /** Optional foreground content rendered over the topographic field */\n  children?: React.ReactNode;\n  className?: string;\n}\n\ninterface ContourRingProps {\n  index: number;\n  total: number;\n  offsetX: MotionValue<number>;\n  offsetY: MotionValue<number>;\n  stiffness: number;\n  damping: number;\n  pulseBoost: boolean;\n  shouldReduceMotion: boolean;\n}\n\nfunction ContourRing({\n  index,\n  total,\n  offsetX,\n  offsetY,\n  stiffness,\n  damping,\n  pulseBoost,\n  shouldReduceMotion,\n}: ContourRingProps) {\n  // Inner rings follow pointer more tightly; outer rings lag with lower factor\n  const weight = (total - index) / total;\n  const targetX = useTransform(offsetX, (v) => v * weight);\n  const targetY = useTransform(offsetY, (v) => v * weight);\n\n  const springX = useSpring(targetX, {\n    stiffness: Math.max(90, stiffness - index * 20),\n    damping: Math.max(12, damping - index),\n    mass: 0.35 + index * 0.1,\n  });\n\n  const springY = useSpring(targetY, {\n    stiffness: Math.max(90, stiffness - index * 20),\n    damping: Math.max(12, damping - index),\n    mass: 0.35 + index * 0.1,\n  });\n\n  const sizePx = 68 + index * 44;\n\n  return (\n    <motion.div\n      aria-hidden=\"true\"\n      animate={{\n        scale: pulseBoost && !shouldReduceMotion ? [1, 1.08, 1] : 1,\n      }}\n      transition={{\n        duration: 0.55,\n        delay: index * 0.04,\n        ease: \"easeOut\",\n      }}\n      style={{\n        width: sizePx,\n        height: sizePx,\n        x: shouldReduceMotion ? 0 : springX,\n        y: shouldReduceMotion ? 0 : springY,\n      }}\n      className=\"pointer-events-none absolute rounded-full border border-neutral-300/75 dark:border-[#262626]\"\n    />\n  );\n}\n\nexport function TopographicRippleSurface({\n  ringCount = 6,\n  stiffness = 220,\n  damping = 20,\n  children,\n  className,\n}: TopographicRippleSurfaceProps) {\n  const containerRef = useRef<HTMLDivElement | null>(null);\n  const shouldReduceMotion = useReducedMotion() ?? false;\n  const [pulseBoost, setPulseBoost] = useState(false);\n\n  const offsetX = useMotionValue(0);\n  const offsetY = useMotionValue(0);\n\n  const handleMouseMove = (e: React.MouseEvent<HTMLDivElement>) => {\n    if (shouldReduceMotion) return;\n    const el = containerRef.current;\n    if (!el) return;\n    const rect = el.getBoundingClientRect();\n    const centerX = rect.width / 2;\n    const centerY = rect.height / 2;\n    const dx = e.clientX - rect.left - centerX;\n    const dy = e.clientY - rect.top - centerY;\n    offsetX.set(dx * 0.42);\n    offsetY.set(dy * 0.42);\n  };\n\n  const handleMouseLeave = () => {\n    offsetX.set(0);\n    offsetY.set(0);\n  };\n\n  const triggerShockwave = () => {\n    setPulseBoost(true);\n    setTimeout(() => setPulseBoost(false), 650);\n  };\n\n  const rings = Array.from({ length: ringCount }, (_, i) => i);\n\n  return (\n    <div\n      ref={containerRef}\n      onMouseMove={handleMouseMove}\n      onMouseLeave={handleMouseLeave}\n      onClick={triggerShockwave}\n      className={cn(\n        \"relative flex min-h-[250px] w-full max-w-lg cursor-pointer select-none items-center justify-center overflow-hidden rounded-2xl border border-neutral-200 bg-white p-8 dark:border-[#222222] dark:bg-[#0A0A0A]\",\n        className\n      )}\n    >\n      {/* Concentric Topographic Isolines */}\n      {rings.map((idx) => (\n        <ContourRing\n          key={idx}\n          index={idx}\n          total={ringCount}\n          offsetX={offsetX}\n          offsetY={offsetY}\n          stiffness={stiffness}\n          damping={damping}\n          pulseBoost={pulseBoost}\n          shouldReduceMotion={shouldReduceMotion}\n        />\n      ))}\n\n      {/* Foreground Telemetry Card */}\n      <div className=\"relative z-10 text-center\">\n        {children || (\n          <div className=\"inline-flex flex-col items-center rounded-2xl border border-neutral-200/90 bg-white/90 px-5 py-3.5 shadow-sm backdrop-blur-md dark:border-[#262626] dark:bg-[#111111]/90\">\n            <span className=\"inline-flex items-center gap-1.5 font-mono text-[10px] font-semibold uppercase tracking-widest text-neutral-500 dark:text-neutral-400\">\n              <Compass className=\"h-3.5 w-3.5 text-black dark:text-white\" />\n              Topographic Isolines\n            </span>\n            <span className=\"mt-1 text-xs font-semibold text-black dark:text-white\">\n              Move cursor to warp • Click to ripple\n            </span>\n          </div>\n        )}\n      </div>\n    </div>\n  );\n}\n\nexport default TopographicRippleSurface;\n",
          "type": "registry:ui",
          "target": "components/ui/topographic-ripple-surface.tsx"
        },
        {
          "path": "lib/utils.ts",
          "content": "import { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...inputs: ClassValue[]) {\n  return twMerge(clsx(inputs));\n}\n\nexport async function copyToClipboard(text: string): Promise<boolean> {\n  if (typeof window === \"undefined\") return false;\n\n  try {\n    if (navigator.clipboard && window.isSecureContext) {\n      await navigator.clipboard.writeText(text);\n      return true;\n    }\n\n    const textArea = document.createElement(\"textarea\");\n    textArea.value = text;\n    textArea.style.position = \"fixed\";\n    textArea.style.left = \"-999999px\";\n    textArea.style.top = \"-999999px\";\n    document.body.appendChild(textArea);\n    textArea.focus();\n    textArea.select();\n    const succeeded = document.execCommand(\"copy\");\n    textArea.remove();\n    return succeeded;\n  } catch {\n    return false;\n  }\n}\n",
          "type": "registry:lib",
          "target": "lib/utils.ts"
        }
      ]
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "underwater-caustics",
      "type": "registry:ui",
      "title": "Underwater Caustics",
      "author": "Rishabh Bose <https://theb0se.vercel.app/>",
      "description": "Shimmering underwater caustic light network powered by a real-time WebGL fragment shader with subtle chromatic dispersion, diagonal volumetric God-ray sunbeams, and buoyant rising bubbles.",
      "dependencies": [
        "lucide-react",
        "clsx",
        "tailwind-merge"
      ],
      "files": [
        {
          "path": "components/ui/underwater-caustics.tsx",
          "content": "\"use client\";\n\nimport React, { useEffect, useRef, useState } from \"react\";\nimport { Sun, Sparkles, CircleDot } from \"lucide-react\";\nimport { cn } from \"@/lib/utils\";\n\nexport interface UnderwaterCausticsProps {\n  /** Base underwater hex color. Default: \"#0369A1\" */\n  waterColor?: string;\n  /** Refracted cellular caustic light network brightness (0.2 to 2.0). Default: 1.0 */\n  causticIntensity?: number;\n  /** Animation speed multiplier. Default: 1.0 */\n  speed?: number;\n  /** Number of buoyant rising bubbles with horizontal sine wobble. Default: 35 */\n  bubbleCount?: number;\n  /** Render diagonal volumetric sunbeams from the water surface. Default: true */\n  sunbeams?: boolean;\n  /** Optional foreground content */\n  children?: React.ReactNode;\n  className?: string;\n}\n\nfunction hexToRgbNormalized(hex: string): [number, number, number] {\n  const clean = hex.replace(\"#\", \"\").trim();\n  if (clean.length === 3) {\n    return [\n      (parseInt(clean[0] + clean[0], 16) || 3) / 255,\n      (parseInt(clean[1] + clean[1], 16) || 105) / 255,\n      (parseInt(clean[2] + clean[2], 16) || 161) / 255,\n    ];\n  }\n  const num = parseInt(clean, 16);\n  if (Number.isNaN(num)) return [3 / 255, 105 / 255, 161 / 255];\n  return [\n    ((num >> 16) & 255) / 255,\n    ((num >> 8) & 255) / 255,\n    (num & 255) / 255,\n  ];\n}\n\nconst VERTEX_SHADER = `\n  attribute vec2 a_position;\n  varying vec2 v_uv;\n  void main() {\n    v_uv = a_position * 0.5 + 0.5;\n    gl_Position = vec4(a_position, 0.0, 1.0);\n  }\n`;\n\nconst FRAGMENT_SHADER = `\n  precision highp float;\n  varying vec2 v_uv;\n  uniform vec2 u_resolution;\n  uniform float u_time;\n  uniform vec3 u_waterColor;\n  uniform float u_intensity;\n  uniform float u_sunbeams;\n\n  // Dual-scale domain-warped cellular wave-interference caustic solver with sharp cusps\n  float causticSolver(vec2 uv, float t) {\n    vec2 p = mod(uv * 6.28318530718, 6.28318530718) - 250.0;\n    vec2 i = vec2(p);\n    float c = 1.0;\n    float inten = 0.0046;\n\n    for (int n = 0; n < 5; n++) {\n      float fn = float(n);\n      float timeShift = t * (1.0 - (3.1 / (fn + 1.0)));\n      i = p + vec2(\n        cos(timeShift - i.x) + sin(timeShift + i.y),\n        sin(timeShift - i.y) + cos(timeShift + i.x)\n      );\n      c += 1.0 / length(vec2(\n        p.x / (sin(i.x + timeShift) / inten),\n        p.y / (cos(i.y + timeShift) / inten)\n      ));\n    }\n\n    c /= 5.0;\n    c = 1.17 - pow(c, 1.42);\n    return pow(abs(c), 8.5);\n  }\n\n  void main() {\n    vec2 aspect = vec2(u_resolution.x / max(1.0, u_resolution.y), 1.0);\n    // Perspective foreshortening + gentle underwater current refraction warp\n    vec2 swellWarp = vec2(\n      sin(v_uv.y * 5.0 + u_time * 0.7) * 0.012,\n      cos(v_uv.x * 4.5 + u_time * 0.55) * 0.012\n    );\n    vec2 uv = (v_uv + swellWarp) * aspect;\n\n    // Chromatic dispersion across RGB channels at sharp focal cusps\n    vec2 disp = vec2(0.0045, 0.0022);\n    float cR1 = causticSolver(uv * 0.92 + disp, u_time * 0.52);\n    float cG1 = causticSolver(uv * 0.92, u_time * 0.52);\n    float cB1 = causticSolver(uv * 0.92 - disp, u_time * 0.52);\n\n    // Secondary finer interference harmonic layer\n    float cG2 = causticSolver(uv * 1.65 + vec2(1.7, 2.3), -u_time * 0.38) * 0.45;\n\n    vec3 causticLight = vec3(\n      cR1 * 0.85 + cG2 * 0.6,\n      cG1 * 1.04 + cG2 * 0.95,\n      cB1 * 1.18 + cG2 * 1.1\n    ) * u_intensity;\n\n    // Marine depth gradient: sunlit turquoise surface (v_uv.y = 1) to deep abyssal floor (v_uv.y = 0)\n    vec3 abyssColor = u_waterColor * 0.12 + vec3(0.005, 0.02, 0.05);\n    vec3 midWater = u_waterColor * 0.58 + vec3(0.01, 0.09, 0.14);\n    vec3 surfaceGlow = u_waterColor * 1.05 + vec3(0.12, 0.34, 0.42);\n\n    vec3 col = mix(abyssColor, midWater, smoothstep(0.0, 0.65, v_uv.y));\n    col = mix(col, surfaceGlow, pow(v_uv.y, 2.2));\n\n    // Undulating surface shimmer near top edge\n    float surfaceRipple = pow(v_uv.y, 5.5) * (0.6 + 0.4 * sin(uv.x * 14.0 + u_time * 1.8));\n    col += vec3(0.55, 0.92, 1.0) * surfaceRipple * 0.32 * u_intensity;\n\n    // Volumetric God-ray sunbeams angling down from the undulating surface\n    if (u_sunbeams > 0.5) {\n      float slantCoord = (uv.x - (1.0 - v_uv.y) * 0.42);\n      float ray1 = 0.5 + 0.5 * sin(slantCoord * 11.0 + u_time * 0.42);\n      float ray2 = 0.5 + 0.5 * cos(slantCoord * 19.0 - u_time * 0.58 + 1.2);\n      float ray3 = 0.5 + 0.5 * sin(slantCoord * 31.0 + u_time * 0.85);\n      float combinedRays = pow(ray1 * 0.55 + ray2 * 0.3 + ray3 * 0.15, 2.8);\n      // Attenuate rays smoothly with depth\n      float depthAtten = pow(v_uv.y, 1.25) * smoothstep(0.02, 0.95, v_uv.y);\n      col += vec3(0.48, 0.92, 1.0) * combinedRays * depthAtten * 0.52 * u_intensity;\n    }\n\n    // Add refracted caustic network (brightest on the floor and near sunlit upper water)\n    float causticMask = 0.55 + 0.45 * v_uv.y;\n    col += causticLight * causticMask;\n\n    // Subtle abyssal radial vignette\n    float vig = smoothstep(1.18, 0.22, length(v_uv - vec2(0.5, 0.52)));\n    col *= 0.68 + 0.32 * vig;\n\n    gl_FragColor = vec4(clamp(col, 0.0, 1.0), 1.0);\n  }\n`;\n\ninterface Bubble {\n  x: number;\n  y: number;\n  r: number;\n  speed: number;\n  wobbleAmp: number;\n  wobbleFreq: number;\n  phase: number;\n  opacity: number;\n}\n\ninterface MarineSnow {\n  x: number;\n  y: number;\n  size: number;\n  vx: number;\n  vy: number;\n  alpha: number;\n  phase: number;\n}\n\nconst CAUSTIC_PRESETS = [\n  { name: \"Lagoon\", color: \"#0369A1\", intensity: 1.05, beams: true },\n  { name: \"Cenote\", color: \"#0D9488\", intensity: 1.25, beams: true },\n  { name: \"Abyssal\", color: \"#1E3A8A\", intensity: 0.85, beams: false },\n];\n\nexport function UnderwaterCaustics({\n  waterColor = \"#0369A1\",\n  causticIntensity = 1.0,\n  speed = 1.0,\n  bubbleCount = 35,\n  sunbeams = true,\n  children,\n  className,\n}: UnderwaterCausticsProps) {\n  const containerRef = useRef<HTMLDivElement>(null);\n  const glCanvasRef = useRef<HTMLCanvasElement>(null);\n  const bubbleCanvasRef = useRef<HTMLCanvasElement>(null);\n\n  const [liveColor, setLiveColor] = useState(waterColor);\n  const [liveIntensity, setLiveIntensity] = useState(causticIntensity);\n  const [liveSpeed, setLiveSpeed] = useState(speed);\n  const [liveBubbles, setLiveBubbles] = useState(bubbleCount);\n  const [liveSunbeams, setLiveSunbeams] = useState(sunbeams);\n\n  useEffect(() => setLiveColor(waterColor), [waterColor]);\n  useEffect(() => setLiveIntensity(causticIntensity), [causticIntensity]);\n  useEffect(() => setLiveSpeed(speed), [speed]);\n  useEffect(() => setLiveBubbles(bubbleCount), [bubbleCount]);\n  useEffect(() => setLiveSunbeams(sunbeams), [sunbeams]);\n\n  const paramsRef = useRef({\n    color: liveColor,\n    intensity: liveIntensity,\n    speed: liveSpeed,\n    bubbles: liveBubbles,\n    sunbeams: liveSunbeams,\n  });\n\n  useEffect(() => {\n    paramsRef.current = {\n      color: liveColor,\n      intensity: liveIntensity,\n      speed: liveSpeed,\n      bubbles: liveBubbles,\n      sunbeams: liveSunbeams,\n    };\n  }, [liveColor, liveIntensity, liveSpeed, liveBubbles, liveSunbeams]);\n\n  useEffect(() => {\n    const container = containerRef.current;\n    const glCanvas = glCanvasRef.current;\n    const bubbleCanvas = bubbleCanvasRef.current;\n    if (!container || !glCanvas || !bubbleCanvas) return;\n\n    const gl = glCanvas.getContext(\"webgl\", {\n      alpha: false,\n      antialias: false,\n      powerPreference: \"high-performance\",\n    });\n    const ctx2d = bubbleCanvas.getContext(\"2d\");\n\n    const compileShader = (type: number, src: string) => {\n      if (!gl) return null;\n      const shader = gl.createShader(type);\n      if (!shader) return null;\n      gl.shaderSource(shader, src);\n      gl.compileShader(shader);\n      if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {\n        gl.deleteShader(shader);\n        return null;\n      }\n      return shader;\n    };\n\n    let program: WebGLProgram | null = null;\n    let uResLoc: WebGLUniformLocation | null = null;\n    let uTimeLoc: WebGLUniformLocation | null = null;\n    let uColorLoc: WebGLUniformLocation | null = null;\n    let uIntensityLoc: WebGLUniformLocation | null = null;\n    let uSunbeamsLoc: WebGLUniformLocation | null = null;\n\n    if (gl) {\n      const vs = compileShader(gl.VERTEX_SHADER, VERTEX_SHADER);\n      const fs = compileShader(gl.FRAGMENT_SHADER, FRAGMENT_SHADER);\n      if (vs && fs) {\n        program = gl.createProgram();\n        if (program) {\n          gl.attachShader(program, vs);\n          gl.attachShader(program, fs);\n          gl.linkProgram(program);\n          gl.useProgram(program);\n\n          const buf = gl.createBuffer();\n          gl.bindBuffer(gl.ARRAY_BUFFER, buf);\n          gl.bufferData(\n            gl.ARRAY_BUFFER,\n            new Float32Array([-1, -1, 1, -1, -1, 1, -1, 1, 1, -1, 1, 1]),\n            gl.STATIC_DRAW\n          );\n          const posLoc = gl.getAttribLocation(program, \"a_position\");\n          gl.enableVertexAttribArray(posLoc);\n          gl.vertexAttribPointer(posLoc, 2, gl.FLOAT, false, 0, 0);\n\n          uResLoc = gl.getUniformLocation(program, \"u_resolution\");\n          uTimeLoc = gl.getUniformLocation(program, \"u_time\");\n          uColorLoc = gl.getUniformLocation(program, \"u_waterColor\");\n          uIntensityLoc = gl.getUniformLocation(program, \"u_intensity\");\n          uSunbeamsLoc = gl.getUniformLocation(program, \"u_sunbeams\");\n        }\n      }\n    }\n\n    let width = 1;\n    let height = 1;\n    let dpr = 1;\n    const bubbles: Bubble[] = [];\n    const snowParticles: MarineSnow[] = [];\n\n    const initMarineSnow = () => {\n      snowParticles.length = 0;\n      for (let i = 0; i < 65; i++) {\n        snowParticles.push({\n          x: Math.random() * width,\n          y: Math.random() * height,\n          size: 0.7 + Math.random() * 1.6,\n          vx: (Math.random() - 0.5) * 0.28,\n          vy: -0.12 - Math.random() * 0.25,\n          alpha: 0.18 + Math.random() * 0.45,\n          phase: Math.random() * Math.PI * 2,\n        });\n      }\n    };\n\n    const syncBubbles = (targetCount: number) => {\n      while (bubbles.length < targetCount) {\n        bubbles.push({\n          x: Math.random() * width,\n          y: Math.random() * height,\n          r: 2.2 + Math.random() * 7.5,\n          speed: 0.55 + Math.random() * 1.45,\n          wobbleAmp: 7 + Math.random() * 18,\n          wobbleFreq: 1.4 + Math.random() * 2.4,\n          phase: Math.random() * Math.PI * 2,\n          opacity: 0.3 + Math.random() * 0.5,\n        });\n      }\n      if (bubbles.length > targetCount) {\n        bubbles.length = targetCount;\n      }\n    };\n\n    const resize = () => {\n      const rect = container.getBoundingClientRect();\n      width = Math.max(1, rect.width);\n      height = Math.max(1, rect.height);\n      dpr = Math.min(window.devicePixelRatio || 1, 1.75);\n\n      glCanvas.width = Math.floor(width * dpr);\n      glCanvas.height = Math.floor(height * dpr);\n      if (gl) {\n        gl.viewport(0, 0, glCanvas.width, glCanvas.height);\n      }\n\n      bubbleCanvas.width = Math.floor(width * dpr);\n      bubbleCanvas.height = Math.floor(height * dpr);\n      if (ctx2d) {\n        ctx2d.setTransform(dpr, 0, 0, dpr, 0, 0);\n      }\n      syncBubbles(paramsRef.current.bubbles);\n      if (snowParticles.length === 0) initMarineSnow();\n    };\n\n    resize();\n    const ro = new ResizeObserver(resize);\n    ro.observe(container);\n\n    let rafId = 0;\n    let time = 0;\n\n    const render = () => {\n      const {\n        color: curColor,\n        intensity: curIntensity,\n        speed: curSpeed,\n        bubbles: curBubbles,\n        sunbeams: curSunbeams,\n      } = paramsRef.current;\n\n      time += 0.016 * curSpeed;\n      syncBubbles(curBubbles);\n\n      // 1. Render WebGL Caustic + Volumetric Sunbeam Shader\n      if (gl && program) {\n        const [r, g, b] = hexToRgbNormalized(curColor);\n        gl.useProgram(program);\n        gl.uniform2f(uResLoc, glCanvas.width, glCanvas.height);\n        gl.uniform1f(uTimeLoc, time);\n        gl.uniform3f(uColorLoc, r, g, b);\n        gl.uniform1f(uIntensityLoc, curIntensity);\n        gl.uniform1f(uSunbeamsLoc, curSunbeams ? 1.0 : 0.0);\n        gl.drawArrays(gl.TRIANGLES, 0, 6);\n      }\n\n      // 2. Render suspended marine snow & 3D Fresnel glass bubbles on overlay 2D canvas\n      if (ctx2d) {\n        ctx2d.clearRect(0, 0, width, height);\n\n        // Suspended marine snow / bioluminescent plankton micro-particles\n        for (let i = 0; i < snowParticles.length; i++) {\n          const sp = snowParticles[i];\n          sp.x += sp.vx + Math.sin(time * 0.9 + sp.phase) * 0.18;\n          sp.y += sp.vy * (0.6 + curSpeed * 0.4);\n          if (sp.y < -5) sp.y = height + 5;\n          if (sp.x < -5) sp.x = width + 5;\n          if (sp.x > width + 5) sp.x = -5;\n\n          const twinkle = 0.55 + 0.45 * Math.sin(time * 2.4 + sp.phase);\n          ctx2d.fillStyle = `rgba(210, 248, 255, ${sp.alpha * twinkle})`;\n          ctx2d.beginPath();\n          ctx2d.arc(sp.x, sp.y, sp.size, 0, Math.PI * 2);\n          ctx2d.fill();\n        }\n\n        // 3D Glass-like rising bubbles with elliptical hydrodynamic wobble & Fresnel rim\n        for (let i = 0; i < bubbles.length; i++) {\n          const b = bubbles[i];\n          b.y -= b.speed * (0.65 + curSpeed * 0.55);\n          if (b.y + b.r < -12) {\n            b.y = height + b.r + Math.random() * 30;\n            b.x = Math.random() * width;\n          }\n\n          const osc = time * b.wobbleFreq + b.phase;\n          const bx = b.x + Math.sin(osc) * b.wobbleAmp;\n          // Hydrodynamic oblate spheroid deformation as bubble rises\n          const squash = 1 + Math.sin(osc * 2.1) * 0.11;\n          const rx = b.r * squash;\n          const ry = b.r / squash;\n\n          // Internal Fresnel rim gradient (transparent core, glowing cyan/white rim)\n          const bubGrad = ctx2d.createRadialGradient(\n            bx - rx * 0.22,\n            b.y - ry * 0.22,\n            b.r * 0.1,\n            bx,\n            b.y,\n            Math.max(rx, ry)\n          );\n          bubGrad.addColorStop(0, \"rgba(255, 255, 255, 0.02)\");\n          bubGrad.addColorStop(0.68, `rgba(140, 230, 255, ${b.opacity * 0.18})`);\n          bubGrad.addColorStop(0.92, `rgba(215, 250, 255, ${b.opacity * 0.65})`);\n          bubGrad.addColorStop(1, \"rgba(255, 255, 255, 0)\");\n\n          ctx2d.save();\n          ctx2d.beginPath();\n          ctx2d.ellipse(bx, b.y, rx, ry, 0, 0, Math.PI * 2);\n          ctx2d.fillStyle = bubGrad;\n          ctx2d.fill();\n\n          // Outer refractive glass contour\n          ctx2d.strokeStyle = `rgba(225, 250, 255, ${b.opacity * 0.78})`;\n          ctx2d.lineWidth = 1.0;\n          ctx2d.stroke();\n\n          // Secondary bottom-right internal caustic reflection arc\n          ctx2d.beginPath();\n          ctx2d.ellipse(\n            bx,\n            b.y,\n            rx * 0.78,\n            ry * 0.78,\n            0,\n            Math.PI * 0.15,\n            Math.PI * 0.75\n          );\n          ctx2d.strokeStyle = `rgba(180, 245, 255, ${b.opacity * 0.55})`;\n          ctx2d.lineWidth = Math.max(0.8, b.r * 0.14);\n          ctx2d.stroke();\n\n          // Primary crisp top-left specular highlight dot\n          ctx2d.beginPath();\n          ctx2d.ellipse(\n            bx - rx * 0.36,\n            b.y - ry * 0.36,\n            Math.max(0.8, rx * 0.26),\n            Math.max(0.6, ry * 0.18),\n            -Math.PI * 0.25,\n            0,\n            Math.PI * 2\n          );\n          ctx2d.fillStyle = `rgba(255, 255, 255, ${Math.min(0.98, b.opacity * 1.55)})`;\n          ctx2d.fill();\n          ctx2d.restore();\n        }\n      }\n\n      rafId = requestAnimationFrame(render);\n    };\n\n    rafId = requestAnimationFrame(render);\n\n    return () => {\n      cancelAnimationFrame(rafId);\n      ro.disconnect();\n    };\n  }, []);\n\n  return (\n    <div\n      ref={containerRef}\n      data-fullscreen-scroll\n      className={cn(\n        \"relative flex min-h-[520px] w-full flex-col justify-between overflow-hidden rounded-2xl border border-white/10 bg-[#02182B] p-6 text-white shadow-2xl\",\n        className\n      )}\n    >\n      <canvas\n        ref={glCanvasRef}\n        aria-hidden=\"true\"\n        className=\"pointer-events-none absolute inset-0 h-full w-full\"\n      />\n      <canvas\n        ref={bubbleCanvasRef}\n        aria-hidden=\"true\"\n        className=\"pointer-events-none absolute inset-0 h-full w-full\"\n      />\n\n      {children && (\n        <div className=\"relative z-10 flex min-h-[520px] w-full flex-col\">\n          {children}\n        </div>\n      )}\n    </div>\n  );\n}\n\nexport default UnderwaterCaustics;\n",
          "type": "registry:ui",
          "target": "components/ui/underwater-caustics.tsx"
        },
        {
          "path": "lib/utils.ts",
          "content": "import { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...inputs: ClassValue[]) {\n  return twMerge(clsx(inputs));\n}\n\nexport async function copyToClipboard(text: string): Promise<boolean> {\n  if (typeof window === \"undefined\") return false;\n\n  try {\n    if (navigator.clipboard && window.isSecureContext) {\n      await navigator.clipboard.writeText(text);\n      return true;\n    }\n\n    const textArea = document.createElement(\"textarea\");\n    textArea.value = text;\n    textArea.style.position = \"fixed\";\n    textArea.style.left = \"-999999px\";\n    textArea.style.top = \"-999999px\";\n    document.body.appendChild(textArea);\n    textArea.focus();\n    textArea.select();\n    const succeeded = document.execCommand(\"copy\");\n    textArea.remove();\n    return succeeded;\n  } catch {\n    return false;\n  }\n}\n",
          "type": "registry:lib",
          "target": "lib/utils.ts"
        }
      ]
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "variable-proximity-text",
      "type": "registry:ui",
      "title": "Variable Proximity Text",
      "author": "Rishabh Bose <https://theb0se.vercel.app/>",
      "description": "Interactive kinetic typography where each glyph interpolates vertical lift, scale, and contrast based on real-time 2D cursor proximity.",
      "dependencies": [
        "framer-motion",
        "clsx",
        "tailwind-merge"
      ],
      "files": [
        {
          "path": "components/ui/variable-proximity-text.tsx",
          "content": "\"use client\";\n\nimport React, { useRef } from \"react\";\nimport {\n  motion,\n  useMotionValue,\n  useSpring,\n  useTransform,\n  useReducedMotion,\n  type MotionValue,\n} from \"framer-motion\";\nimport { cn } from \"@/lib/utils\";\n\nexport interface VariableProximityTextProps {\n  /** Text string to split into proximity-reactive kinetic glyphs. */\n  text?: string;\n  /** Pointer influence radius in pixels. Default: 120 */\n  radius?: number;\n  /** Peak vertical displacement in pixels at zero pointer distance. Default: -10 */\n  maxLift?: number;\n  /** Peak glyph scale factor at zero pointer distance. Default: 1.22 */\n  maxScale?: number;\n  /** Hooke's Law spring stiffness coefficient. Default: 300 */\n  stiffness?: number;\n  /** Spring damping coefficient. Default: 22 */\n  damping?: number;\n  className?: string;\n}\n\ninterface ProximityGlyphProps {\n  char: string;\n  mouseX: MotionValue<number>;\n  mouseY: MotionValue<number>;\n  radius: number;\n  maxLift: number;\n  maxScale: number;\n  stiffness: number;\n  damping: number;\n  shouldReduceMotion: boolean;\n}\n\nfunction ProximityGlyph({\n  char,\n  mouseX,\n  mouseY,\n  radius,\n  maxLift,\n  maxScale,\n  stiffness,\n  damping,\n  shouldReduceMotion,\n}: ProximityGlyphProps) {\n  const glyphRef = useRef<HTMLSpanElement | null>(null);\n\n  const proximityFactor = useTransform([mouseX, mouseY], ([x, y]) => {\n    const el = glyphRef.current;\n    if (!el || x === -Infinity || y === -Infinity) return 0;\n    const rect = el.getBoundingClientRect();\n    const centerX = rect.left + rect.width / 2;\n    const centerY = rect.top + rect.height / 2;\n    const dx = (x as number) - centerX;\n    const dy = (y as number) - centerY;\n    const dist = Math.sqrt(dx * dx + dy * dy);\n    if (dist >= radius) return 0;\n    return 1 - dist / radius;\n  });\n\n  const targetY = useTransform(proximityFactor, [0, 1], [0, maxLift]);\n  const targetScale = useTransform(proximityFactor, [0, 1], [1, maxScale]);\n  const targetOpacity = useTransform(proximityFactor, [0, 1], [0.68, 1]);\n\n  const springY = useSpring(targetY, { stiffness, damping, mass: 0.35 });\n  const springScale = useSpring(targetScale, { stiffness, damping, mass: 0.35 });\n\n  if (char === \" \") {\n    return <span className=\"inline-block w-[0.32em]\">&nbsp;</span>;\n  }\n\n  return (\n    <motion.span\n      ref={glyphRef}\n      aria-hidden=\"true\"\n      style={{\n        y: shouldReduceMotion ? 0 : springY,\n        scale: shouldReduceMotion ? 1 : springScale,\n        opacity: shouldReduceMotion ? 1 : targetOpacity,\n      }}\n      className=\"inline-block origin-bottom select-none will-change-transform\"\n    >\n      {char}\n    </motion.span>\n  );\n}\n\nexport function VariableProximityText({\n  text = \"Kinetic typography engineered with spring physics.\",\n  radius = 120,\n  maxLift = -10,\n  maxScale = 1.22,\n  stiffness = 300,\n  damping = 22,\n  className,\n}: VariableProximityTextProps) {\n  const shouldReduceMotion = useReducedMotion() ?? false;\n  const mouseX = useMotionValue(-Infinity);\n  const mouseY = useMotionValue(-Infinity);\n\n  const words = text.split(\" \");\n\n  return (\n    <div\n      onMouseMove={(e) => {\n        if (!shouldReduceMotion) {\n          mouseX.set(e.clientX);\n          mouseY.set(e.clientY);\n        }\n      }}\n      onMouseLeave={() => {\n        mouseX.set(-Infinity);\n        mouseY.set(-Infinity);\n      }}\n      className={cn(\n        \"relative cursor-default rounded-2xl border border-neutral-200 bg-white px-6 py-8 text-center dark:border-[#222222] dark:bg-[#0A0A0A]\",\n        className\n      )}\n    >\n      {/* Screen-reader accessible uninterrupted string */}\n      <span className=\"sr-only\">{text}</span>\n\n      <p\n        aria-hidden=\"true\"\n        className=\"text-xl font-semibold tracking-tight text-black sm:text-2xl dark:text-white\"\n      >\n        {words.map((word, wordIdx) => (\n          <span key={wordIdx} className=\"inline-block whitespace-nowrap\">\n            {word.split(\"\").map((char, charIdx) => (\n              <ProximityGlyph\n                key={`${wordIdx}-${charIdx}`}\n                char={char}\n                mouseX={mouseX}\n                mouseY={mouseY}\n                radius={radius}\n                maxLift={maxLift}\n                maxScale={maxScale}\n                stiffness={stiffness}\n                damping={damping}\n                shouldReduceMotion={shouldReduceMotion}\n              />\n            ))}\n            {wordIdx < words.length - 1 && (\n              <span className=\"inline-block w-[0.32em]\">&nbsp;</span>\n            )}\n          </span>\n        ))}\n      </p>\n\n      <div className=\"mt-3 text-[11px] font-medium uppercase tracking-widest text-neutral-400 dark:text-neutral-500\">\n        Sweep cursor across glyphs • Radius {radius}px\n      </div>\n    </div>\n  );\n}\n\nexport default VariableProximityText;\n",
          "type": "registry:ui",
          "target": "components/ui/variable-proximity-text.tsx"
        },
        {
          "path": "lib/utils.ts",
          "content": "import { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...inputs: ClassValue[]) {\n  return twMerge(clsx(inputs));\n}\n\nexport async function copyToClipboard(text: string): Promise<boolean> {\n  if (typeof window === \"undefined\") return false;\n\n  try {\n    if (navigator.clipboard && window.isSecureContext) {\n      await navigator.clipboard.writeText(text);\n      return true;\n    }\n\n    const textArea = document.createElement(\"textarea\");\n    textArea.value = text;\n    textArea.style.position = \"fixed\";\n    textArea.style.left = \"-999999px\";\n    textArea.style.top = \"-999999px\";\n    document.body.appendChild(textArea);\n    textArea.focus();\n    textArea.select();\n    const succeeded = document.execCommand(\"copy\");\n    textArea.remove();\n    return succeeded;\n  } catch {\n    return false;\n  }\n}\n",
          "type": "registry:lib",
          "target": "lib/utils.ts"
        }
      ]
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "volcano-embers",
      "type": "registry:ui",
      "title": "Volcano Embers",
      "author": "Rishabh Bose <https://theb0se.vercel.app/>",
      "description": "Rising volcanic embers and charred thermal ash on Canvas 2D with molten caldera horizon glow, velocity-aligned incandescent spark trails, and turbulent updraft vortices.",
      "dependencies": [
        "lucide-react",
        "clsx",
        "tailwind-merge"
      ],
      "files": [
        {
          "path": "components/ui/volcano-embers.tsx",
          "content": "\"use client\";\n\nimport React, { useEffect, useRef, useState } from \"react\";\nimport { Flame, Wind, ArrowUp, Sparkles, RotateCcw } from \"lucide-react\";\nimport { cn } from \"@/lib/utils\";\n\nexport interface VolcanoEmbersProps {\n  /** Total number of rising incandescent embers and thermal sparks */\n  emberCount?: number;\n  /** Vertical thermal updraft velocity multiplier */\n  updraftSpeed?: number;\n  /** Horizontal curl/vortex turbulence intensity */\n  turbulence?: number;\n  /** Primary ember glow color in hex */\n  emberColor?: string;\n  /** Molten magma horizon glow intensity at the bottom (0 to 1.5) */\n  coreGlow?: number;\n  /** Optional foreground content */\n  children?: React.ReactNode;\n  /** Additional container classes */\n  className?: string;\n}\n\ninterface EmberParticle {\n  x: number;\n  y: number;\n  vx: number;\n  vy: number;\n  size: number;\n  life: number;\n  maxLife: number;\n  flickerPhase: number;\n  flickerSpeed: number;\n  turbulenceSeed: number;\n  /** 0 = charred ash flake, 1 = sharp curved long-exposure spark streak, 2 = foreground bokeh ember */\n  plane: 0 | 1 | 2;\n  history: { x: number; y: number }[];\n}\n\ninterface SmokePlume {\n  x: number;\n  y: number;\n  radius: number;\n  vx: number;\n  vy: number;\n  life: number;\n  maxLife: number;\n  seed: number;\n}\n\nfunction hexToRgb(hex: string): { r: number; g: number; b: number } {\n  const clean = hex.replace(\"#\", \"\").trim();\n  const full =\n    clean.length === 3\n      ? clean\n          .split(\"\")\n          .map((c) => c + c)\n          .join(\"\")\n      : clean;\n  const num = parseInt(full, 16);\n  if (Number.isNaN(num)) return { r: 255, g: 107, b: 26 };\n  return {\n    r: (num >> 16) & 255,\n    g: (num >> 8) & 255,\n    b: num & 255,\n  };\n}\n\n// 2D divergence-free curl-like velocity field for coherent thermal vortex eddies\nfunction sampleCurlVelocity(\n  x: number,\n  y: number,\n  t: number,\n  seed: number\n): { cx: number; cy: number } {\n  const sx = x * 0.0065;\n  const sy = y * 0.0065;\n  // Stream function potential psi(x, y, t) derivatives\n  const dPsiDy =\n    Math.cos(sy * 1.4 - t * 1.3 + seed * 0.2) * 1.35 +\n    Math.sin(sx * 2.1 + sy * 1.9 + t * 0.9) * 0.85 +\n    Math.cos(sy * 3.4 + sx * 1.2 - t * 1.8) * 0.45;\n  const dPsiDx =\n    -Math.sin(sx * 1.4 + t * 1.1 + seed * 0.2) * 1.1 +\n    Math.cos(sx * 2.1 + sy * 1.9 + t * 0.9) * 0.65;\n  return { cx: dPsiDy, cy: -dPsiDx * 0.35 };\n}\n\nconst EMBER_PRESETS = [\n  { label: \"Magma Orange\", hex: \"#FF6B1A\" },\n  { label: \"Solar Gold\", hex: \"#FACC15\" },\n  { label: \"Crimson Forge\", hex: \"#F43F5E\" },\n  { label: \"Arcane Blue\", hex: \"#38BDF8\" },\n];\n\nexport function VolcanoEmbers({\n  emberCount = 110,\n  updraftSpeed = 1.2,\n  turbulence = 1.0,\n  emberColor = \"#FF6B1A\",\n  coreGlow = 0.8,\n  children,\n  className,\n}: VolcanoEmbersProps) {\n  const containerRef = useRef<HTMLDivElement>(null);\n  const canvasRef = useRef<HTMLCanvasElement>(null);\n\n  const [simCount, setSimCount] = useState(emberCount);\n  const [simUpdraft, setSimUpdraft] = useState(updraftSpeed);\n  const [simTurbulence, setSimTurbulence] = useState(turbulence);\n  const [simColor, setSimColor] = useState(emberColor);\n  const [simGlow, setSimGlow] = useState(coreGlow);\n\n  useEffect(() => setSimCount(emberCount), [emberCount]);\n  useEffect(() => setSimUpdraft(updraftSpeed), [updraftSpeed]);\n  useEffect(() => setSimTurbulence(turbulence), [turbulence]);\n  useEffect(() => setSimColor(emberColor), [emberColor]);\n  useEffect(() => setSimGlow(coreGlow), [coreGlow]);\n\n  const pointerRef = useRef<{ x: number; y: number; active: boolean }>({\n    x: 0,\n    y: 0,\n    active: false,\n  });\n\n  useEffect(() => {\n    const container = containerRef.current;\n    const canvas = canvasRef.current;\n    if (!container || !canvas) return;\n    const ctx = canvas.getContext(\"2d\");\n    if (!ctx) return;\n\n    let width = container.clientWidth || 800;\n    let height = container.clientHeight || 520;\n    let dpr = Math.min(window.devicePixelRatio || 1, 2);\n\n    const createSmokePlume = (w: number, h: number, randomY = false): SmokePlume => {\n      const maxLife = 220 + Math.random() * 140;\n      return {\n        x: w * (0.1 + Math.random() * 0.8),\n        y: randomY ? Math.random() * h : h + 40,\n        radius: 65 + Math.random() * 75,\n        vx: (Math.random() - 0.5) * 0.4,\n        vy: -(0.35 + Math.random() * 0.45),\n        life: randomY ? Math.random() * maxLife : 0,\n        maxLife,\n        seed: Math.random() * 10,\n      };\n    };\n\n    const createEmber = (\n      w: number,\n      h: number,\n      idx: number,\n      randomY = false\n    ): EmberParticle => {\n      const ratio = (idx * 0.61803398875) % 1;\n      let plane: 0 | 1 | 2 = 1;\n      let size = 2.0;\n\n      if (ratio < 0.2) {\n        // Charred floating thermal ash flake\n        plane = 0;\n        size = 1.4 + Math.random() * 2.0;\n      } else if (ratio < 0.88) {\n        // Sharp mid-ground incandescent long-exposure spark\n        plane = 1;\n        size = 1.4 + Math.random() * 2.2;\n      } else {\n        // Large out-of-focus foreground bokeh ember\n        plane = 2;\n        size = 14 + Math.random() * 16;\n      }\n\n      const maxLife = 120 + Math.random() * 150;\n      const startX = Math.random() * w;\n      const startY = randomY ? Math.random() * h : h + 8 + Math.random() * 30;\n\n      return {\n        x: startX,\n        y: startY,\n        vx: (Math.random() - 0.5) * 1.2,\n        vy:\n          plane === 2\n            ? -(1.5 + Math.random() * 2.2)\n            : -(1.2 + Math.random() * 2.5),\n        size,\n        life: randomY ? Math.random() * maxLife : 0,\n        maxLife,\n        flickerPhase: Math.random() * Math.PI * 2,\n        flickerSpeed: 0.09 + Math.random() * 0.16,\n        turbulenceSeed: Math.random() * 30,\n        plane,\n        history: [{ x: startX, y: startY }],\n      };\n    };\n\n    let plumes: SmokePlume[] = Array.from({ length: 18 }, () =>\n      createSmokePlume(width, height, true)\n    );\n    let particles: EmberParticle[] = Array.from({ length: simCount }, (_, i) =>\n      createEmber(width, height, i, true)\n    );\n\n    const buildCalderaRidge = (w: number, h: number) => {\n      const pts: { x: number; y: number }[] = [];\n      const steps = 40;\n      for (let i = 0; i <= steps; i++) {\n        const u = i / steps;\n        // Jagged volcanic crater rim dipping in the center caldera\n        const craterDip = Math.exp(-Math.pow((u - 0.5) * 3.2, 2)) * 18;\n        const jagged =\n          Math.sin(i * 1.9) * 6 +\n          Math.cos(i * 4.3) * 4 +\n          Math.sin(i * 9.1) * 2.2;\n        pts.push({\n          x: u * w,\n          y: h - 22 + craterDip + jagged,\n        });\n      }\n      return pts;\n    };\n\n    let calderaPts = buildCalderaRidge(width, height);\n\n    const updateSize = () => {\n      if (!container || !canvas) return;\n      width = container.clientWidth || 800;\n      height = container.clientHeight || 520;\n      dpr = Math.min(window.devicePixelRatio || 1, 2);\n      canvas.width = Math.floor(width * dpr);\n      canvas.height = Math.floor(height * dpr);\n      ctx.setTransform(dpr, 0, 0, dpr, 0, 0);\n      calderaPts = buildCalderaRidge(width, height);\n    };\n\n    updateSize();\n    const observer = new ResizeObserver(updateSize);\n    observer.observe(container);\n\n    let rafId = 0;\n    let time = 0;\n    const rgb = hexToRgb(simColor);\n\n    const render = () => {\n      time += 0.016;\n\n      if (particles.length < simCount) {\n        while (particles.length < simCount) {\n          particles.push(\n            createEmber(width, height, particles.length, true)\n          );\n        }\n      } else if (particles.length > simCount) {\n        particles.length = simCount;\n      }\n\n      // Volcanic smoky night sky gradient\n      const bgGrad = ctx.createLinearGradient(0, 0, 0, height);\n      bgGrad.addColorStop(0, \"#040305\");\n      bgGrad.addColorStop(0.52, \"#0d070a\");\n      bgGrad.addColorStop(0.84, \"#1e0c08\");\n      bgGrad.addColorStop(1, \"#331206\");\n      ctx.fillStyle = bgGrad;\n      ctx.fillRect(0, 0, width, height);\n\n      // Billowing volcanic smoke & ash plumes illuminated from below by the caldera\n      for (let i = 0; i < plumes.length; i++) {\n        const pl = plumes[i];\n        pl.life++;\n        if (pl.life >= pl.maxLife || pl.y < -pl.radius) {\n          plumes[i] = createSmokePlume(width, height, false);\n          continue;\n        }\n        const pRatio = pl.life / pl.maxLife;\n        pl.x +=\n          pl.vx +\n          Math.sin(time * 0.5 + pl.seed) * 0.35 * simTurbulence;\n        pl.y += pl.vy * simUpdraft;\n\n        const curR = pl.radius * (0.75 + pRatio * 0.85);\n        const envAlpha = Math.sin(pRatio * Math.PI) * 0.22;\n        const bottomProximity = Math.max(0, (pl.y / height));\n\n        const sGrad = ctx.createRadialGradient(\n          pl.x,\n          pl.y + curR * 0.25,\n          curR * 0.1,\n          pl.x,\n          pl.y,\n          curR\n        );\n        // Under-lit warm magma scatter at the base of the smoke cloud, dark charcoal at top\n        const litR = Math.round(18 + bottomProximity * rgb.r * 0.35 * simGlow);\n        const litG = Math.round(12 + bottomProximity * rgb.g * 0.28 * simGlow);\n        const litB = Math.round(16 + bottomProximity * rgb.b * 0.22 * simGlow);\n\n        sGrad.addColorStop(0, `rgba(${litR}, ${litG}, ${litB}, ${envAlpha.toFixed(3)})`);\n        sGrad.addColorStop(0.6, `rgba(14, 10, 14, ${(envAlpha * 0.65).toFixed(3)})`);\n        sGrad.addColorStop(1, \"rgba(8, 6, 10, 0)\");\n\n        ctx.fillStyle = sGrad;\n        ctx.beginPath();\n        ctx.arc(pl.x, pl.y, curR, 0, Math.PI * 2);\n        ctx.fill();\n      }\n\n      // Molten caldera horizon glow at the bottom\n      const pulse = 0.92 + Math.sin(time * 2.4) * 0.08;\n      const horizonGlow = ctx.createRadialGradient(\n        width * 0.5,\n        height * 1.04,\n        8,\n        width * 0.5,\n        height * 1.01,\n        width * 0.72\n      );\n      const glowAlpha = Math.min(1, simGlow * 0.62 * pulse);\n      horizonGlow.addColorStop(\n        0,\n        `rgba(255, 248, 200, ${(glowAlpha * 0.92).toFixed(3)})`\n      );\n      horizonGlow.addColorStop(\n        0.26,\n        `rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, ${glowAlpha.toFixed(3)})`\n      );\n      horizonGlow.addColorStop(\n        0.62,\n        `rgba(${Math.floor(rgb.r * 0.65)}, ${Math.floor(rgb.g * 0.22)}, 8, ${(\n          glowAlpha * 0.38\n        ).toFixed(3)})`\n      );\n      horizonGlow.addColorStop(1, \"rgba(0, 0, 0, 0)\");\n\n      ctx.fillStyle = horizonGlow;\n      ctx.fillRect(0, 0, width, height);\n\n      // Update & draw embers across depth planes\n      const updateAndDrawEmber = (p: EmberParticle, idx: number) => {\n        p.life++;\n        p.flickerPhase += p.flickerSpeed;\n\n        const lifeRatio = p.life / p.maxLife;\n        if (lifeRatio >= 1 || p.y < -50) {\n          particles[idx] = createEmber(width, height, idx, false);\n          return;\n        }\n\n        // Coherent curl-noise vortex eddy turbulence\n        const { cx, cy } = sampleCurlVelocity(\n          p.x,\n          p.y,\n          time,\n          p.turbulenceSeed\n        );\n        p.vx += (cx * 1.35 * simTurbulence - p.vx) * 0.065;\n        const vyTarget = (p.vy + cy * 0.45 * simTurbulence) * simUpdraft;\n\n        // Pointer thermal updraft deflection\n        if (pointerRef.current.active) {\n          const dx = p.x - pointerRef.current.x;\n          const dy = p.y - pointerRef.current.y;\n          const distSq = dx * dx + dy * dy;\n          if (distSq < 28000 && distSq > 16) {\n            const dist = Math.sqrt(distSq);\n            const push = (1 - dist / 167) * 0.42;\n            p.vx += (dx / dist) * push;\n          }\n        }\n\n        p.x += p.vx;\n        p.y += vyTarget;\n\n        if (p.x < -30) {\n          p.x = width + 30;\n          p.history = [{ x: p.x, y: p.y }];\n        } else if (p.x > width + 30) {\n          p.x = -30;\n          p.history = [{ x: p.x, y: p.y }];\n        } else {\n          p.history.unshift({ x: p.x, y: p.y });\n          if (p.history.length > 7) p.history.pop();\n        }\n\n        const coolFactor = Math.max(0, 1 - Math.pow(lifeRatio, 1.4));\n        const flicker = 0.68 + 0.32 * Math.sin(p.flickerPhase);\n        const radius = p.size * (0.35 + 0.65 * coolFactor);\n\n        if (p.plane === 0) {\n          // Floating dark charred thermal ash flake\n          ctx.fillStyle = `rgba(148, 163, 184, ${(\n            0.3 *\n            coolFactor *\n            flicker\n          ).toFixed(3)})`;\n          ctx.beginPath();\n          ctx.arc(p.x, p.y, radius, 0, Math.PI * 2);\n          ctx.fill();\n        } else if (p.plane === 1) {\n          // Curved long-exposure incandescent light streak with white-hot head & orange-red tail\n          const alpha = coolFactor * flicker;\n          if (p.history.length >= 2) {\n            const tailPt = p.history[p.history.length - 1];\n            const streakGrad = ctx.createLinearGradient(\n              p.x,\n              p.y,\n              tailPt.x,\n              tailPt.y\n            );\n            streakGrad.addColorStop(\n              0,\n              `rgba(255, 253, 235, ${Math.min(1, alpha * 1.1).toFixed(3)})`\n            );\n            streakGrad.addColorStop(\n              0.38,\n              `rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, ${(alpha * 0.88).toFixed(3)})`\n            );\n            streakGrad.addColorStop(\n              1,\n              `rgba(${Math.floor(rgb.r * 0.7)}, 20, 5, 0)`\n            );\n\n            ctx.strokeStyle = streakGrad;\n            ctx.lineWidth = radius * 1.35;\n            ctx.lineCap = \"round\";\n            ctx.lineJoin = \"round\";\n            ctx.beginPath();\n            ctx.moveTo(p.history[0].x, p.history[0].y);\n            for (let hIdx = 1; hIdx < p.history.length; hIdx++) {\n              ctx.lineTo(p.history[hIdx].x, p.history[hIdx].y);\n            }\n            ctx.stroke();\n          }\n\n          // Hot incandescent core bloom\n          const haloR = radius * 4.2;\n          const eGrad = ctx.createRadialGradient(\n            p.x,\n            p.y,\n            0,\n            p.x,\n            p.y,\n            haloR\n          );\n          eGrad.addColorStop(\n            0,\n            `rgba(255, 255, 240, ${(alpha * 0.96).toFixed(3)})`\n          );\n          eGrad.addColorStop(\n            0.32,\n            `rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, ${(alpha * 0.72).toFixed(3)})`\n          );\n          eGrad.addColorStop(1, `rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, 0)`);\n\n          ctx.fillStyle = eGrad;\n          ctx.beginPath();\n          ctx.arc(p.x, p.y, haloR, 0, Math.PI * 2);\n          ctx.fill();\n        } else {\n          // Out-of-focus foreground optical bokeh ember disc\n          const bokehAlpha = coolFactor * flicker * 0.22;\n          const bGrad = ctx.createRadialGradient(\n            p.x,\n            p.y,\n            radius * 0.1,\n            p.x,\n            p.y,\n            radius\n          );\n          bGrad.addColorStop(\n            0,\n            `rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, ${(bokehAlpha * 0.55).toFixed(\n              3\n            )})`\n          );\n          bGrad.addColorStop(\n            0.78,\n            `rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, ${(bokehAlpha * 0.92).toFixed(\n              3\n            )})`\n          );\n          bGrad.addColorStop(\n            0.92,\n            `rgba(255, 235, 190, ${(bokehAlpha * 1.15).toFixed(3)})`\n          );\n          bGrad.addColorStop(1, `rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, 0)`);\n\n          ctx.fillStyle = bGrad;\n          ctx.beginPath();\n          ctx.arc(p.x, p.y, radius, 0, Math.PI * 2);\n          ctx.fill();\n        }\n      };\n\n      // Render ash & sharp mid-ground spark streaks\n      ctx.save();\n      ctx.globalCompositeOperation = \"screen\";\n      for (let i = 0; i < particles.length; i++) {\n        if (particles[i].plane !== 2) {\n          updateAndDrawEmber(particles[i], i);\n        }\n      }\n      ctx.restore();\n\n      // Jagged volcanic basalt caldera rim along the bottom edge with glowing magma rim\n      if (calderaPts.length > 0) {\n        ctx.save();\n        ctx.strokeStyle = `rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, ${(\n          0.45 * simGlow\n        ).toFixed(3)})`;\n        ctx.lineWidth = 2.2;\n        ctx.beginPath();\n        ctx.moveTo(calderaPts[0].x, calderaPts[0].y);\n        for (const pt of calderaPts) {\n          ctx.lineTo(pt.x, pt.y);\n        }\n        ctx.stroke();\n\n        ctx.fillStyle = \"#060304\";\n        ctx.beginPath();\n        ctx.moveTo(0, height);\n        for (const pt of calderaPts) {\n          ctx.lineTo(pt.x, pt.y);\n        }\n        ctx.lineTo(width, height);\n        ctx.closePath();\n        ctx.fill();\n        ctx.restore();\n      }\n\n      // Render large out-of-focus foreground bokeh embers in front of the caldera rim\n      ctx.save();\n      ctx.globalCompositeOperation = \"screen\";\n      for (let i = 0; i < particles.length; i++) {\n        if (particles[i].plane === 2) {\n          updateAndDrawEmber(particles[i], i);\n        }\n      }\n      ctx.restore();\n\n      rafId = requestAnimationFrame(render);\n    };\n\n    rafId = requestAnimationFrame(render);\n\n    return () => {\n      cancelAnimationFrame(rafId);\n      observer.disconnect();\n    };\n  }, [simCount, simUpdraft, simTurbulence, simColor, simGlow]);\n\n  const handlePointerMove = (e: React.PointerEvent<HTMLDivElement>) => {\n    const rect = e.currentTarget.getBoundingClientRect();\n    pointerRef.current = {\n      x: e.clientX - rect.left,\n      y: e.clientY - rect.top,\n      active: true,\n    };\n  };\n\n  const handlePointerLeave = () => {\n    pointerRef.current.active = false;\n  };\n\n  const resetDefaults = () => {\n    setSimCount(emberCount);\n    setSimUpdraft(updraftSpeed);\n    setSimTurbulence(turbulence);\n    setSimColor(emberColor);\n    setSimGlow(coreGlow);\n  };\n\n  return (\n    <div\n      ref={containerRef}\n      data-fullscreen-scroll\n      onPointerMove={handlePointerMove}\n      onPointerLeave={handlePointerLeave}\n      className={cn(\n        \"relative w-full min-h-[520px] overflow-hidden rounded-2xl bg-[#040305] text-slate-100 select-none\",\n        className\n      )}\n    >\n      <canvas\n        ref={canvasRef}\n        className=\"pointer-events-none absolute inset-0 h-full w-full\"\n      />\n\n      {children && (\n        <div className=\"relative z-10 flex min-h-[520px] w-full flex-col\">\n          {children}\n        </div>\n      )}\n    </div>\n  );\n}\n\nexport default VolcanoEmbers;\n",
          "type": "registry:ui",
          "target": "components/ui/volcano-embers.tsx"
        },
        {
          "path": "lib/utils.ts",
          "content": "import { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...inputs: ClassValue[]) {\n  return twMerge(clsx(inputs));\n}\n\nexport async function copyToClipboard(text: string): Promise<boolean> {\n  if (typeof window === \"undefined\") return false;\n\n  try {\n    if (navigator.clipboard && window.isSecureContext) {\n      await navigator.clipboard.writeText(text);\n      return true;\n    }\n\n    const textArea = document.createElement(\"textarea\");\n    textArea.value = text;\n    textArea.style.position = \"fixed\";\n    textArea.style.left = \"-999999px\";\n    textArea.style.top = \"-999999px\";\n    document.body.appendChild(textArea);\n    textArea.focus();\n    textArea.select();\n    const succeeded = document.execCommand(\"copy\");\n    textArea.remove();\n    return succeeded;\n  } catch {\n    return false;\n  }\n}\n",
          "type": "registry:lib",
          "target": "lib/utils.ts"
        }
      ]
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "warp-speed",
      "type": "registry:ui",
      "title": "Warp Speed",
      "author": "Rishabh Bose <https://theb0se.vercel.app/>",
      "description": "3D hyperspace starfield using perspective projection (`screenX = x / z`, `screenY = y / z`), delta-time streak rendering, a cursor-following vanishing point, and a warp jump accelerator.",
      "dependencies": [
        "lucide-react",
        "clsx",
        "tailwind-merge"
      ],
      "files": [
        {
          "path": "components/ui/warp-speed.tsx",
          "content": "\"use client\";\n\nimport React, { useEffect, useRef, useState } from \"react\";\nimport { Zap } from \"lucide-react\";\nimport { cn } from \"@/lib/utils\";\n\nexport interface WarpSpeedProps {\n  /** Base forward velocity. Default: 180 */\n  speed?: number;\n  /** Number of 3D stars in the tunnel. Default: 320 */\n  starCount?: number;\n  /** Streak tail multiplier. Default: 1.4 */\n  streakLength?: number;\n  /** Engage hyperspace warp jump (ramps speed up 5x). Default: false */\n  warp?: boolean;\n  /** Normalized vanishing point { x: 0..1, y: 0..1 }. Default: { x: 0.5, y: 0.5 } */\n  center?: { x: number; y: number };\n  /** Allow vanishing point to follow the cursor. Default: true */\n  followCursor?: boolean;\n  /** Optional foreground content */\n  children?: React.ReactNode;\n  className?: string;\n}\n\ninterface Star3D {\n  x: number;\n  y: number;\n  z: number;\n  pz: number;\n}\n\nexport function WarpSpeed({\n  speed = 180,\n  starCount = 320,\n  streakLength = 1.4,\n  warp = false,\n  center = { x: 0.5, y: 0.5 },\n  followCursor = true,\n  children,\n  className,\n}: WarpSpeedProps) {\n  const canvasRef = useRef<HTMLCanvasElement>(null);\n  const [isWarping, setIsWarping] = useState(warp);\n  const vanishingRef = useRef({\n    x: center.x,\n    y: center.y,\n    targetX: center.x,\n    targetY: center.y,\n  });\n\n  useEffect(() => {\n    setIsWarping(warp);\n  }, [warp]);\n\n  useEffect(() => {\n    vanishingRef.current.targetX = center.x;\n    vanishingRef.current.targetY = center.y;\n  }, [center.x, center.y]);\n\n  useEffect(() => {\n    const canvas = canvasRef.current;\n    if (!canvas) return;\n    const ctx = canvas.getContext(\"2d\");\n    if (!ctx) return;\n\n    let rafId: number;\n    let width = (canvas.width = canvas.offsetWidth || 600);\n    let height = (canvas.height = canvas.offsetHeight || 360);\n    const maxDepth = 1000;\n\n    const createStar = (): Star3D => {\n      const z = Math.random() * maxDepth + 1;\n      return {\n        x: (Math.random() - 0.5) * width * 2.2,\n        y: (Math.random() - 0.5) * height * 2.2,\n        z,\n        pz: z,\n      };\n    };\n\n    const stars: Star3D[] = Array.from({ length: starCount }, createStar);\n    let currentVelocity = speed;\n\n    const handleResize = () => {\n      if (!canvas) return;\n      width = canvas.width = canvas.offsetWidth || 600;\n      height = canvas.height = canvas.offsetHeight || 360;\n    };\n\n    window.addEventListener(\"resize\", handleResize);\n\n    let last = performance.now();\n    const render = (now: number) => {\n      const dt = Math.min(0.05, (now - last) / 1000);\n      last = now;\n\n      // Smoothly ramp velocity up or down for warp jump\n      const targetVelocity = isWarping ? speed * 5.2 : speed;\n      currentVelocity += (targetVelocity - currentVelocity) * 0.08;\n\n      // Smoothly interpolate vanishing point\n      vanishingRef.current.x +=\n        (vanishingRef.current.targetX - vanishingRef.current.x) * 0.08;\n      vanishingRef.current.y +=\n        (vanishingRef.current.targetY - vanishingRef.current.y) * 0.08;\n\n      const cx = vanishingRef.current.x * width;\n      const cy = vanishingRef.current.y * height;\n      const focal = Math.min(width, height) * 0.65;\n\n      ctx.fillStyle = isWarping\n        ? \"rgba(3, 5, 12, 0.32)\"\n        : \"rgba(3, 5, 12, 0.55)\";\n      ctx.fillRect(0, 0, width, height);\n\n      for (let i = 0; i < stars.length; i++) {\n        const s = stars[i];\n        s.pz = s.z + currentVelocity * dt * streakLength * (isWarping ? 2.8 : 1);\n        s.z -= currentVelocity * dt;\n\n        if (s.z <= 2) {\n          s.x = (Math.random() - 0.5) * width * 2.2;\n          s.y = (Math.random() - 0.5) * height * 2.2;\n          s.z = maxDepth;\n          s.pz = maxDepth;\n          continue;\n        }\n\n        // 3D perspective projection: screenX = (x / z) * focal + cx\n        const sx = (s.x / s.z) * focal + cx;\n        const sy = (s.y / s.z) * focal + cy;\n        const px = (s.x / s.pz) * focal + cx;\n        const py = (s.y / s.pz) * focal + cy;\n\n        const depthRatio = 1 - s.z / maxDepth;\n        const alpha = Math.max(0.08, Math.min(1, depthRatio * 1.2));\n        const lineWidth = Math.max(0.6, depthRatio * (isWarping ? 2.8 : 2.0));\n\n        ctx.strokeStyle = isWarping\n          ? `rgba(186, 230, 253, ${alpha.toFixed(3)})`\n          : `rgba(255, 255, 255, ${alpha.toFixed(3)})`;\n        ctx.lineWidth = lineWidth;\n        ctx.lineCap = \"round\";\n        ctx.beginPath();\n        ctx.moveTo(px, py);\n        ctx.lineTo(sx, sy);\n        ctx.stroke();\n      }\n\n      rafId = requestAnimationFrame(render);\n    };\n\n    rafId = requestAnimationFrame(render);\n    return () => {\n      cancelAnimationFrame(rafId);\n      window.removeEventListener(\"resize\", handleResize);\n    };\n  }, [speed, starCount, streakLength, isWarping]);\n\n  return (\n    <div\n      data-fullscreen-scroll\n      onMouseMove={(e) => {\n        if (!followCursor) return;\n        const rect = e.currentTarget.getBoundingClientRect();\n        vanishingRef.current.targetX = (e.clientX - rect.left) / rect.width;\n        vanishingRef.current.targetY = (e.clientY - rect.top) / rect.height;\n      }}\n      onMouseLeave={() => {\n        if (!followCursor) return;\n        vanishingRef.current.targetX = center.x;\n        vanishingRef.current.targetY = center.y;\n      }}\n      className={cn(\n        \"relative flex min-h-[360px] w-full flex-col justify-between overflow-hidden rounded-3xl border border-neutral-800 bg-[#03050C] p-6 text-white shadow-sm\",\n        className\n      )}\n    >\n      <canvas\n        ref={canvasRef}\n        aria-hidden=\"true\"\n        className=\"pointer-events-none absolute inset-0 h-full w-full\"\n      />\n\n      <div className=\"relative z-10 flex flex-1 flex-col justify-between\">\n        {children ?? (\n          <>\n            <div className=\"flex flex-wrap items-center justify-between gap-2\">\n              <span className=\"inline-flex items-center gap-1.5 rounded-full border border-white/15 bg-black/40 px-3 py-1 font-mono text-[11px] font-medium text-white backdrop-blur-md\">\n                <Zap className=\"h-3.5 w-3.5 text-sky-400\" />\n                Warp Speed · {isWarping ? \"HYPERSPACE\" : \"SUBLIGHT\"}\n              </span>\n\n              <button\n                type=\"button\"\n                onClick={() => setIsWarping((w) => !w)}\n                className={cn(\n                  \"inline-flex items-center gap-1.5 rounded-full border px-3.5 py-1 font-mono text-xs font-semibold transition-all active:scale-95\",\n                  isWarping\n                    ? \"border-sky-400 bg-sky-400 text-black shadow-[0_0_20px_rgba(56,189,248,0.6)]\"\n                    : \"border-white/20 bg-white/10 text-white backdrop-blur-md hover:bg-white/20\"\n                )}\n              >\n                <Zap className=\"h-3 w-3\" />\n                <span>{isWarping ? \"Disengage Warp\" : \"Engage Warp Jump\"}</span>\n              </button>\n            </div>\n\n            <div className=\"my-auto max-w-md py-8\">\n              <h3 className=\"text-2xl font-bold tracking-tight text-white sm:text-3xl\">\n                3D Hyperspace Projection\n              </h3>\n              <p className=\"mt-2 text-xs leading-relaxed text-white/75 sm:text-sm\">\n                Projects 3D star coordinates via{\" \"}\n                <code className=\"font-mono text-sky-300\">screenX = x / z</code>{\" \"}\n                with cursor-steered vanishing point and velocity streak ramps.\n              </p>\n            </div>\n\n            <div className=\"font-mono text-[11px] text-white/50\">\n              Move cursor to steer vanishing point · Click button to jump\n            </div>\n          </>\n        )}\n      </div>\n    </div>\n  );\n}\n\nexport default WarpSpeed;\n",
          "type": "registry:ui",
          "target": "components/ui/warp-speed.tsx"
        },
        {
          "path": "lib/utils.ts",
          "content": "import { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...inputs: ClassValue[]) {\n  return twMerge(clsx(inputs));\n}\n\nexport async function copyToClipboard(text: string): Promise<boolean> {\n  if (typeof window === \"undefined\") return false;\n\n  try {\n    if (navigator.clipboard && window.isSecureContext) {\n      await navigator.clipboard.writeText(text);\n      return true;\n    }\n\n    const textArea = document.createElement(\"textarea\");\n    textArea.value = text;\n    textArea.style.position = \"fixed\";\n    textArea.style.left = \"-999999px\";\n    textArea.style.top = \"-999999px\";\n    document.body.appendChild(textArea);\n    textArea.focus();\n    textArea.select();\n    const succeeded = document.execCommand(\"copy\");\n    textArea.remove();\n    return succeeded;\n  } catch {\n    return false;\n  }\n}\n",
          "type": "registry:lib",
          "target": "lib/utils.ts"
        }
      ]
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "water-ripples",
      "type": "registry:ui",
      "title": "Water Ripples",
      "author": "Rishabh Bose <https://theb0se.vercel.app/>",
      "description": "Interactive water surface ripple simulation combining a real-time 2D finite-difference wave-equation height-map buffer with expanding specular caustic refraction rings triggered by cursor wakes, clicks, and ambient droplets.",
      "dependencies": [
        "lucide-react",
        "clsx",
        "tailwind-merge"
      ],
      "files": [
        {
          "path": "components/ui/water-ripples.tsx",
          "content": "\"use client\";\n\nimport React, { useEffect, useRef, useState } from \"react\";\nimport { Radio, CloudRain, MousePointerClick } from \"lucide-react\";\nimport { cn } from \"@/lib/utils\";\n\nexport interface WaterRipplesProps {\n  /** Wave energy retention factor per frame (0.90 to 0.995). Default: 0.97 */\n  damping?: number;\n  /** Maximum expansion radius of spawned concentric ripple rings in px. Default: 140 */\n  rippleRadius?: number;\n  /** Automatically spawn periodic rain/ambient droplets across the surface. Default: true */\n  ambientDrops?: boolean;\n  /** Primary specular caustic highlight hex color. Default: \"#38BDF8\" */\n  color?: string;\n  /** Spawn ripples on pointer move and click. Default: true */\n  interactive?: boolean;\n  /** Optional foreground content */\n  children?: React.ReactNode;\n  className?: string;\n}\n\nfunction hexToRgb(hex: string): [number, number, number] {\n  const clean = hex.replace(\"#\", \"\").trim();\n  if (clean.length === 3) {\n    return [\n      parseInt(clean[0] + clean[0], 16) || 56,\n      parseInt(clean[1] + clean[1], 16) || 189,\n      parseInt(clean[2] + clean[2], 16) || 248,\n    ];\n  }\n  const num = parseInt(clean, 16);\n  if (Number.isNaN(num)) return [56, 189, 248];\n  return [(num >> 16) & 255, (num >> 8) & 255, num & 255];\n}\n\nconst RIPPLE_PRESETS = [\n  { name: \"Lagoon Pool\", color: \"#38BDF8\", damping: 0.975, radius: 140 },\n  { name: \"Jade Sanctuary\", color: \"#34D399\", damping: 0.982, radius: 175 },\n  { name: \"Sapphire Basin\", color: \"#818CF8\", damping: 0.962, radius: 120 },\n];\n\nexport function WaterRipples({\n  damping = 0.97,\n  rippleRadius = 140,\n  ambientDrops = true,\n  color = \"#38BDF8\",\n  interactive = true,\n  children,\n  className,\n}: WaterRipplesProps) {\n  const containerRef = useRef<HTMLDivElement>(null);\n  const canvasRef = useRef<HTMLCanvasElement>(null);\n\n  const [liveDamping, setLiveDamping] = useState(damping);\n  const [liveRadius, setLiveRadius] = useState(rippleRadius);\n  const [liveAmbient, setLiveAmbient] = useState(ambientDrops);\n  const [liveColor, setLiveColor] = useState(color);\n  const [dropCounter, setDropCounter] = useState(0);\n\n  useEffect(() => setLiveDamping(damping), [damping]);\n  useEffect(() => setLiveRadius(rippleRadius), [rippleRadius]);\n  useEffect(() => setLiveAmbient(ambientDrops), [ambientDrops]);\n  useEffect(() => setLiveColor(color), [color]);\n\n  const paramsRef = useRef({\n    damping: liveDamping,\n    radius: liveRadius,\n    ambient: liveAmbient,\n    color: liveColor,\n  });\n\n  useEffect(() => {\n    paramsRef.current = {\n      damping: liveDamping,\n      radius: liveRadius,\n      ambient: liveAmbient,\n      color: liveColor,\n    };\n  }, [liveDamping, liveRadius, liveAmbient, liveColor]);\n\n  // Imperative disturb callback ref so pointer handlers trigger ripples without re-mounting\n  const disturbRef = useRef<\n    (normX: number, normY: number, strength: number) => void\n  >(() => {});\n\n  useEffect(() => {\n    const container = containerRef.current;\n    const canvas = canvasRef.current;\n    if (!container || !canvas) return;\n\n    const ctx = canvas.getContext(\"2d\");\n    if (!ctx) return;\n\n    let simW = 280;\n    let simH = 180;\n    let bufPrev = new Float32Array(simW * simH);\n    let bufCurr = new Float32Array(simW * simH);\n    // Precomputed procedural submerged mosaic/pebble & static caustic texture buffer\n    let bedTex = new Float32Array(simW * simH);\n\n    const offscreen = document.createElement(\"canvas\");\n    offscreen.width = simW;\n    offscreen.height = simH;\n    const offCtx = offscreen.getContext(\"2d\");\n    let imgData = offCtx ? offCtx.createImageData(simW, simH) : null;\n\n    const buildSubmergedBed = (w: number, h: number) => {\n      bedTex = new Float32Array(w * h);\n      for (let y = 0; y < h; y++) {\n        const ny = y / h;\n        for (let x = 0; x < w; x++) {\n          const nx = x / w;\n          // Subtle submerged stone tile grid + organic pebble/sand harmonic texture\n          const tileX = Math.abs(Math.sin(nx * Math.PI * 14));\n          const tileY = Math.abs(Math.sin(ny * Math.PI * 9));\n          const grout = Math.pow(Math.min(tileX, tileY), 0.18);\n\n          const pebble =\n            0.5 +\n            0.25 * Math.sin(x * 0.23 + Math.cos(y * 0.19) * 2.5) +\n            0.25 * Math.cos(y * 0.27 - Math.sin(x * 0.21) * 2.5);\n\n          bedTex[y * w + x] = grout * (0.72 + 0.28 * pebble);\n        }\n      }\n    };\n\n    let viewW = 1;\n    let viewH = 1;\n    let dpr = 1;\n\n    const resize = () => {\n      const rect = container.getBoundingClientRect();\n      viewW = Math.max(1, rect.width);\n      viewH = Math.max(1, rect.height);\n      dpr = Math.min(window.devicePixelRatio || 1, 2);\n      canvas.width = Math.floor(viewW * dpr);\n      canvas.height = Math.floor(viewH * dpr);\n      ctx.setTransform(dpr, 0, 0, dpr, 0, 0);\n\n      // 0.45x simulation grid resolution for silky 60fps per-pixel 3D normal shading\n      const nextSimW = Math.max(160, Math.min(340, Math.floor(viewW * 0.42)));\n      const nextSimH = Math.max(110, Math.min(230, Math.floor(viewH * 0.42)));\n      if (nextSimW !== simW || nextSimH !== simH || bedTex.length === 0) {\n        simW = nextSimW;\n        simH = nextSimH;\n        bufPrev = new Float32Array(simW * simH);\n        bufCurr = new Float32Array(simW * simH);\n        buildSubmergedBed(simW, simH);\n        offscreen.width = simW;\n        offscreen.height = simH;\n        imgData = offCtx ? offCtx.createImageData(simW, simH) : null;\n      }\n    };\n\n    resize();\n    const ro = new ResizeObserver(resize);\n    ro.observe(container);\n\n    const triggerRipple = (normX: number, normY: number, strength: number) => {\n      const gx = Math.floor(normX * simW);\n      const gy = Math.floor(normY * simH);\n      const rad = Math.max(\n        3,\n        Math.min(12, Math.round((paramsRef.current.radius / 140) * 6))\n      );\n\n      for (let dy = -rad; dy <= rad; dy++) {\n        const y = gy + dy;\n        if (y <= 2 || y >= simH - 2) continue;\n        for (let dx = -rad; dx <= rad; dx++) {\n          const x = gx + dx;\n          if (x <= 2 || x >= simW - 2) continue;\n          const dist = Math.sqrt(dx * dx + dy * dy);\n          if (dist <= rad) {\n            // Smooth raised ring profile so each drop launches a realistic capillary wave packet\n            const phase = (dist / rad) * Math.PI;\n            const profile = Math.cos(phase);\n            bufPrev[y * simW + x] -= strength * profile;\n          }\n        }\n      }\n    };\n\n    disturbRef.current = triggerRipple;\n\n    // Seed initial welcoming droplets\n    triggerRipple(0.35, 0.45, 220);\n    triggerRipple(0.66, 0.54, 190);\n\n    let rafId = 0;\n    let frame = 0;\n\n    // Normalized 3D directional light vector L = normalize(-0.45, -0.55, 0.70)\n    // and Halfway vector H = normalize(L + V) where V = (0, 0, 1)\n    const lx = -0.45;\n    const ly = -0.55;\n    const lz = 0.703;\n    const hLen = Math.hypot(lx, ly, lz + 1.0);\n    const hx = lx / hLen;\n    const hy = ly / hLen;\n    const hz = (lz + 1.0) / hLen;\n\n    const render = () => {\n      frame++;\n      const {\n        damping: curDamping,\n        ambient: curAmbient,\n        color: curColor,\n      } = paramsRef.current;\n\n      const [tintR, tintG, tintB] = hexToRgb(curColor);\n      const damp = Math.max(0.9, Math.min(0.994, curDamping));\n\n      // Periodic ambient rain droplets\n      if (curAmbient && frame % 24 === 0) {\n        triggerRipple(\n          0.1 + Math.random() * 0.8,\n          0.12 + Math.random() * 0.76,\n          140 + Math.random() * 120\n        );\n      }\n\n      // 1. Step 2D Wave Equation with 8-neighbor isotropic Laplacian kernel for circular waves\n      for (let y = 1; y < simH - 1; y++) {\n        const row = y * simW;\n        for (let x = 1; x < simW - 1; x++) {\n          const idx = row + x;\n          const cardinal =\n            bufPrev[idx - 1] +\n            bufPrev[idx + 1] +\n            bufPrev[idx - simW] +\n            bufPrev[idx + simW];\n          const diagonal =\n            bufPrev[idx - simW - 1] +\n            bufPrev[idx - simW + 1] +\n            bufPrev[idx + simW - 1] +\n            bufPrev[idx + simW + 1];\n\n          const avg = cardinal * 0.4 + diagonal * 0.1;\n          bufCurr[idx] = (avg - bufCurr[idx]) * damp;\n        }\n      }\n\n      // 2. Per-pixel 3D Surface Normal Reconstruction, Snell Refraction, Caustic Focusing & Blinn-Phong Specular\n      if (offCtx && imgData) {\n        const data = imgData.data;\n        const timeShift = frame * 0.025;\n\n        for (let y = 1; y < simH - 1; y++) {\n          const row = y * simW;\n          const vNorm = y / simH;\n\n          for (let x = 1; x < simW - 1; x++) {\n            const idx = row + x;\n\n            // Central-difference 2D height-field gradient (dh/dx, dh/dy)\n            const dhdx = (bufCurr[idx + 1] - bufCurr[idx - 1]) * 0.032;\n            const dhdy = (bufCurr[idx + simW] - bufCurr[idx - simW]) * 0.032;\n\n            // 3D Surface Normal N = normalize(-dhdx, -dhdy, 1.0)\n            const invLen = 1.0 / Math.sqrt(dhdx * dhdx + dhdy * dhdy + 1.0);\n            const nx = -dhdx * invLen;\n            const ny = -dhdy * invLen;\n            const nz = invLen;\n\n            // Refracted floor lookup coordinates shifted by surface normal\n            const refX = Math.max(\n              0,\n              Math.min(simW - 1, Math.round(x + nx * 26))\n            );\n            const refY = Math.max(\n              0,\n              Math.min(simH - 1, Math.round(y + ny * 26))\n            );\n            const floorPattern = bedTex[refY * simW + refX];\n\n            // Ambient refracted caustic wave network on the pool floor\n            const cx = refX * 0.11 + timeShift;\n            const cy = refY * 0.11 - timeShift * 0.7;\n            const ambientCaustic = Math.pow(\n              0.5 + 0.5 * Math.sin(cx + Math.cos(cy * 1.3)) * Math.cos(cy - Math.sin(cx * 1.2)),\n              3.0\n            );\n\n            // Wave curvature convergence (Laplacian) creates bright caustic focal rings on the bed\n            const curvature = Math.max(\n              0,\n              bufCurr[idx] * 2.0 -\n                (bufCurr[idx - 1] + bufCurr[idx + 1]) * 0.5\n            );\n            const rippleCaustic = Math.min(1.4, curvature * 0.018);\n\n            // Schlick Fresnel reflection factor: grazing angles reflect more bright sky light\n            const fresnel = Math.pow(1.0 - nz, 3.0);\n\n            // Diffuse lighting + sharp Blinn-Phong specular highlight pow(max(dot(N, H), 0.0), 80.0)\n            const ndotl = Math.max(0.0, nx * lx + ny * ly + nz * lz);\n            const ndoth = Math.max(0.0, nx * hx + ny * hy + nz * hz);\n            const specular = Math.pow(ndoth, 80.0) * 1.85 + Math.pow(ndoth, 18.0) * 0.35;\n\n            // Combine deep water absorption + refracted floor + caustics + Fresnel sky + specular glint\n            const depthShade = 0.42 + 0.58 * (1.0 - vNorm * 0.45);\n            const floorLight =\n              floorPattern * depthShade * (0.55 + 0.45 * ndotl) +\n              ambientCaustic * 0.24 +\n              rippleCaustic * 0.55;\n\n            const rOut =\n              4 +\n              floorLight * tintR * 0.78 +\n              fresnel * 145 +\n              specular * 255;\n            const gOut =\n              14 +\n              floorLight * tintG * 0.92 +\n              fresnel * 215 +\n              specular * 252;\n            const bOut =\n              30 +\n              floorLight * tintB * 1.05 +\n              fresnel * 255 +\n              specular * 255;\n\n            const p = idx * 4;\n            data[p] = rOut > 255 ? 255 : rOut < 0 ? 0 : rOut;\n            data[p + 1] = gOut > 255 ? 255 : gOut < 0 ? 0 : gOut;\n            data[p + 2] = bOut > 255 ? 255 : bOut < 0 ? 0 : bOut;\n            data[p + 3] = 255;\n          }\n        }\n\n        offCtx.putImageData(imgData, 0, 0);\n\n        // Upscale smoothly onto full-resolution display canvas\n        ctx.imageSmoothingEnabled = true;\n        ctx.imageSmoothingQuality = \"high\";\n        ctx.drawImage(offscreen, 0, 0, viewW, viewH);\n      }\n\n      // Swap wave equation buffers\n      const temp = bufPrev;\n      bufPrev = bufCurr;\n      bufCurr = temp;\n\n      rafId = requestAnimationFrame(render);\n    };\n\n    rafId = requestAnimationFrame(render);\n\n    return () => {\n      cancelAnimationFrame(rafId);\n      ro.disconnect();\n    };\n  }, []);\n\n  const handlePointerMove = (e: React.PointerEvent<HTMLDivElement>) => {\n    if (!interactive || !containerRef.current) return;\n    const rect = containerRef.current.getBoundingClientRect();\n    const nx = (e.clientX - rect.left) / Math.max(1, rect.width);\n    const ny = (e.clientY - rect.top) / Math.max(1, rect.height);\n    disturbRef.current(nx, ny, 95);\n  };\n\n  const handlePointerDown = (e: React.PointerEvent<HTMLDivElement>) => {\n    if (!interactive || !containerRef.current) return;\n    const rect = containerRef.current.getBoundingClientRect();\n    const nx = (e.clientX - rect.left) / Math.max(1, rect.width);\n    const ny = (e.clientY - rect.top) / Math.max(1, rect.height);\n    disturbRef.current(nx, ny, 280);\n    setDropCounter((c) => c + 1);\n  };\n\n  return (\n    <div\n      ref={containerRef}\n      data-fullscreen-scroll\n      onPointerMove={handlePointerMove}\n      onPointerDown={handlePointerDown}\n      className={cn(\n        \"relative flex min-h-[520px] w-full flex-col justify-between overflow-hidden rounded-2xl border border-white/10 bg-[#030A18] p-6 text-white shadow-2xl select-none\",\n        interactive && \"cursor-crosshair\",\n        className\n      )}\n    >\n      <canvas\n        ref={canvasRef}\n        aria-hidden=\"true\"\n        className=\"pointer-events-none absolute inset-0 h-full w-full\"\n      />\n\n      {children && (\n        <div className=\"relative z-10 flex min-h-[520px] w-full flex-col\">\n          {children}\n        </div>\n      )}\n    </div>\n  );\n}\n\nexport default WaterRipples;\n",
          "type": "registry:ui",
          "target": "components/ui/water-ripples.tsx"
        },
        {
          "path": "lib/utils.ts",
          "content": "import { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...inputs: ClassValue[]) {\n  return twMerge(clsx(inputs));\n}\n\nexport async function copyToClipboard(text: string): Promise<boolean> {\n  if (typeof window === \"undefined\") return false;\n\n  try {\n    if (navigator.clipboard && window.isSecureContext) {\n      await navigator.clipboard.writeText(text);\n      return true;\n    }\n\n    const textArea = document.createElement(\"textarea\");\n    textArea.value = text;\n    textArea.style.position = \"fixed\";\n    textArea.style.left = \"-999999px\";\n    textArea.style.top = \"-999999px\";\n    document.body.appendChild(textArea);\n    textArea.focus();\n    textArea.select();\n    const succeeded = document.execCommand(\"copy\");\n    textArea.remove();\n    return succeeded;\n  } catch {\n    return false;\n  }\n}\n",
          "type": "registry:lib",
          "target": "lib/utils.ts"
        }
      ]
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "waterfall",
      "type": "registry:ui",
      "title": "Waterfall",
      "author": "Rishabh Bose <https://theb0se.vercel.app/>",
      "description": "Physics-driven cascading waterfall background rendered on HTML5 Canvas 2D with 240+ layered vertical hydro streaks, gravity-accelerated splash droplets, and a pulsing volumetric mist cloud at the plunge basin.",
      "dependencies": [
        "lucide-react",
        "clsx",
        "tailwind-merge"
      ],
      "files": [
        {
          "path": "components/ui/waterfall.tsx",
          "content": "\"use client\";\n\nimport React, { useEffect, useRef, useState } from \"react\";\nimport { Droplets, Sparkles, Wind } from \"lucide-react\";\nimport { cn } from \"@/lib/utils\";\n\nexport interface WaterfallProps {\n  /** Water velocity multiplier (0.3 to 2.5). Default: 1.0 */\n  flow?: number;\n  /** Plunge pool volumetric mist intensity (0 to 1). Default: 0.75 */\n  mistAmount?: number;\n  /** Primary water tint hex color. Default: \"#38BDF8\" */\n  color?: string;\n  /** Width of the waterfall curtain relative to container (0.3 to 1.0). Default: 0.75 */\n  curtainWidth?: number;\n  /** Upward-bouncing splash droplet density/energy. Default: 1.0 */\n  splashIntensity?: number;\n  /** Optional foreground content */\n  children?: React.ReactNode;\n  className?: string;\n}\n\ninterface WaterRibbon {\n  xNorm: number; // -0.5 to 0.5 within curtain\n  y: number;\n  width: number;\n  baseSpeed: number;\n  opacity: number;\n  layer: 0 | 1 | 2; // 0 = deep subsurface sheet, 1 = turbulent mid-ribbon, 2 = aerated whitewater jet\n  phase: number;\n  freq: number;\n  chuteIndex: number;\n}\n\ninterface SplashDrop {\n  x: number;\n  y: number;\n  vx: number;\n  vy: number;\n  radius: number;\n  alpha: number;\n  life: number;\n  maxLife: number;\n}\n\ninterface MistBank {\n  xNorm: number;\n  yOffset: number;\n  radius: number;\n  phase: number;\n  speed: number;\n  risePhase: number;\n}\n\ninterface PoolRipple {\n  xNorm: number;\n  yOffset: number;\n  rx: number;\n  ry: number;\n  maxRx: number;\n  alpha: number;\n  speed: number;\n}\n\ninterface CliffLedge {\n  side: \"left\" | \"right\" | \"center\";\n  yNorm: number;\n  xNorm: number;\n  wNorm: number;\n  hNorm: number;\n  shade: number;\n  points: Array<{ dx: number; dy: number }>;\n}\n\nfunction hexToRgb(hex: string): [number, number, number] {\n  const clean = hex.replace(\"#\", \"\").trim();\n  if (clean.length === 3) {\n    return [\n      parseInt(clean[0] + clean[0], 16) || 56,\n      parseInt(clean[1] + clean[1], 16) || 189,\n      parseInt(clean[2] + clean[2], 16) || 248,\n    ];\n  }\n  const num = parseInt(clean, 16);\n  if (Number.isNaN(num)) return [56, 189, 248];\n  return [(num >> 16) & 255, (num >> 8) & 255, num & 255];\n}\n\nconst PRESETS = [\n  { name: \"Skógafoss\", color: \"#38BDF8\", flow: 1.0, mist: 0.78, curtain: 0.72 },\n  { name: \"Emerald Gorge\", color: \"#2DD4BF\", flow: 1.35, mist: 0.9, curtain: 0.85 },\n  { name: \"Glacial Melt\", color: \"#60A5FA\", flow: 0.85, mist: 0.65, curtain: 0.58 },\n];\n\nexport function Waterfall({\n  flow = 1.0,\n  mistAmount = 0.75,\n  color = \"#38BDF8\",\n  curtainWidth = 0.75,\n  splashIntensity = 1.0,\n  children,\n  className,\n}: WaterfallProps) {\n  const containerRef = useRef<HTMLDivElement>(null);\n  const canvasRef = useRef<HTMLCanvasElement>(null);\n\n  const [liveFlow, setLiveFlow] = useState(flow);\n  const [liveMist, setLiveMist] = useState(mistAmount);\n  const [liveColor, setLiveColor] = useState(color);\n  const [liveCurtain, setLiveCurtain] = useState(curtainWidth);\n\n  useEffect(() => setLiveFlow(flow), [flow]);\n  useEffect(() => setLiveMist(mistAmount), [mistAmount]);\n  useEffect(() => setLiveColor(color), [color]);\n  useEffect(() => setLiveCurtain(curtainWidth), [curtainWidth]);\n\n  const paramsRef = useRef({\n    flow: liveFlow,\n    mist: liveMist,\n    color: liveColor,\n    curtain: liveCurtain,\n    splash: splashIntensity,\n  });\n\n  useEffect(() => {\n    paramsRef.current = {\n      flow: liveFlow,\n      mist: liveMist,\n      color: liveColor,\n      curtain: liveCurtain,\n      splash: splashIntensity,\n    };\n  }, [liveFlow, liveMist, liveColor, liveCurtain, splashIntensity]);\n\n  useEffect(() => {\n    const container = containerRef.current;\n    const canvas = canvasRef.current;\n    if (!container || !canvas) return;\n\n    const ctx = canvas.getContext(\"2d\");\n    if (!ctx) return;\n\n    let width = 0;\n    let height = 0;\n    let dpr = 1;\n    let rafId = 0;\n\n    const RIBBON_COUNT = 290;\n    const ribbons: WaterRibbon[] = [];\n    const drops: SplashDrop[] = [];\n    const mistBanks: MistBank[] = [];\n    const poolRipples: PoolRipple[] = [];\n    const cliffLedges: CliffLedge[] = [];\n\n    // 7 natural rock chutes across the crest lip so water groups into organic streams\n    const chuteCenters = [-0.43, -0.29, -0.14, 0.0, 0.15, 0.3, 0.44];\n\n    const initScene = () => {\n      ribbons.length = 0;\n      for (let i = 0; i < RIBBON_COUNT; i++) {\n        const layerRand = Math.random();\n        const layer: 0 | 1 | 2 = layerRand < 0.32 ? 0 : layerRand < 0.76 ? 1 : 2;\n        const chuteIdx = Math.floor(Math.random() * chuteCenters.length);\n        const chuteSpread = layer === 0 ? 0.14 : layer === 1 ? 0.095 : 0.065;\n        const xNorm = Math.max(\n          -0.49,\n          Math.min(\n            0.49,\n            chuteCenters[chuteIdx] + (Math.random() - 0.5) * 2 * chuteSpread\n          )\n        );\n\n        ribbons.push({\n          xNorm,\n          y: Math.random(), // normalized 0 (crest) to 1 (plunge)\n          width:\n            layer === 0\n              ? 14 + Math.random() * 20\n              : layer === 1\n                ? 4.5 + Math.random() * 8\n                : 1.5 + Math.random() * 3.2,\n          baseSpeed:\n            layer === 0\n              ? 0.0055 + Math.random() * 0.003\n              : layer === 1\n                ? 0.008 + Math.random() * 0.0045\n                : 0.011 + Math.random() * 0.006,\n          opacity:\n            layer === 0\n              ? 0.16 + Math.random() * 0.14\n              : layer === 1\n                ? 0.28 + Math.random() * 0.26\n                : 0.55 + Math.random() * 0.4,\n          layer,\n          phase: Math.random() * Math.PI * 2,\n          freq: 2.5 + Math.random() * 4.5,\n          chuteIndex: chuteIdx,\n        });\n      }\n\n      mistBanks.length = 0;\n      for (let i = 0; i < 24; i++) {\n        mistBanks.push({\n          xNorm: (Math.random() - 0.5) * 1.25,\n          yOffset: (Math.random() - 0.5) * 44,\n          radius: 65 + Math.random() * 110,\n          phase: Math.random() * Math.PI * 2,\n          speed: 0.5 + Math.random() * 0.85,\n          risePhase: Math.random() * Math.PI * 2,\n        });\n      }\n\n      poolRipples.length = 0;\n      for (let i = 0; i < 18; i++) {\n        const maxRx = 55 + Math.random() * 140;\n        poolRipples.push({\n          xNorm: (Math.random() - 0.5) * 0.95,\n          yOffset: 6 + Math.random() * 68,\n          rx: Math.random() * maxRx,\n          ry: 3 + Math.random() * 8,\n          maxRx,\n          alpha: 0.22 + Math.random() * 0.3,\n          speed: 0.65 + Math.random() * 0.85,\n        });\n      }\n\n      // Generate craggy wet basalt rock strata flanking & behind the cascade\n      cliffLedges.length = 0;\n      for (let row = 0; row < 11; row++) {\n        const yNorm = 0.06 + (row / 10) * 0.72;\n        for (const side of [\"left\", \"right\", \"center\"] as const) {\n          const polyPts: Array<{ dx: number; dy: number }> = [];\n          const segs = 7;\n          for (let s = 0; s <= segs; s++) {\n            const t = s / segs;\n            polyPts.push({\n              dx: t,\n              dy: (Math.sin(row * 3.1 + s * 1.9) * 0.5 + (Math.random() - 0.5) * 0.5) * 0.04,\n            });\n          }\n          cliffLedges.push({\n            side,\n            yNorm,\n            xNorm:\n              side === \"left\"\n                ? 0\n                : side === \"right\"\n                  ? 0.68 + (row % 3) * 0.03\n                  : 0.22 + (row % 2) * 0.08,\n            wNorm:\n              side === \"center\"\n                ? 0.52\n                : 0.28 + Math.sin(row * 1.7) * 0.06,\n            hNorm: 0.09 + (row % 3) * 0.025,\n            shade: 0.65 + (row % 4) * 0.12,\n            points: polyPts,\n          });\n        }\n      }\n    };\n\n    const resize = () => {\n      const rect = container.getBoundingClientRect();\n      width = Math.max(1, rect.width);\n      height = Math.max(1, rect.height);\n      dpr = Math.min(window.devicePixelRatio || 1, 2);\n      canvas.width = Math.floor(width * dpr);\n      canvas.height = Math.floor(height * dpr);\n      ctx.setTransform(dpr, 0, 0, dpr, 0, 0);\n      if (ribbons.length === 0) initScene();\n    };\n\n    resize();\n    const ro = new ResizeObserver(resize);\n    ro.observe(container);\n\n    let time = 0;\n\n    const render = () => {\n      const {\n        flow: curFlow,\n        mist: curMist,\n        color: curColor,\n        curtain: curCurtain,\n        splash: curSplash,\n      } = paramsRef.current;\n\n      time += 0.016 * curFlow;\n      const [r, g, b] = hexToRgb(curColor);\n      const clampCurtain = Math.max(0.3, Math.min(1.0, curCurtain));\n      const cWidth = width * clampCurtain;\n      const centerX = width * 0.5;\n      const crestY = height * 0.09;\n      const plungeY = height * 0.79;\n      const fallHeight = plungeY - crestY;\n\n      // 1. Atmospheric misty gorge sky & deep canyon backdrop\n      const skyGrad = ctx.createLinearGradient(0, 0, 0, height);\n      skyGrad.addColorStop(0, \"#050D1A\");\n      skyGrad.addColorStop(0.12, \"#09192E\");\n      skyGrad.addColorStop(0.75, \"#040B17\");\n      skyGrad.addColorStop(1, \"#02060D\");\n      ctx.fillStyle = skyGrad;\n      ctx.fillRect(0, 0, width, height);\n\n      // Top atmospheric zenith glow catching the crest of the waterfall\n      const crestSunGlow = ctx.createRadialGradient(\n        centerX,\n        crestY,\n        10,\n        centerX,\n        crestY + fallHeight * 0.25,\n        cWidth * 0.75\n      );\n      crestSunGlow.addColorStop(0, `rgba(${Math.min(255, r + 80)}, ${Math.min(255, g + 65)}, 255, 0.26)`);\n      crestSunGlow.addColorStop(0.45, `rgba(${r}, ${g}, ${b}, 0.1)`);\n      crestSunGlow.addColorStop(1, \"rgba(0, 0, 0, 0)\");\n      ctx.fillStyle = crestSunGlow;\n      ctx.fillRect(0, 0, width, height);\n\n      // 2. Shadowed wet basalt cliff rock strata flanking & behind the waterfall\n      for (let i = 0; i < cliffLedges.length; i++) {\n        const ledge = cliffLedges[i];\n        const ly = ledge.yNorm * height;\n        const lh = ledge.hNorm * height;\n        let lx = ledge.xNorm * width;\n        let lw = ledge.wNorm * width;\n\n        if (ledge.side === \"left\") {\n          lw = Math.max(width * 0.16, centerX - cWidth * 0.46 + Math.sin(i * 2.1) * 22);\n          lx = 0;\n        } else if (ledge.side === \"right\") {\n          const rightStart = Math.min(\n            width * 0.84,\n            centerX + cWidth * 0.46 - Math.cos(i * 1.9) * 22\n          );\n          lx = rightStart;\n          lw = width - rightStart;\n        }\n\n        ctx.beginPath();\n        ctx.moveTo(lx, ly + lh);\n        for (let p = 0; p < ledge.points.length; p++) {\n          const pt = ledge.points[p];\n          ctx.lineTo(lx + pt.dx * lw, ly + pt.dy * height);\n        }\n        ctx.lineTo(lx + lw, ly + lh);\n        ctx.closePath();\n\n        const rockGrad = ctx.createLinearGradient(0, ly, 0, ly + lh);\n        const br = Math.round(12 * ledge.shade);\n        const bg = Math.round(22 * ledge.shade);\n        const bb = Math.round(36 * ledge.shade);\n        rockGrad.addColorStop(0, `rgb(${br + 10}, ${bg + 16}, ${bb + 24})`);\n        rockGrad.addColorStop(0.25, `rgb(${br}, ${bg}, ${bb})`);\n        rockGrad.addColorStop(1, \"#030710\");\n        ctx.fillStyle = rockGrad;\n        ctx.fill();\n\n        // Wet basalt specular sheen on top rock ridge catching mist light\n        if (ledge.side !== \"center\") {\n          ctx.beginPath();\n          for (let p = 0; p < ledge.points.length; p++) {\n            const pt = ledge.points[p];\n            if (p === 0) ctx.moveTo(lx + pt.dx * lw, ly + pt.dy * height);\n            else ctx.lineTo(lx + pt.dx * lw, ly + pt.dy * height);\n          }\n          ctx.strokeStyle = `rgba(${Math.min(255, r + 50)}, ${Math.min(255, g + 50)}, 255, 0.14)`;\n          ctx.lineWidth = 1.4;\n          ctx.stroke();\n        }\n      }\n\n      // Upper river feeding into the waterfall lip\n      const riverGrad = ctx.createLinearGradient(0, 0, 0, crestY + 12);\n      riverGrad.addColorStop(0, \"#041022\");\n      riverGrad.addColorStop(0.7, `rgba(${Math.floor(r * 0.45)}, ${Math.floor(g * 0.6)}, ${Math.floor(b * 0.75)}, 0.65)`);\n      riverGrad.addColorStop(1, `rgba(225, 248, 255, 0.85)`);\n      ctx.fillStyle = riverGrad;\n      ctx.fillRect(centerX - cWidth * 0.5, 0, cWidth, crestY + 4);\n\n      // 3. Multi-layered turbulent water ribbons accelerating under gravity v = sqrt(2 * g * y)\n      ctx.save();\n      ctx.globalCompositeOperation = \"lighter\";\n\n      for (let i = 0; i < ribbons.length; i++) {\n        const rb = ribbons[i];\n        // Physical gravitational acceleration: velocity increases with square root of fall distance\n        const gravityFactor = Math.sqrt(0.18 + Math.max(0, rb.y) * 1.95);\n        rb.y += rb.baseSpeed * curFlow * gravityFactor;\n\n        // Multi-frequency FBM/sine horizontal turbulence as water breaks into chutes\n        const yPos = crestY + rb.y * fallHeight;\n        const turb =\n          Math.sin(rb.y * rb.freq + time * 3.2 + rb.phase) *\n            (rb.layer === 0 ? 5.5 : 2.8) +\n          Math.cos(rb.y * (rb.freq * 2.1) - time * 4.8 + rb.chuteIndex) * 1.6;\n\n        // Slight inward vena-contracta narrowing mid-fall, then fanning out at plunge base\n        const fanFactor = 1.0 - Math.sin(rb.y * Math.PI) * 0.04 + rb.y * 0.07;\n        const xPos = centerX + rb.xNorm * cWidth * fanFactor + turb;\n\n        // Ribbon length stretches proportionally to gravitational speed (motion blur streak)\n        const streakLen =\n          (rb.layer === 0 ? 75 : rb.layer === 1 ? 58 : 42) *\n          (0.65 + gravityFactor * 0.75);\n\n        const yTop = Math.max(crestY - 4, yPos - streakLen);\n        const yBot = Math.min(plungeY + 10, yPos);\n\n        // Edge feathering & aerated whitewater transition near the crest\n        const edgeDist = 1 - Math.min(1, Math.abs(rb.xNorm) * 1.9);\n        const crestAerated = Math.max(0, 1 - rb.y * 2.6); // extra foamy bright near top lip\n        const alpha = rb.opacity * (0.35 + 0.65 * edgeDist);\n\n        if (yBot > yTop) {\n          const grad = ctx.createLinearGradient(xPos, yTop, xPos, yBot);\n          if (rb.layer === 2 || crestAerated > 0.45) {\n            grad.addColorStop(0, \"rgba(255, 255, 255, 0)\");\n            grad.addColorStop(0.35, `rgba(220, 248, 255, ${alpha * 0.75})`);\n            grad.addColorStop(0.82, `rgba(255, 255, 255, ${Math.min(0.95, alpha * 1.15)})`);\n            grad.addColorStop(1, \"rgba(255, 255, 255, 0)\");\n          } else {\n            grad.addColorStop(0, `rgba(${r}, ${g}, ${b}, 0)`);\n            grad.addColorStop(0.35, `rgba(${r}, ${g}, ${b}, ${alpha * 0.65})`);\n            grad.addColorStop(\n              0.8,\n              `rgba(${Math.min(255, r + 75)}, ${Math.min(255, g + 60)}, 255, ${alpha})`\n            );\n            grad.addColorStop(1, `rgba(${r}, ${g}, ${b}, 0)`);\n          }\n\n          ctx.fillStyle = grad;\n          // Slightly thinner width as water stretches at high velocity\n          const dynamicWidth = rb.width * (1.12 - rb.y * 0.28);\n          ctx.fillRect(\n            xPos - dynamicWidth * 0.5,\n            yTop,\n            dynamicWidth,\n            yBot - yTop\n          );\n        }\n\n        // Reset at plunge pool & trigger kinetic splash droplets\n        if (rb.y >= 1.06) {\n          rb.y = -Math.random() * 0.08;\n          const chuteSpread = rb.layer === 0 ? 0.14 : rb.layer === 1 ? 0.095 : 0.065;\n          rb.xNorm = Math.max(\n            -0.49,\n            Math.min(\n              0.49,\n              chuteCenters[rb.chuteIndex] + (Math.random() - 0.5) * 2 * chuteSpread\n            )\n          );\n\n          if (\n            drops.length < 160 &&\n            Math.random() < 0.36 * curSplash * Math.min(1.9, curFlow)\n          ) {\n            const impactX = centerX + rb.xNorm * cWidth;\n            const maxLife = 26 + Math.random() * 32;\n            drops.push({\n              x: impactX + (Math.random() - 0.5) * 18,\n              y: plungeY + (Math.random() - 0.5) * 8,\n              vx: (Math.random() - 0.5) * 4.2,\n              vy: -(2.6 + Math.random() * 5.2) * Math.sqrt(curFlow),\n              radius: 1.0 + Math.random() * 2.2,\n              alpha: 0.5 + Math.random() * 0.45,\n              life: 0,\n              maxLife,\n            });\n          }\n        }\n      }\n\n      // 4. Aerated rolling crest foam lip at the top ledge\n      for (let c = 0; c < chuteCenters.length; c++) {\n        const cx = centerX + chuteCenters[c] * cWidth;\n        const lipRadius = (cWidth / chuteCenters.length) * 0.78;\n        const lipGrad = ctx.createRadialGradient(\n          cx,\n          crestY + 4,\n          2,\n          cx,\n          crestY + 12,\n          lipRadius\n        );\n        lipGrad.addColorStop(0, \"rgba(255, 255, 255, 0.52)\");\n        lipGrad.addColorStop(0.5, `rgba(${Math.min(255, r + 80)}, ${Math.min(255, g + 70)}, 255, 0.24)`);\n        lipGrad.addColorStop(1, \"rgba(0, 0, 0, 0)\");\n        ctx.fillStyle = lipGrad;\n        ctx.beginPath();\n        ctx.ellipse(cx, crestY + 6, lipRadius, 14, 0, 0, Math.PI * 2);\n        ctx.fill();\n      }\n      ctx.restore();\n\n      // 5. Dark abyssal plunge pool basin with subsurface emerald/cyan scattering\n      const poolGrad = ctx.createLinearGradient(0, plungeY - 6, 0, height);\n      poolGrad.addColorStop(0, `rgba(${Math.min(255, r + 40)}, ${Math.min(255, g + 50)}, 255, 0.42)`);\n      poolGrad.addColorStop(0.22, `rgba(${Math.floor(r * 0.45)}, ${Math.floor(g * 0.55)}, ${Math.floor(b * 0.7)}, 0.72)`);\n      poolGrad.addColorStop(0.65, `rgba(${Math.floor(r * 0.18)}, ${Math.floor(g * 0.26)}, ${Math.floor(b * 0.38)}, 0.92)`);\n      poolGrad.addColorStop(1, \"#02060E\");\n      ctx.fillStyle = poolGrad;\n      ctx.fillRect(0, plungeY, width, height - plungeY);\n\n      ctx.save();\n      ctx.globalCompositeOperation = \"lighter\";\n\n      // Boiling whitewater foam rollers at the plunge pool impact zone\n      const boilCount = 11;\n      for (let bIdx = 0; bIdx < boilCount; bIdx++) {\n        const bx =\n          centerX +\n          ((bIdx / (boilCount - 1)) - 0.5) * cWidth * 0.95 +\n          Math.sin(time * 3.8 + bIdx * 1.7) * 10;\n        const by = plungeY + 4 + Math.cos(time * 4.2 + bIdx * 2.3) * 4;\n        const brx = (cWidth / boilCount) * (0.85 + 0.25 * Math.sin(time * 5 + bIdx));\n        const bry = 8 + 4 * Math.cos(time * 4.5 + bIdx);\n\n        const boilGrad = ctx.createRadialGradient(bx, by, 2, bx, by, brx);\n        boilGrad.addColorStop(0, \"rgba(255, 255, 255, 0.58)\");\n        boilGrad.addColorStop(0.55, `rgba(${Math.min(255, r + 75)}, ${Math.min(255, g + 65)}, 255, 0.25)`);\n        boilGrad.addColorStop(1, \"rgba(0, 0, 0, 0)\");\n        ctx.fillStyle = boilGrad;\n        ctx.beginPath();\n        ctx.ellipse(bx, by, brx, bry, 0, 0, Math.PI * 2);\n        ctx.fill();\n      }\n\n      // Expanding elliptical water surface ripples propagating outward across the plunge pool\n      for (let i = 0; i < poolRipples.length; i++) {\n        const pr = poolRipples[i];\n        pr.rx += pr.speed * (0.7 + curFlow * 0.45);\n        if (pr.rx > pr.maxRx) {\n          pr.rx = 6;\n          pr.xNorm = (Math.random() - 0.5) * 0.95;\n          pr.yOffset = 6 + Math.random() * (height - plungeY - 18);\n        }\n        const progress = pr.rx / pr.maxRx;\n        const fade = (1 - progress) * Math.sin(progress * Math.PI);\n        const rx = centerX + pr.xNorm * cWidth * 0.9;\n        const ry = plungeY + pr.yOffset + progress * 18;\n\n        ctx.beginPath();\n        ctx.ellipse(\n          rx,\n          ry,\n          pr.rx,\n          Math.max(2, pr.rx * 0.14),\n          0,\n          0,\n          Math.PI * 2\n        );\n        ctx.strokeStyle = `rgba(220, 248, 255, ${pr.alpha * fade})`;\n        ctx.lineWidth = 1.3 * (1 - progress * 0.5);\n        ctx.stroke();\n      }\n\n      // 6. Ballistic splash droplets & fine spray with gravity\n      for (let i = drops.length - 1; i >= 0; i--) {\n        const d = drops[i];\n        d.x += d.vx;\n        d.y += d.vy;\n        d.vy += 0.18; // gravity\n        d.life += 1;\n\n        const lifeRatio = 1 - d.life / d.maxLife;\n        if (lifeRatio <= 0 || d.y > height) {\n          drops.splice(i, 1);\n          continue;\n        }\n\n        ctx.beginPath();\n        ctx.arc(d.x, d.y, d.radius, 0, Math.PI * 2);\n        ctx.fillStyle = `rgba(235, 251, 255, ${d.alpha * lifeRatio})`;\n        ctx.fill();\n      }\n\n      // 7. Rising volumetric mist banks catching top ambient light\n      if (curMist > 0.01) {\n        for (let i = 0; i < mistBanks.length; i++) {\n          const m = mistBanks[i];\n          const rise = ((time * 0.22 * m.speed + m.risePhase) % 1);\n          const fade = Math.sin(rise * Math.PI);\n          const mx =\n            centerX +\n            m.xNorm * cWidth * 0.62 +\n            Math.sin(time * 0.65 + m.phase) * 28;\n          const my = plungeY + m.yOffset - rise * 78;\n          const rad = m.radius * (0.85 + rise * 0.35);\n\n          const mistGrad = ctx.createRadialGradient(\n            mx,\n            my - rad * 0.18,\n            4,\n            mx,\n            my,\n            rad\n          );\n          const peakAlpha = 0.16 * curMist * fade;\n          mistGrad.addColorStop(0, `rgba(235, 250, 255, ${peakAlpha})`);\n          mistGrad.addColorStop(\n            0.48,\n            `rgba(${Math.min(255, r + 35)}, ${Math.min(255, g + 35)}, 255, ${peakAlpha * 0.58})`\n          );\n          mistGrad.addColorStop(1, \"rgba(0, 0, 0, 0)\");\n\n          ctx.fillStyle = mistGrad;\n          ctx.beginPath();\n          ctx.arc(mx, my, rad, 0, Math.PI * 2);\n          ctx.fill();\n        }\n      }\n\n      ctx.restore();\n\n      rafId = requestAnimationFrame(render);\n    };\n\n    rafId = requestAnimationFrame(render);\n\n    return () => {\n      cancelAnimationFrame(rafId);\n      ro.disconnect();\n    };\n  }, []);\n\n  return (\n    <div\n      ref={containerRef}\n      data-fullscreen-scroll\n      className={cn(\n        \"relative flex min-h-[520px] w-full flex-col justify-between overflow-hidden rounded-2xl border border-white/10 bg-[#020611] p-6 text-white shadow-2xl\",\n        className\n      )}\n    >\n      <canvas\n        ref={canvasRef}\n        aria-hidden=\"true\"\n        className=\"pointer-events-none absolute inset-0 h-full w-full\"\n      />\n\n      {/* Subtle top-to-bottom vignette */}\n      <div\n        aria-hidden=\"true\"\n        className=\"pointer-events-none absolute inset-0 bg-gradient-to-b from-[#020611]/55 via-transparent to-[#020611]/75\"\n      />\n\n      {children && (\n        <div className=\"relative z-10 flex min-h-[520px] w-full flex-col\">\n          {children}\n        </div>\n      )}\n    </div>\n  );\n}\n\nexport default Waterfall;\n",
          "type": "registry:ui",
          "target": "components/ui/waterfall.tsx"
        },
        {
          "path": "lib/utils.ts",
          "content": "import { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...inputs: ClassValue[]) {\n  return twMerge(clsx(inputs));\n}\n\nexport async function copyToClipboard(text: string): Promise<boolean> {\n  if (typeof window === \"undefined\") return false;\n\n  try {\n    if (navigator.clipboard && window.isSecureContext) {\n      await navigator.clipboard.writeText(text);\n      return true;\n    }\n\n    const textArea = document.createElement(\"textarea\");\n    textArea.value = text;\n    textArea.style.position = \"fixed\";\n    textArea.style.left = \"-999999px\";\n    textArea.style.top = \"-999999px\";\n    document.body.appendChild(textArea);\n    textArea.focus();\n    textArea.select();\n    const succeeded = document.execCommand(\"copy\");\n    textArea.remove();\n    return succeeded;\n  } catch {\n    return false;\n  }\n}\n",
          "type": "registry:lib",
          "target": "lib/utils.ts"
        }
      ]
    },
    {
      "$schema": "https://ui.shadcn.com/schema/registry-item.json",
      "name": "wormhole-tunnel",
      "type": "registry:ui",
      "title": "Wormhole Tunnel",
      "author": "Rishabh Bose <https://theb0se.vercel.app/>",
      "description": "Structured hyperspace wormhole tunnel on Canvas 2D featuring concentric polygonal energy rings and longitudinal warp ribs scaling from an interactive Lissajous vanishing point.",
      "dependencies": [
        "lucide-react",
        "clsx",
        "tailwind-merge"
      ],
      "files": [
        {
          "path": "components/ui/wormhole-tunnel.tsx",
          "content": "\"use client\";\n\nimport React, { useEffect, useRef, useState } from \"react\";\nimport { Compass, Zap, Sliders, RotateCcw } from \"lucide-react\";\nimport { cn } from \"@/lib/utils\";\n\nexport interface WormholeTunnelProps {\n  /** Number of concentric depth rings in the wormhole conduit (default: 28) */\n  ringCount?: number;\n  /** Forward traversal speed multiplier through the tunnel (default: 1.0) */\n  speed?: number;\n  /** Starting HSL hue in degrees (0-360, default: 195) */\n  baseHue?: number;\n  /** Total hue shift range from throat to outer aperture (default: 90) */\n  hueShift?: number;\n  /** Helical twist multiplier applied across tunnel depth (default: 1.2) */\n  twist?: number;\n  /** Whether the wormhole throat bends toward pointer movement (default: true) */\n  interactive?: boolean;\n  /** Optional foreground content rendered over the tunnel */\n  children?: React.ReactNode;\n  /** Additional CSS classes for the root container */\n  className?: string;\n}\n\ninterface RelativisticStarStreak {\n  angle: number;\n  z: number; // 0 (throat) to 1 (camera)\n  speedOffset: number;\n  hueOffset: number;\n  thickness: number;\n  radialJitter: number;\n}\n\ninterface PlasmaCloudPuff {\n  angle: number;\n  z: number;\n  sizeFactor: number;\n  hueShift: number;\n  alpha: number;\n}\n\nconst WORMHOLE_PRESETS = [\n  { name: \"Cherenkov Cyan\", baseHue: 195, hueShift: 90, twist: 1.2, speed: 1.0 },\n  { name: \"Hyperdrive Magenta\", baseHue: 295, hueShift: 110, twist: 1.8, speed: 1.4 },\n  { name: \"Chrono Gold\", baseHue: 38, hueShift: 65, twist: 0.75, speed: 0.85 },\n] as const;\n\nexport function WormholeTunnel({\n  ringCount = 28,\n  speed = 1.0,\n  baseHue = 195,\n  hueShift = 90,\n  twist = 1.2,\n  interactive = true,\n  children,\n  className,\n}: WormholeTunnelProps) {\n  const containerRef = useRef<HTMLDivElement>(null);\n  const canvasRef = useRef<HTMLCanvasElement>(null);\n\n  const [activeRings, setActiveRings] = useState(ringCount);\n  const [activeSpeed, setActiveSpeed] = useState(speed);\n  const [activeHue, setActiveHue] = useState(baseHue);\n  const [activeHueShift, setActiveHueShift] = useState(hueShift);\n  const [activeTwist, setActiveTwist] = useState(twist);\n  const pointerRef = useRef<{ x: number; y: number; active: boolean }>({\n    x: 0,\n    y: 0,\n    active: false,\n  });\n\n  useEffect(() => {\n    setActiveRings(ringCount);\n  }, [ringCount]);\n  useEffect(() => {\n    setActiveSpeed(speed);\n  }, [speed]);\n  useEffect(() => {\n    setActiveHue(baseHue);\n  }, [baseHue]);\n  useEffect(() => {\n    setActiveHueShift(hueShift);\n  }, [hueShift]);\n  useEffect(() => {\n    setActiveTwist(twist);\n  }, [twist]);\n\n  useEffect(() => {\n    const container = containerRef.current;\n    const canvas = canvasRef.current;\n    if (!container || !canvas) return;\n\n    const ctx = canvas.getContext(\"2d\");\n    if (!ctx) return;\n\n    let width = container.clientWidth || 800;\n    let height = container.clientHeight || 520;\n    let dpr = Math.min(window.devicePixelRatio || 1, 2);\n\n    const resize = () => {\n      if (!container || !canvas) return;\n      width = container.clientWidth || 800;\n      height = container.clientHeight || 520;\n      dpr = Math.min(window.devicePixelRatio || 1, 2);\n      canvas.width = Math.floor(width * dpr);\n      canvas.height = Math.floor(height * dpr);\n      ctx.setTransform(dpr, 0, 0, dpr, 0, 0);\n    };\n\n    resize();\n    const observer = new ResizeObserver(resize);\n    observer.observe(container);\n\n    // Relativistic star streaks warping along the curved spacetime walls\n    const starStreaks: RelativisticStarStreak[] = Array.from(\n      { length: 150 },\n      () => ({\n        angle: Math.random() * Math.PI * 2,\n        z: Math.random(),\n        speedOffset: 0.65 + Math.random() * 0.85,\n        hueOffset: (Math.random() - 0.5) * 45,\n        thickness: 0.8 + Math.random() * 1.8,\n        radialJitter: 0.88 + Math.random() * 0.28,\n      })\n    );\n\n    // Volumetric plasma nebula clouds spiraling along the manifold\n    const plasmaPuffs: PlasmaCloudPuff[] = Array.from({ length: 42 }, (_, i) => ({\n      angle: (i / 42) * Math.PI * 6,\n      z: i / 42,\n      sizeFactor: 0.42 + (i % 5) * 0.12,\n      hueShift: ((i % 7) - 3) * 14,\n      alpha: 0.08 + (i % 4) * 0.035,\n    }));\n\n    let rafId = 0;\n    let time = 0;\n    let smoothTargetX = 0;\n    let smoothTargetY = 0;\n\n    const numRings = Math.max(12, Math.min(60, activeRings));\n    const segments = 16;\n\n    const render = () => {\n      const dt = 0.008 * activeSpeed;\n      time += dt;\n\n      // Deep relativistic void with motion persistence\n      ctx.fillStyle = \"rgba(2, 4, 12, 0.34)\";\n      ctx.fillRect(0, 0, width, height);\n\n      const cx = width * 0.5;\n      const cy = height * 0.5;\n      const maxRadius = Math.hypot(width, height) * 0.68;\n\n      // Lissajous oscillation + interactive pointer steering for the throat\n      const lissajousX = Math.sin(time * 2.1) * (width * 0.11);\n      const lissajousY = Math.cos(time * 1.6) * (height * 0.09);\n\n      const targetX =\n        interactive && pointerRef.current.active\n          ? pointerRef.current.x * (width * 0.25)\n          : lissajousX;\n      const targetY =\n        interactive && pointerRef.current.active\n          ? pointerRef.current.y * (height * 0.22)\n          : lissajousY;\n\n      smoothTargetX += (targetX - smoothTargetX) * 0.06;\n      smoothTargetY += (targetY - smoothTargetY) * 0.06;\n\n      // Helper to compute curved 3D manifold center and radius at normalized depth zNorm (0 = throat, 1 = camera)\n      const sampleManifold = (zNorm: number) => {\n        // Hyperbolic spacetime funnel profile: narrow throat flaring exponentially\n        const scale = Math.pow(zNorm, 2.45);\n        const radius = 8 + scale * maxRadius;\n        const bendFactor = Math.pow(1 - zNorm, 1.48);\n        const waveWobbleX =\n          Math.sin(zNorm * Math.PI * 2.5 - time * 3.2) * 20 * bendFactor;\n        const waveWobbleY =\n          Math.cos(zNorm * Math.PI * 2.5 - time * 2.8) * 15 * bendFactor;\n\n        return {\n          x: cx + smoothTargetX * bendFactor + waveWobbleX,\n          y: cy + smoothTargetY * bendFactor + waveWobbleY,\n          radius,\n          rotation: time * 0.95 + (1 - zNorm) * activeTwist * Math.PI * 1.55,\n          hue: (activeHue + (1 - zNorm) * activeHueShift + 360) % 360,\n        };\n      };\n\n      // 1. Volumetric Spiraling Plasma Nebula Clouds (Depth-Sorted Back-to-Front)\n      ctx.save();\n      ctx.globalCompositeOperation = \"screen\";\n      for (let i = 0; i < plasmaPuffs.length; i++) {\n        const puff = plasmaPuffs[i];\n        const zNorm = (puff.z + time * 0.85) % 1;\n        const m = sampleManifold(zNorm);\n        const theta = puff.angle + m.rotation * 1.15;\n        const px = m.x + Math.cos(theta) * m.radius * 0.92;\n        const py = m.y + Math.sin(theta) * m.radius * 0.92;\n        const puffRadius = Math.max(18, m.radius * puff.sizeFactor);\n        const depthFade = Math.sin(zNorm * Math.PI);\n        const pHue = (m.hue + puff.hueShift + 360) % 360;\n\n        const nebGrad = ctx.createRadialGradient(\n          px,\n          py,\n          0,\n          px,\n          py,\n          puffRadius\n        );\n        nebGrad.addColorStop(\n          0,\n          `hsla(${pHue.toFixed(1)}, 95%, 65%, ${(\n            puff.alpha *\n            depthFade *\n            1.45\n          ).toFixed(3)})`\n        );\n        nebGrad.addColorStop(\n          0.48,\n          `hsla(${((pHue + 28) % 360).toFixed(1)}, 90%, 48%, ${(\n            puff.alpha *\n            depthFade *\n            0.65\n          ).toFixed(3)})`\n        );\n        nebGrad.addColorStop(1, \"rgba(0, 0, 0, 0)\");\n\n        ctx.fillStyle = nebGrad;\n        ctx.beginPath();\n        ctx.arc(px, py, puffRadius, 0, Math.PI * 2);\n        ctx.fill();\n      }\n      ctx.restore();\n\n      // 2. Curved Spacetime Manifold Geometry, Longitudinal Energy Filaments & Depth-Fog Occlusion\n      const ringVertices: Array<{\n        points: Array<{ x: number; y: number }>;\n        cx: number;\n        cy: number;\n        radius: number;\n        zNorm: number;\n        hue: number;\n        alpha: number;\n      }> = [];\n\n      const phase = (time * 1.45) % 1;\n\n      for (let i = 0; i < numRings; i++) {\n        const zNorm = (i + phase) / numRings;\n        const m = sampleManifold(zNorm);\n        // Depth fog attenuation near throat (zNorm -> 0) and smooth fade at camera clip (zNorm -> 1)\n        const alpha =\n          Math.sin(zNorm * Math.PI) * (0.14 + Math.pow(zNorm, 0.72) * 0.78);\n\n        const points: Array<{ x: number; y: number }> = [];\n        for (let s = 0; s < segments; s++) {\n          const theta = m.rotation + (s / segments) * Math.PI * 2;\n          const ripple =\n            1 + 0.045 * Math.sin(s * 4 + time * 4.5 + zNorm * 9);\n          points.push({\n            x: m.x + Math.cos(theta) * m.radius * ripple,\n            y: m.y + Math.sin(theta) * m.radius * ripple,\n          });\n        }\n\n        ringVertices.push({\n          points,\n          cx: m.x,\n          cy: m.y,\n          radius: m.radius,\n          zNorm,\n          hue: m.hue,\n          alpha,\n        });\n      }\n\n      // Draw volumetric depth-fog shadow rings + glowing plasma filaments from back to front\n      for (let i = 0; i < ringVertices.length - 1; i++) {\n        const curr = ringVertices[i];\n        const next = ringVertices[i + 1];\n\n        // Subtle dark depth-fog occlusion band between rings to give 3D tubular solidity\n        if (i % 2 === 0) {\n          ctx.save();\n          ctx.strokeStyle = `rgba(2, 4, 14, ${(\n            (1 - curr.zNorm) *\n            0.35\n          ).toFixed(3)})`;\n          ctx.lineWidth = Math.max(2, (next.radius - curr.radius) * 0.65);\n          ctx.beginPath();\n          ctx.arc(curr.cx, curr.cy, curr.radius, 0, Math.PI * 2);\n          ctx.stroke();\n          ctx.restore();\n        }\n\n        // Spiraling longitudinal plasma filaments connecting consecutive rings\n        ctx.save();\n        ctx.globalCompositeOperation = \"lighter\";\n        const ribAlpha = Math.min(curr.alpha, next.alpha) * 0.52;\n        ctx.strokeStyle = `hsla(${curr.hue.toFixed(1)}, 95%, 66%, ${ribAlpha.toFixed(3)})`;\n        ctx.lineWidth = 0.7 + curr.zNorm * 1.65;\n\n        ctx.beginPath();\n        for (let s = 0; s < segments; s++) {\n          const nextIdx = (s + 1) % segments; // Helical diagonal filament weave\n          ctx.moveTo(curr.points[s].x, curr.points[s].y);\n          ctx.lineTo(next.points[nextIdx].x, next.points[nextIdx].y);\n        }\n        ctx.stroke();\n        ctx.restore();\n      }\n\n      // Draw concentric curved energy rings with chromatic aberration near the throat\n      ctx.save();\n      ctx.globalCompositeOperation = \"lighter\";\n      for (let i = 0; i < ringVertices.length; i++) {\n        const ring = ringVertices[i];\n        const pts = ring.points;\n        const lw = 0.9 + Math.pow(ring.zNorm, 1.55) * 2.6;\n\n        const traceSmoothRing = (offsetX: number, offsetY: number) => {\n          ctx.beginPath();\n          for (let s = 0; s < segments; s++) {\n            const p0 = pts[s];\n            const p1 = pts[(s + 1) % segments];\n            const midX = (p0.x + p1.x) * 0.5 + offsetX;\n            const midY = (p0.y + p1.y) * 0.5 + offsetY;\n            if (s === 0) {\n              const prev = pts[segments - 1];\n              ctx.moveTo(\n                (prev.x + p0.x) * 0.5 + offsetX,\n                (prev.y + p0.y) * 0.5 + offsetY\n              );\n            }\n            ctx.quadraticCurveTo(p0.x + offsetX, p0.y + offsetY, midX, midY);\n          }\n          ctx.closePath();\n        };\n\n        // Relativistic chromatic aberration split (cyan vs magenta/red channel offset)\n        const chromaShift = (1 - ring.zNorm) * 3.2 + ring.zNorm * 1.4;\n        ctx.strokeStyle = `hsla(${((ring.hue - 32 + 360) % 360).toFixed(\n          1\n        )}, 100%, 62%, ${(ring.alpha * 0.42).toFixed(3)})`;\n        ctx.lineWidth = lw * 1.15;\n        traceSmoothRing(-chromaShift, 0);\n        ctx.stroke();\n\n        ctx.strokeStyle = `hsla(${((ring.hue + 32) % 360).toFixed(\n          1\n        )}, 100%, 62%, ${(ring.alpha * 0.42).toFixed(3)})`;\n        traceSmoothRing(chromaShift, 0);\n        ctx.stroke();\n\n        // Primary white-hot/tinted geodesic ring\n        ctx.strokeStyle = `hsla(${ring.hue.toFixed(1)}, 98%, 74%, ${ring.alpha.toFixed(3)})`;\n        ctx.lineWidth = lw;\n        traceSmoothRing(0, 0);\n        ctx.stroke();\n      }\n\n      // 3. Relativistic Star Streaks Warping Along the Tunnel Walls\n      for (let i = 0; i < starStreaks.length; i++) {\n        const st = starStreaks[i];\n        st.z += 0.011 * Math.max(0.15, activeSpeed) * st.speedOffset;\n        if (st.z >= 1) {\n          st.z = 0.02 + Math.random() * 0.08;\n          st.angle = Math.random() * Math.PI * 2;\n        }\n\n        const zTail = Math.max(0.01, st.z - (0.035 + st.z * 0.085) * Math.max(0.3, activeSpeed));\n        const mHead = sampleManifold(st.z);\n        const mTail = sampleManifold(zTail);\n\n        const aHead = st.angle + mHead.rotation * 0.85;\n        const aTail = st.angle + mTail.rotation * 0.85;\n\n        const hx = mHead.x + Math.cos(aHead) * mHead.radius * st.radialJitter;\n        const hy = mHead.y + Math.sin(aHead) * mHead.radius * st.radialJitter;\n        const tx = mTail.x + Math.cos(aTail) * mTail.radius * st.radialJitter;\n        const ty = mTail.y + Math.sin(aTail) * mTail.radius * st.radialJitter;\n\n        const streakAlpha = Math.sin(st.z * Math.PI) * 0.9;\n        const sHue = (mHead.hue + st.hueOffset + 360) % 360;\n\n        const sGrad = ctx.createLinearGradient(hx, hy, tx, ty);\n        sGrad.addColorStop(0, `rgba(255, 255, 255, ${streakAlpha.toFixed(3)})`);\n        sGrad.addColorStop(\n          0.35,\n          `hsla(${sHue.toFixed(1)}, 100%, 75%, ${(streakAlpha * 0.8).toFixed(3)})`\n        );\n        sGrad.addColorStop(1, \"rgba(0, 0, 0, 0)\");\n\n        ctx.strokeStyle = sGrad;\n        ctx.lineWidth = st.thickness * (0.5 + st.z * 1.4);\n        ctx.lineCap = \"round\";\n        ctx.beginPath();\n        ctx.moveTo(hx, hy);\n        ctx.lineTo(tx, ty);\n        ctx.stroke();\n      }\n\n      // 4. Vanishing Throat Gravitational Lensing Singularity & Chromatic Caustic Ring\n      const throat = sampleManifold(0.02);\n      const throatHue = (activeHue + activeHueShift) % 360;\n\n      // Outer lensing caustic halo\n      const outerThroatGlow = ctx.createRadialGradient(\n        throat.x,\n        throat.y,\n        4,\n        throat.x,\n        throat.y,\n        135\n      );\n      outerThroatGlow.addColorStop(0, \"rgba(255, 255, 255, 1)\");\n      outerThroatGlow.addColorStop(\n        0.16,\n        `hsla(${throatHue.toFixed(1)}, 100%, 78%, 0.85)`\n      );\n      outerThroatGlow.addColorStop(\n        0.42,\n        `hsla(${activeHue.toFixed(1)}, 95%, 58%, 0.35)`\n      );\n      outerThroatGlow.addColorStop(1, \"rgba(0, 0, 0, 0)\");\n\n      ctx.fillStyle = outerThroatGlow;\n      ctx.beginPath();\n      ctx.arc(throat.x, throat.y, 135, 0, Math.PI * 2);\n      ctx.fill();\n\n      // Dark event-horizon aperture pinprick inside the wormhole throat surrounded by an Einstein ring\n      ctx.globalCompositeOperation = \"source-over\";\n      ctx.fillStyle = \"#02030A\";\n      ctx.beginPath();\n      ctx.arc(throat.x, throat.y, 9, 0, Math.PI * 2);\n      ctx.fill();\n\n      ctx.globalCompositeOperation = \"lighter\";\n      ctx.strokeStyle = \"rgba(255, 255, 255, 0.92)\";\n      ctx.lineWidth = 1.8;\n      ctx.beginPath();\n      ctx.arc(throat.x, throat.y, 10.5, 0, Math.PI * 2);\n      ctx.stroke();\n\n      ctx.restore();\n\n      rafId = requestAnimationFrame(render);\n    };\n\n    ctx.fillStyle = \"#02040C\";\n    ctx.fillRect(0, 0, width, height);\n    rafId = requestAnimationFrame(render);\n\n    return () => {\n      cancelAnimationFrame(rafId);\n      observer.disconnect();\n    };\n  }, [activeRings, activeSpeed, activeHue, activeHueShift, activeTwist, interactive]);\n\n  const handlePointerMove = (e: React.PointerEvent<HTMLDivElement>) => {\n    if (!interactive || !containerRef.current) return;\n    const rect = containerRef.current.getBoundingClientRect();\n    const nx = ((e.clientX - rect.left) / rect.width - 0.5) * 2;\n    const ny = ((e.clientY - rect.top) / rect.height - 0.5) * 2;\n    pointerRef.current = { x: nx, y: ny, active: true };\n  };\n\n  const handlePointerLeave = () => {\n    pointerRef.current.active = false;\n  };\n\n  return (\n    <div\n      ref={containerRef}\n      data-fullscreen-scroll\n      onPointerMove={handlePointerMove}\n      onPointerLeave={handlePointerLeave}\n      className={cn(\n        \"relative w-full min-h-[520px] overflow-hidden rounded-2xl bg-[#02040C] text-white select-none\",\n        className\n      )}\n    >\n      <canvas\n        ref={canvasRef}\n        aria-hidden=\"true\"\n        className=\"pointer-events-none absolute inset-0 h-full w-full\"\n      />\n\n      {children && (\n        <div className=\"relative z-10 flex min-h-[520px] w-full flex-col\">\n          {children}\n        </div>\n      )}\n    </div>\n  );\n}\n\nexport default WormholeTunnel;\n",
          "type": "registry:ui",
          "target": "components/ui/wormhole-tunnel.tsx"
        },
        {
          "path": "lib/utils.ts",
          "content": "import { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...inputs: ClassValue[]) {\n  return twMerge(clsx(inputs));\n}\n\nexport async function copyToClipboard(text: string): Promise<boolean> {\n  if (typeof window === \"undefined\") return false;\n\n  try {\n    if (navigator.clipboard && window.isSecureContext) {\n      await navigator.clipboard.writeText(text);\n      return true;\n    }\n\n    const textArea = document.createElement(\"textarea\");\n    textArea.value = text;\n    textArea.style.position = \"fixed\";\n    textArea.style.left = \"-999999px\";\n    textArea.style.top = \"-999999px\";\n    document.body.appendChild(textArea);\n    textArea.focus();\n    textArea.select();\n    const succeeded = document.execCommand(\"copy\");\n    textArea.remove();\n    return succeeded;\n  } catch {\n    return false;\n  }\n}\n",
          "type": "registry:lib",
          "target": "lib/utils.ts"
        }
      ]
    }
  ]
}
