{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "card-stack",
  "title": "Card Stack",
  "description": "Layered testimonial cards that cycle forward with a spring stack. Click the front card to advance.",
  "dependencies": [
    "framer-motion"
  ],
  "files": [
    {
      "path": "components/cards/CardStack.tsx",
      "content": "'use client';\n\nimport { useEffect, useState } from 'react';\nimport { motion, useReducedMotion } from 'framer-motion';\n\ntype CardStackItem = {\n  id?: string;\n  name?: string;\n  role?: string;\n  quote?: string;\n  accent?: string;\n};\n\ntype CardStackProps = {\n  items?: CardStackItem[];\n  interval?: number;\n  className?: string;\n};\n\nconst DEFAULT_ITEMS: CardStackItem[] = [\n  {\n    id: 'novak',\n    name: 'Amelia Novak',\n    role: 'Head of Product, Northline',\n    quote: 'The stack feels like a product, not a kit. We shipped the landing page in an afternoon.',\n    accent: '#4F46E5',\n  },\n  {\n    id: 'reed',\n    name: 'Jonah Reed',\n    role: 'Founder, Softsignal',\n    quote: 'Quiet motion, clear hierarchy. Customers notice the craft without us having to explain it.',\n    accent: '#0D9488',\n  },\n  {\n    id: 'park',\n    name: 'Hana Park',\n    role: 'Design Lead, Lattice & Co',\n    quote: 'Copy, paste, tune. That is the whole workflow. Our team actually enjoys the frontend now.',\n    accent: '#C026D3',\n  },\n];\n\nexport default function CardStack({\n  items = DEFAULT_ITEMS,\n  interval = 4200,\n  className = '',\n}: CardStackProps) {\n  const list = items.length ? items : DEFAULT_ITEMS;\n  const [active, setActive] = useState(0);\n  const reduceMotion = useReducedMotion();\n\n  useEffect(() => {\n    if (list.length < 2 || reduceMotion) return;\n    const id = window.setInterval(() => {\n      setActive((current) => (current + 1) % list.length);\n    }, interval);\n    return () => window.clearInterval(id);\n  }, [interval, list.length, reduceMotion]);\n\n  function advance() {\n    setActive((current) => (current + 1) % list.length);\n  }\n\n  return (\n    <div\n      className={['relative mx-auto h-[280px] w-full max-w-[340px]', className]\n        .filter(Boolean)\n        .join(' ')}\n    >\n      {list.map((item, index) => {\n        const stackIndex = (index - active + list.length) % list.length;\n        if (stackIndex > 2) return null;\n\n        const isFront = stackIndex === 0;\n\n        return (\n          <motion.article\n            key={item.id ?? `${item.name}-${index}`}\n            className={[\n              'absolute inset-x-0 top-0 rounded-[var(--radius-2xl,1rem)] border border-[color:var(--color-border,#e5e7eb)] bg-[var(--color-card,#fff)] p-6 shadow-sm',\n              isFront ? 'cursor-pointer' : 'pointer-events-none',\n            ].join(' ')}\n            style={{\n              transformOrigin: 'center top',\n              zIndex: list.length - stackIndex,\n            }}\n            animate={{\n              y: stackIndex * 14,\n              scale: 1 - stackIndex * 0.05,\n              rotate: stackIndex === 0 ? 0 : stackIndex % 2 === 0 ? 2.4 : -2.4,\n              opacity: 1 - stackIndex * 0.12,\n            }}\n            transition={\n              reduceMotion\n                ? { duration: 0 }\n                : { type: 'spring', stiffness: 260, damping: 28 }\n            }\n            onClick={isFront ? advance : undefined}\n            tabIndex={isFront ? 0 : -1}\n            onKeyDown={\n              isFront\n                ? (event) => {\n                  if (event.key === 'Enter' || event.key === ' ') {\n                    event.preventDefault();\n                    advance();\n                  }\n                }\n                : undefined\n            }\n          >\n            <span\n              className='mb-4 block h-1 w-10 rounded-full'\n              style={{ backgroundColor: item.accent ?? '#4F46E5' }}\n              aria-hidden\n            />\n            <p className='text-[15px] leading-6 text-[color:var(--color-card-foreground,#374151)]'>{item.quote}</p>\n            <div className='mt-6 flex items-center gap-3'>\n              <span\n                className='flex h-9 w-9 items-center justify-center rounded-full text-xs font-semibold text-white'\n                style={{ backgroundColor: item.accent ?? '#4F46E5' }}\n                aria-hidden\n              >\n                {(item.name ?? 'A')\n                  .split(' ')\n                  .map((part) => part[0])\n                  .slice(0, 2)\n                  .join('')}\n              </span>\n              <div>\n                <p className='text-sm font-semibold text-[color:var(--color-card-foreground,#111827)]'>{item.name}</p>\n                <p className='text-xs text-[color:var(--color-muted-foreground,#6b7280)]'>{item.role}</p>\n              </div>\n            </div>\n          </motion.article>\n        );\n      })}\n    </div>\n  );\n}\n",
      "type": "registry:component",
      "target": "@components/cards/CardStack.tsx"
    }
  ],
  "categories": [
    "cards"
  ],
  "type": "registry:component"
}