{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "flip-card",
  "title": "Flip Card",
  "description": "A book-style flip card with a spine tab that reveals on hover.",
  "dependencies": [
    "lucide-react"
  ],
  "registryDependencies": [
    "utils"
  ],
  "files": [
    {
      "path": "components/library/flip-card.tsx",
      "content": "\"use client\"\n\nimport { BookOpenIcon, type LucideIcon } from \"lucide-react\"\nimport { cn } from \"@/lib/utils\"\nimport { forwardRef, type ReactNode, type KeyboardEvent } from \"react\"\n\ntype SizePreset = \"sm\" | \"md\" | \"lg\" | \"xl\"\n\ninterface SizeTokens {\n    /** Tailwind width class for the card */\n    width: string\n    /** Tailwind height class for the card */\n    height: string\n    /** Tailwind text-size class for the title */\n    titleText: string\n    /** Tailwind text-size class for the label */\n    labelText: string\n    /** Tailwind padding class for the inner content */\n    padding: string\n    /** Tailwind w/h classes for the label icon */\n    iconSize: string\n    /** Tailwind text class for the spine text */\n    spineTextSize: string\n    /** Tailwind gap for label row */\n    labelGap: string\n    /** Tailwind margin-bottom for label row */\n    labelMb: string\n}\n\nconst SIZE_MAP: Record<SizePreset, SizeTokens> = {\n    sm: {\n        width: \"w-48\",\n        height: \"h-64\",\n        titleText: \"text-xl\",\n        labelText: \"text-[11px]\",\n        padding: \"p-3\",\n        iconSize: \"w-3.5 h-3.5\",\n        spineTextSize: \"text-[10px]\",\n        labelGap: \"gap-1\",\n        labelMb: \"mb-2\",\n    },\n    md: {\n        width: \"w-60\",\n        height: \"h-80\",\n        titleText: \"text-2xl\",\n        labelText: \"text-xs\",\n        padding: \"p-4\",\n        iconSize: \"w-3.5 h-3.5\",\n        spineTextSize: \"text-xs\",\n        labelGap: \"gap-1.5\",\n        labelMb: \"mb-2.5\",\n    },\n    lg: {\n        width: \"w-72\",\n        height: \"h-100\",\n        titleText: \"text-3xl\",\n        labelText: \"text-xs\",\n        padding: \"p-5\",\n        iconSize: \"w-4 h-4\",\n        spineTextSize: \"text-sm\",\n        labelGap: \"gap-1.5\",\n        labelMb: \"mb-3\",\n    },\n    xl: {\n        width: \"w-80\",\n        height: \"h-[28rem]\",\n        titleText: \"text-4xl\",\n        labelText: \"text-xs\",\n        padding: \"p-6\",\n        iconSize: \"w-5 h-5\",\n        spineTextSize: \"text-sm\",\n        labelGap: \"gap-2\",\n        labelMb: \"mb-4\",\n    },\n}\n\n\ninterface FlipCardProps {\n    /** Label text shown above the title */\n    label?: string\n    /** Icon component rendered next to the label */\n    icon?: LucideIcon\n    /** Main title / heading content */\n    title?: ReactNode\n    /** Text on the spine tab revealed on hover */\n    spineText?: string\n    /** Accent color preset or custom Tailwind classes — presets: \"red\" | \"blue\" | \"green\" | \"purple\" | \"orange\" | \"amber\" | \"teal\" */\n    accentColor?: string\n    /** Additional className applied to the root container */\n    className?: string\n    /** Callback fired when the card is clicked */\n    onClick?: () => void\n    /**\n     * Size preset that controls card dimensions, text, padding, and spine proportionally.\n     * @default \"lg\"\n     */\n    size?: SizePreset\n    /** Optional debug label shown on the shadow layer */\n    shadowLabel?: string\n}\n\nconst ACCENT_BG: Record<string, string> = {\n    red: \"bg-[#b1121f]\",\n    blue: \"bg-[#0077b6]\",\n    green: \"bg-green-600\",\n    purple: \"bg-[#59168b]\",\n    orange: \"bg-orange-600\",\n    amber: \"bg-amber-600\",\n    teal: \"bg-teal-600\",\n} as const\n\nconst ACCENT_TEXT: Record<string, string> = {\n    red: \"text-red-700\",\n    blue: \"text-sky-700\",\n    green: \"text-green-700\",\n    purple: \"text-fuchsia-700\",\n    orange: \"text-orange-700\",\n    amber: \"text-amber-700\",\n    teal: \"text-teal-700\",\n} as const\n\nconst DEFAULT_TITLE = (\n    <>\n        Build a scalable Component Library that cut development time by{\" \"}\n        <span className=\"font-bold\">50%</span> across Three Design Teams\n    </>\n)\n\nexport const FlipCard = forwardRef<HTMLDivElement, FlipCardProps>(\n    (\n        {\n            label = \"Case Study\",\n            icon: Icon = BookOpenIcon,\n            title = DEFAULT_TITLE,\n            spineText = \"click to read\",\n            accentColor = \"red\",\n            className,\n            onClick,\n            size = \"lg\",\n            shadowLabel,\n        },\n        ref,\n    ) => {\n        const tokens = SIZE_MAP[size]\n\n        const spineBg = ACCENT_BG[accentColor] ?? accentColor\n        const titleText = ACCENT_TEXT[accentColor] ?? accentColor\n\n        const handleKeyDown = (e: KeyboardEvent<HTMLDivElement>) => {\n            if (onClick && (e.key === \"Enter\" || e.key === \" \")) {\n                e.preventDefault()\n                onClick()\n            }\n        }\n\n        return (\n            <div\n                ref={ref}\n                className={cn(\n                    \"relative perspective-[1000px] group select-none\",\n                    onClick && \"cursor-pointer\",\n                    className,\n                )}\n                onClick={onClick}\n                role={onClick ? \"button\" : undefined}\n                tabIndex={onClick ? 0 : undefined}\n                onKeyDown={handleKeyDown}\n            >\n                <div className=\"transform-3d\">\n                    {/* Shadow layer */}\n                    <div className={cn(\"absolute bg-neutral-300 -z-1 rounded-lg h-full\", tokens.width)}>\n                        {shadowLabel && (\n                            <p className=\"text-xs p-2 text-right text-neutral-500 whitespace-pre-line\">\n                                {shadowLabel}\n                            </p>\n                        )}\n                    </div>\n\n                    {/* Spine tab */}\n                    <div\n                        className={cn(\n                            \"absolute h-5/6 w-5/6 bottom-3 right-0 origin-[20%_100%] group-hover:rotate-z-6 rounded-md transition-transform duration-300 ease-out\",\n                            spineBg,\n                        )}\n                    >\n                        <span className=\"absolute right-0 top-0 h-full flex items-start px-2 py-5\">\n                            <p className={cn(\n                                \"text-white [writing-mode:vertical-rl] rotate-180 uppercase font-semibold tracking-wider\",\n                                tokens.spineTextSize,\n                            )}>\n                                {spineText}\n                            </p>\n                        </span>\n                    </div>\n\n                    {/* Main card face */}\n                    <div\n                        className={cn(\n                            \"transition-transform duration-300 ease-out origin-left bg-neutral-200 relative group-hover:-rotate-y-35 rounded-lg shadow-sm overflow-hidden\",\n                            tokens.height,\n                            tokens.width,\n                        )}\n                    >\n                        <div className={tokens.padding}>\n                            <span className={cn(\"flex items-center\", tokens.labelGap, tokens.labelMb)}>\n                                <Icon className={cn(\"text-neutral-500\", tokens.iconSize)} />\n                                <h2 className={cn(\n                                    \"text-neutral-500 font-semibold uppercase tracking-wide\",\n                                    tokens.labelText,\n                                )}>\n                                    {label}\n                                </h2>\n                            </span>\n                            <h1 className={cn(\"font-semibold leading-snug\", tokens.titleText, titleText)}>\n                                {title}\n                            </h1>\n                        </div>\n                    </div>\n                </div>\n            </div>\n        )\n    },\n)\n\nFlipCard.displayName = \"FlipCard\"",
      "type": "registry:component"
    }
  ],
  "type": "registry:component"
}