{
  "name": "spotlight-cards",
  "type": "registry:component",
  "dependencies": [
    "motion",
    "lucide-react"
  ],
  "files": [
    {
      "type": "registry:component",
      "content": "\"use client\";\n\n/**\n * @author dorianbaffier\n * @description Feature grid with aurora ambient, magnetic 3D tilt, and focus-dim siblings.\n * @version 2.0.0\n * @date 2025-02-20\n * @license MIT\n * @website https://kokonutui.com\n * @github https://github.com/kokonut-labs/kokonutui\n */\n\nimport type { LucideIcon } from \"lucide-react\";\nimport { Cloud, Code, Cpu, Globe, Lock, Zap } from \"lucide-react\";\nimport { motion, useMotionValue, useSpring, useTransform } from \"motion/react\";\nimport { useRef, useState } from \"react\";\nimport { cn } from \"@/lib/utils\";\n\n// ─── Constants ──────────────────────────────────────────────────────────────────\n\nconst TILT_MAX = 9;\nconst TILT_SPRING = { stiffness: 300, damping: 28 } as const;\nconst GLOW_SPRING = { stiffness: 180, damping: 22 } as const;\n\n// ─── Data ────────────────────────────────────────────────────────────────────────\n\nexport interface SpotlightItem {\n  icon: LucideIcon;\n  title: string;\n  description: string;\n  color: string;\n}\n\nconst DEFAULT_ITEMS: SpotlightItem[] = [\n  {\n    icon: Zap,\n    title: \"Instant\",\n    description:\n      \"Sub-100ms latency on every request, globally distributed across every region.\",\n    color: \"#f59e0b\",\n  },\n  {\n    icon: Lock,\n    title: \"Secure\",\n    description:\n      \"Zero-trust by default. SOC 2 certified with end-to-end encryption throughout.\",\n    color: \"#60a5fa\",\n  },\n  {\n    icon: Globe,\n    title: \"Global\",\n    description:\n      \"Edge-deployed to 300+ locations. Your users always hit a nearby server.\",\n    color: \"#34d399\",\n  },\n  {\n    icon: Code,\n    title: \"Developer first\",\n    description:\n      \"Type-safe SDKs in five languages, a complete REST API, and honest docs.\",\n    color: \"#a78bfa\",\n  },\n  {\n    icon: Cpu,\n    title: \"Scalable\",\n    description:\n      \"From side project to Series B without touching your infrastructure config.\",\n    color: \"#38bdf8\",\n  },\n  {\n    icon: Cloud,\n    title: \"Serverless\",\n    description:\n      \"No servers to provision, patch, or babysit. Just deploy and move on.\",\n    color: \"#f472b6\",\n  },\n];\n\n// ─── Card ────────────────────────────────────────────────────────────────────────\n\ninterface CardProps {\n  item: SpotlightItem;\n  dimmed: boolean;\n  onHoverStart: () => void;\n  onHoverEnd: () => void;\n}\n\nfunction Card({ item, dimmed, onHoverStart, onHoverEnd }: CardProps) {\n  const Icon = item.icon;\n  const cardRef = useRef<HTMLDivElement>(null);\n\n  const normX = useMotionValue(0.5);\n  const normY = useMotionValue(0.5);\n\n  const rawRotateX = useTransform(normY, [0, 1], [TILT_MAX, -TILT_MAX]);\n  const rawRotateY = useTransform(normX, [0, 1], [-TILT_MAX, TILT_MAX]);\n\n  const rotateX = useSpring(rawRotateX, TILT_SPRING);\n  const rotateY = useSpring(rawRotateY, TILT_SPRING);\n  const glowOpacity = useSpring(0, GLOW_SPRING);\n\n  const handleMouseMove = (e: React.MouseEvent<HTMLDivElement>) => {\n    const el = cardRef.current;\n    if (!el) {\n      return;\n    }\n    const rect = el.getBoundingClientRect();\n    normX.set((e.clientX - rect.left) / rect.width);\n    normY.set((e.clientY - rect.top) / rect.height);\n  };\n\n  const handleMouseEnter = () => {\n    glowOpacity.set(1);\n    onHoverStart();\n  };\n\n  const handleMouseLeave = () => {\n    normX.set(0.5);\n    normY.set(0.5);\n    glowOpacity.set(0);\n    onHoverEnd();\n  };\n\n  return (\n    <motion.div\n      animate={{\n        scale: dimmed ? 0.96 : 1,\n        opacity: dimmed ? 0.5 : 1,\n      }}\n      className={cn(\n        \"group relative flex flex-col gap-5 overflow-hidden rounded-2xl border p-6\",\n        // Light\n        \"border-zinc-200 bg-white shadow-[0_2px_8px_rgba(0,0,0,0.04)]\",\n        // Dark\n        \"dark:border-white/6 dark:bg-white/3 dark:shadow-none\",\n        \"transition-[border-color] duration-300\",\n        \"hover:border-zinc-300 dark:hover:border-white/14\"\n      )}\n      onMouseEnter={handleMouseEnter}\n      onMouseLeave={handleMouseLeave}\n      onMouseMove={handleMouseMove}\n      ref={cardRef}\n      style={{\n        rotateX,\n        rotateY,\n        transformPerspective: 900,\n      }}\n      transition={{ duration: 0.18, ease: \"easeOut\" }}\n    >\n      {/* Static accent tint — always visible */}\n      <div\n        aria-hidden=\"true\"\n        className=\"pointer-events-none absolute inset-0 rounded-2xl\"\n        style={{\n          background: `radial-gradient(ellipse at 20% 20%, ${item.color}14, transparent 65%)`,\n        }}\n      />\n\n      {/* Hover glow layer */}\n      <motion.div\n        aria-hidden=\"true\"\n        className=\"pointer-events-none absolute inset-0 rounded-2xl\"\n        style={{\n          opacity: glowOpacity,\n          background: `radial-gradient(ellipse at 20% 20%, ${item.color}2e, transparent 65%)`,\n        }}\n      />\n\n      {/* Shimmer sweep */}\n      <div\n        aria-hidden=\"true\"\n        className=\"pointer-events-none absolute inset-y-0 left-0 w-[55%] -translate-x-full -skew-x-12 bg-linear-to-r from-transparent via-white/4.5 to-transparent transition-transform duration-700 ease-out group-hover:translate-x-[280%]\"\n      />\n\n      {/* Icon badge */}\n      <div\n        className=\"relative z-10 flex h-10 w-10 items-center justify-center rounded-xl\"\n        style={{\n          background: `${item.color}18`,\n          boxShadow: `inset 0 0 0 1px ${item.color}30`,\n        }}\n      >\n        <Icon size={17} strokeWidth={1.9} style={{ color: item.color }} />\n      </div>\n\n      {/* Text */}\n      <div className=\"relative z-10 flex flex-col gap-2\">\n        <h3 className=\"font-semibold text-[14px] text-zinc-900 tracking-tight dark:text-white\">\n          {item.title}\n        </h3>\n        <p className=\"text-[12.5px] text-zinc-500 leading-relaxed dark:text-white/40\">\n          {item.description}\n        </p>\n      </div>\n\n      {/* Accent bottom line */}\n      <div\n        aria-hidden=\"true\"\n        className=\"absolute bottom-0 left-0 h-[2px] w-0 rounded-full transition-all duration-500 group-hover:w-full\"\n        style={{\n          background: `linear-gradient(to right, ${item.color}80, transparent)`,\n        }}\n      />\n    </motion.div>\n  );\n}\n\nCard.displayName = \"Card\";\n\n// ─── Main export ──────────────────────────────────────────────────────────────────\n\nexport interface SpotlightCardsProps {\n  items?: SpotlightItem[];\n  eyebrow?: string;\n  heading?: string;\n  className?: string;\n}\n\nexport default function SpotlightCards({\n  items = DEFAULT_ITEMS,\n  eyebrow = \"Features\",\n  heading = \"Everything you need\",\n  className,\n}: SpotlightCardsProps) {\n  const [hoveredTitle, setHoveredTitle] = useState<string | null>(null);\n\n  return (\n    <div\n      className={cn(\n        \"relative w-full overflow-hidden rounded-2xl px-8 pt-9 pb-10\",\n        \"bg-white dark:bg-[#06060f]\",\n        className\n      )}\n    >\n      {/* Dot grid — light mode only */}\n      <div\n        aria-hidden=\"true\"\n        className=\"pointer-events-none absolute inset-0 dark:hidden\"\n        style={{\n          backgroundImage:\n            \"radial-gradient(circle, rgba(0,0,0,0.055) 1px, transparent 1px)\",\n          backgroundSize: \"22px 22px\",\n        }}\n      />\n\n      {/* Header */}\n      <div className=\"relative mb-8 flex flex-col gap-1.5\">\n        <p className=\"font-semibold text-[10px] text-indigo-600 uppercase tracking-[0.22em] dark:text-indigo-400/80\">\n          {eyebrow}\n        </p>\n        <h2 className=\"font-semibold text-[22px] text-zinc-900 tracking-tight dark:text-white\">\n          {heading}\n        </h2>\n      </div>\n\n      {/* Card grid */}\n      <div className=\"relative grid grid-cols-2 gap-3 sm:grid-cols-3\">\n        {items.map((item) => (\n          <Card\n            dimmed={hoveredTitle !== null && hoveredTitle !== item.title}\n            item={item}\n            key={item.title}\n            onHoverEnd={() => setHoveredTitle(null)}\n            onHoverStart={() => setHoveredTitle(item.title)}\n          />\n        ))}\n      </div>\n    </div>\n  );\n}\n",
      "path": "/components/kokonutui/spotlight-cards.tsx",
      "target": "components/kokonutui/spotlight-cards.tsx"
    }
  ]
}