{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "card-motion",
  "title": "Motion card",
  "description": "Styled card: the Motion set. 5 decorative card variations (LiftCard, FadeCard, PopCard, SlideCard, RevealCard) on the ai2 token system, powered by framer-motion, reduced-motion aware and sized sm to xl. Part of the free styled layer.",
  "dependencies": [
    "motion@^12.42.2"
  ],
  "registryDependencies": [
    "@ai2/tokens"
  ],
  "files": [
    {
      "path": "registry/ai2/styled/card-motion.tsx",
      "content": "\"use client\"\n\nimport type * as React from \"react\"\nimport { motion, useReducedMotion } from \"motion/react\"\n\nimport { cn } from \"@/lib/utils\"\n\n/* Motion card family: 5 cards carrying an entry or hover motion. The surface is the same calm token card in every variant; the difference is in the motion alone (lift, fade, pop, slide, reveal). Every variant is turned off with useReducedMotion(): instead of moving, the card simply sits in its final state. Colour comes ONLY from semantic tokens, transparency through color-mix. size = the padding plus radius scale (the same as card-styled). */\n\nexport type StyledSize = \"sm\" | \"md\" | \"lg\" | \"xl\"\n\nconst radii: Record<StyledSize, string> = {\n  sm: \"rounded-lg\",\n  md: \"rounded-xl\",\n  lg: \"rounded-2xl\",\n  xl: \"rounded-2xl\",\n}\n\nconst pads: Record<StyledSize, string> = {\n  sm: \"p-4\",\n  md: \"p-5\",\n  lg: \"p-6\",\n  xl: \"p-8\",\n}\n\ntype Props = React.ComponentProps<\"div\"> & { size?: StyledSize }\n\nconst shell =\n  \"relative w-64 border border-border bg-card text-card-foreground shadow-[0_1px_2px_color-mix(in_oklab,var(--color-foreground)_10%,transparent)]\"\n\nconst spring = { type: \"spring\" as const, stiffness: 320, damping: 24 }\n\nconst defaultBody = (\n  <div className=\"flex flex-col gap-1\">\n    <span className=\"text-sm font-semibold text-foreground\">Card title</span>\n    <span className=\"text-xs leading-relaxed text-muted-foreground\">\n      A short description that shows how content sits inside the card.\n    </span>\n  </div>\n)\n\n/* Lift: the card rises on hover and its shadow grows. */\nexport function LiftCard({ className, size = \"md\", children, ...props }: Props) {\n  const reduce = useReducedMotion()\n  return (\n    <div data-slot=\"styled-card\" className={cn(\"relative\", className)} {...props}>\n      <motion.div\n        className={cn(\n          shell,\n          \"transition-shadow duration-(--motion-base) ease-(--motion-ease) hover:shadow-[0_18px_36px_-16px_color-mix(in_oklab,var(--color-foreground)_45%,transparent)] motion-reduce:transition-none\",\n          radii[size],\n          pads[size]\n        )}\n        whileHover={reduce ? undefined : { y: -6 }}\n        transition={spring}\n      >\n        {children ?? defaultBody}\n      </motion.div>\n    </div>\n  )\n}\n\n/* Fade: the card appears softly. Visible immediately under reduced-motion. */\nexport function FadeCard({ className, size = \"md\", children, ...props }: Props) {\n  const reduce = useReducedMotion()\n  return (\n    <div data-slot=\"styled-card\" className={cn(\"relative\", className)} {...props}>\n      <motion.div\n        className={cn(shell, radii[size], pads[size])}\n        initial={reduce ? false : { opacity: 0 }}\n        animate={{ opacity: 1 }}\n        transition={{ duration: 0.45, ease: \"easeOut\" }}\n      >\n        {children ?? defaultBody}\n      </motion.div>\n    </div>\n  )\n}\n\n/* Pop: the card enters growing with a spring and grows slightly further on hover. */\nexport function PopCard({ className, size = \"md\", children, ...props }: Props) {\n  const reduce = useReducedMotion()\n  return (\n    <div data-slot=\"styled-card\" className={cn(\"relative\", className)} {...props}>\n      <motion.div\n        className={cn(shell, radii[size], pads[size])}\n        initial={reduce ? false : { opacity: 0, scale: 0.9 }}\n        animate={{ opacity: 1, scale: 1 }}\n        whileHover={reduce ? undefined : { scale: 1.03 }}\n        transition={spring}\n      >\n        {children ?? defaultBody}\n      </motion.div>\n    </div>\n  )\n}\n\n/* Slide: kart soldan kayarak girer. */\nexport function SlideCard({ className, size = \"md\", children, ...props }: Props) {\n  const reduce = useReducedMotion()\n  return (\n    <div data-slot=\"styled-card\" className={cn(\"relative\", className)} {...props}>\n      <motion.div\n        className={cn(shell, radii[size], pads[size])}\n        initial={reduce ? false : { opacity: 0, x: -28 }}\n        animate={{ opacity: 1, x: 0 }}\n        transition={{ duration: 0.4, ease: \"easeOut\" }}\n      >\n        {children ?? defaultBody}\n      </motion.div>\n    </div>\n  )\n}\n\n/* Reveal: the content emerges through a clip-path as if opening from the top down. No clipping under reduced-motion, the content is fully visible. */\nexport function RevealCard({ className, size = \"md\", children, ...props }: Props) {\n  const reduce = useReducedMotion()\n  return (\n    <div data-slot=\"styled-card\" className={cn(\"relative\", className)} {...props}>\n      <motion.div\n        className={cn(shell, \"overflow-hidden\", radii[size], pads[size])}\n        initial={reduce ? false : { clipPath: \"inset(0 0 100% 0)\", opacity: 0 }}\n        animate={{ clipPath: \"inset(0 0 0% 0)\", opacity: 1 }}\n        transition={{ duration: 0.5, ease: \"easeOut\" }}\n      >\n        {children ?? defaultBody}\n      </motion.div>\n    </div>\n  )\n}\n",
      "type": "registry:component",
      "target": "components/ui/card-motion.tsx"
    }
  ],
  "categories": [
    "styled",
    "card"
  ],
  "type": "registry:component"
}