{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "floating-card",
  "title": "Floating Card",
  "author": "mrap10",
  "description": "Card with 3D tilt, text-reveal and image focus effects on hover.",
  "dependencies": ["motion"],
  "files": [
    {
      "path": "registry/default/cards/floating-card.tsx",
      "content": "\"use client\";\n\nimport { motion, useMotionValue, useSpring, useTransform } from \"motion/react\";\nimport { cn } from \"@/lib/utils\";\nimport { useRef, useState } from \"react\";\n\nconst DEFAULT_CARD = {\n  image:\n    \"https://images.unsplash.com/photo-1531746020798-e6953c6e8e04?w=400&q=80\",\n  name: \"Priya Nair\",\n  description: \"Design Lead\",\n};\n\nconst EASE: [number, number, number, number] = [0.22, 1, 0.36, 1];\nconst SPRING = { stiffness: 180, damping: 22, mass: 0.5 };\n\ntype FloatingCardProps = {\n  image?: string;\n  name?: string;\n  description?: string;\n  index?: number;\n  className?: string;\n};\n\nexport function FloatingCard({\n  image = DEFAULT_CARD.image,\n  name = DEFAULT_CARD.name,\n  description = DEFAULT_CARD.description,\n  index = 0,\n  className,\n}: FloatingCardProps) {\n  const [hovered, setHovered] = useState(false);\n  const cardRef = useRef<HTMLDivElement>(null);\n\n  const rawX = useMotionValue(0);\n  const rawY = useMotionValue(0);\n  const rotateX = useSpring(useTransform(rawY, [-0.5, 0.5], [6, -6]), SPRING);\n  const rotateY = useSpring(useTransform(rawX, [-0.5, 0.5], [-6, 6]), SPRING);\n\n  const handleMouseMove = (e: React.MouseEvent<HTMLDivElement>) => {\n    const rect = cardRef.current?.getBoundingClientRect();\n    if (!rect) return;\n    rawX.set((e.clientX - rect.left) / rect.width - 0.5);\n    rawY.set((e.clientY - rect.top) / rect.height - 0.5);\n  };\n\n  const handleMouseLeave = () => {\n    rawX.set(0);\n    rawY.set(0);\n    setHovered(false);\n  };\n\n  return (\n    <motion.div\n      ref={cardRef}\n      onMouseMove={handleMouseMove}\n      onMouseEnter={() => setHovered(true)}\n      onMouseLeave={handleMouseLeave}\n      style={{ rotateX, rotateY, transformPerspective: 900 }}\n      initial={{ opacity: 0, y: 24 }}\n      animate={{ opacity: 1, y: 0 }}\n      transition={{ duration: 0.55, delay: index * 0.1, ease: EASE }}\n      className={cn(\n        \"group relative h-88 w-72 overflow-hidden rounded-2xl border border-black/10 bg-neutral-100 font-sans shadow-[0_2px_12px_rgba(0,0,0,0.08)] select-none dark:border-white/10 dark:bg-neutral-900 dark:shadow-[0_2px_20px_rgba(0,0,0,0.45)]\",\n        className\n      )}\n    >\n      <motion.img\n        src={image}\n        alt={name}\n        animate={{ scale: hovered ? 1.06 : 1 }}\n        transition={{ duration: 0.5, ease: EASE }}\n        className=\"block h-full w-full object-cover md:grayscale-100 md:group-hover:grayscale-0\"\n      />\n\n      {/* Vignette (always visible, deepens on hover) */}\n      <motion.div\n        animate={{ opacity: hovered ? 1 : 0.35 }}\n        transition={{ duration: 0.4, ease: EASE }}\n        className=\"pointer-events-none absolute inset-0 hidden bg-linear-to-t from-black/80 via-black/20 to-transparent md:block\"\n      />\n      <div className=\"pointer-events-none absolute inset-0 block bg-linear-to-t from-black/80 via-black/20 to-transparent md:hidden\" />\n\n      <CornerBracket hovered={hovered} className=\"absolute top-4 right-4\" />\n      <CornerBracket\n        hovered={hovered}\n        className=\"absolute top-4 left-4 -scale-x-100\"\n      />\n\n      {/* Text overlay */}\n      <div className=\"absolute right-0 bottom-0 left-0 block px-5 pt-10 pb-5 md:hidden\">\n        <p className=\"text-lg font-semibold text-white\">{name}</p>\n        <div className=\"my-2 h-0.75 rounded-full bg-white/25\" />\n        <p className=\"text-sm leading-relaxed tracking-wide text-white/60\">\n          {description}\n        </p>\n      </div>\n\n      <motion.div\n        initial={false}\n        animate={hovered ? { y: 0 } : { y: \"100%\" }}\n        transition={{ duration: 0.38, ease: EASE }}\n        className=\"absolute right-0 bottom-0 left-0 hidden px-5 pt-10 pb-5 md:block\"\n      >\n        <motion.p\n          initial={false}\n          animate={hovered ? { y: 0, opacity: 1 } : { y: 10, opacity: 0 }}\n          transition={{ duration: 0.32, delay: hovered ? 0.05 : 0, ease: EASE }}\n          className=\"text-lg font-semibold text-white\"\n        >\n          {name}\n        </motion.p>\n\n        <motion.div\n          initial={false}\n          animate={\n            hovered ? { scaleX: 1, opacity: 1 } : { scaleX: 0, opacity: 0 }\n          }\n          transition={{ duration: 0.3, delay: hovered ? 0.1 : 0, ease: EASE }}\n          style={{ originX: 0 }}\n          className=\"my-2 h-0.75 rounded-full bg-white/25\"\n        />\n\n        <motion.p\n          initial={false}\n          animate={hovered ? { y: 0, opacity: 1 } : { y: 10, opacity: 0 }}\n          transition={{ duration: 0.32, delay: hovered ? 0.14 : 0, ease: EASE }}\n          className=\"text-sm leading-relaxed tracking-wide text-white/60\"\n        >\n          {description}\n        </motion.p>\n      </motion.div>\n\n      {/* Accent line (bottom) */}\n      <motion.div\n        initial={false}\n        animate={\n          hovered ? { scaleX: 1, opacity: 1 } : { scaleX: 0, opacity: 0 }\n        }\n        transition={{ duration: 0.4, delay: hovered ? 0.02 : 0, ease: EASE }}\n        style={{ originX: 0 }}\n        className=\"absolute right-0 bottom-0 left-0 h-0.75 bg-white/40 dark:bg-white/20\"\n      />\n    </motion.div>\n  );\n}\n\nfunction CornerBracket({\n  hovered,\n  className,\n}: {\n  hovered: boolean;\n  className?: string;\n}) {\n  return (\n    <motion.svg\n      initial={false}\n      animate={\n        hovered ? { opacity: 0.5, scale: 1 } : { opacity: 0, scale: 0.85 }\n      }\n      transition={{ duration: 0.3, ease: EASE }}\n      width=\"18\"\n      height=\"18\"\n      viewBox=\"0 0 18 18\"\n      fill=\"none\"\n      className={className}\n    >\n      <path\n        d=\"M18 0 H10 M18 0 V8\"\n        stroke=\"white\"\n        strokeWidth=\"2.5\"\n        strokeLinecap=\"round\"\n      />\n    </motion.svg>\n  );\n}\n",
      "type": "registry:component"
    }
  ],
  "categories": ["cards"],
  "type": "registry:component"
}
