{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "ds-tilt-card",
  "title": "Tilt Card",
  "description": "Card 3D com tilt no mousemove, glare radial e fallback prefers-reduced-motion — inspirado em Aceternity 3D Card + Wobble Card.",
  "dependencies": [
    "class-variance-authority"
  ],
  "registryDependencies": [
    "@lema-ds/card",
    "@lema-ds/skeleton"
  ],
  "files": [
    {
      "path": "components/ds/ds-tilt-card.tsx",
      "content": "\"use client\"\n\nimport * as React from \"react\"\nimport { cva, type VariantProps } from \"class-variance-authority\"\n\nimport { cn } from \"@/lib/utils\"\nimport { Card } from \"@/components/ui/card\"\nimport { Skeleton } from \"@/components/ui/skeleton\"\n\n// ── Types ──\n\nexport interface TiltCardProps\n  extends\n    React.HTMLAttributes<HTMLDivElement>,\n    VariantProps<typeof tiltCardVariants> {\n  glare?: boolean\n  intensity?: number\n  scaleOnHover?: boolean\n  loading?: boolean\n}\n\n// ── Variants ──\n\nexport const tiltCardVariants = cva(\n  \"relative flex flex-col overflow-hidden transition-shadow duration-200 hover:will-change-transform motion-reduce:transform-none motion-reduce:transition-none\",\n  {\n    variants: {\n      variant: {\n        default: \"border bg-card text-card-foreground shadow-sm\",\n        muted: \"border-border/60 bg-muted/40 text-foreground\",\n        ghost: \"border-transparent bg-transparent shadow-none\",\n      },\n      radius: {\n        sm: \"rounded-sm\",\n        md: \"rounded-lg\",\n        lg: \"rounded-xl\",\n        xl: \"rounded-2xl\",\n      },\n    },\n    defaultVariants: {\n      variant: \"default\",\n      radius: \"xl\",\n    },\n  }\n)\n\n// ── Component ──\n\nexport function TiltCard({\n  className,\n  variant = \"default\",\n  radius = \"xl\",\n  glare = true,\n  intensity = 12,\n  scaleOnHover = true,\n  loading = false,\n  children,\n  onMouseMove,\n  onMouseLeave,\n  ...props\n}: TiltCardProps) {\n  const ref = React.useRef<HTMLDivElement>(null)\n  const glareRef = React.useRef<HTMLDivElement>(null)\n  const reduceMotion =\n    typeof window !== \"undefined\" &&\n    window.matchMedia?.(\"(prefers-reduced-motion: reduce)\").matches\n\n  const handleMove = (e: React.MouseEvent<HTMLDivElement>) => {\n    onMouseMove?.(e)\n    if (reduceMotion || !ref.current) return\n    ref.current.style.willChange = \"transform\"\n    const rect = ref.current.getBoundingClientRect()\n    const x = e.clientX - rect.left\n    const y = e.clientY - rect.top\n    const midX = rect.width / 2\n    const midY = rect.height / 2\n    const rotateY = ((x - midX) / midX) * intensity\n    const rotateX = ((midY - y) / midY) * intensity\n    ref.current.style.transform = `perspective(900px) rotateX(${rotateX}deg) rotateY(${rotateY}deg) ${scaleOnHover ? \"scale3d(1.02,1.02,1.02)\" : \"\"}`\n    if (glareRef.current) {\n      glareRef.current.style.background = `radial-gradient(circle at ${x}px ${y}px, hsl(var(--foreground) / 0.08), transparent 55%)`\n      glareRef.current.style.opacity = \"1\"\n    }\n  }\n\n  const handleLeave = (e: React.MouseEvent<HTMLDivElement>) => {\n    onMouseLeave?.(e)\n    if (!ref.current) return\n    ref.current.style.willChange = \"auto\"\n    ref.current.style.transform =\n      \"perspective(900px) rotateX(0deg) rotateY(0deg) scale3d(1,1,1)\"\n    if (glareRef.current) glareRef.current.style.opacity = \"0\"\n  }\n\n  if (loading) {\n    return (\n      <div\n        data-slot=\"tilt-card-skeleton\"\n        className={cn(tiltCardVariants({ variant, radius }), \"p-6\", className)}\n        {...props}\n      >\n        <Skeleton className=\"h-5 w-32\" />\n        <Skeleton className=\"mt-3 h-4 w-full\" />\n        <Skeleton className=\"mt-2 h-4 w-3/4\" />\n        <Skeleton className=\"mt-6 h-9 w-28 rounded-full\" />\n      </div>\n    )\n  }\n\n  return (\n    <Card\n      ref={ref}\n      data-slot=\"tilt-card\"\n      tabIndex={0}\n      role=\"group\"\n      aria-label=\"Card with 3D effect\"\n      onMouseMove={handleMove}\n      onMouseLeave={handleLeave}\n      onFocus={() => {\n        if (ref.current && !reduceMotion) {\n          ref.current.style.willChange = \"transform\"\n          ref.current.style.transform =\n            \"perspective(900px) rotateX(2deg) rotateY(-2deg) scale3d(1.01,1.01,1.01)\"\n        }\n      }}\n      onBlur={handleLeave as unknown as React.FocusEventHandler<HTMLDivElement>}\n      className={cn(\n        tiltCardVariants({ variant, radius }),\n        \"focus-visible:ring-2 focus-visible:ring-ring focus-visible:outline-none\",\n        className\n      )}\n      {...props}\n    >\n      {glare && (\n        <div\n          ref={glareRef}\n          aria-hidden=\"true\"\n          className=\"pointer-events-none absolute inset-0 rounded-[inherit] opacity-0 transition-opacity duration-200\"\n        />\n      )}\n      <div className=\"relative z-10 flex flex-1 flex-col\">{children}</div>\n    </Card>\n  )\n}\n",
      "type": "registry:ui"
    }
  ],
  "type": "registry:ui"
}
