{"version":1,"id":"expanding-feature-card","framework":"next","kind":"block","files":[{"path":"src/blocks/gfa/expanding-feature-card.tsx","content":"\"use client\";\n\nimport { type ReactNode, useState } from \"react\";\nimport { LiquidMetal } from \"@paper-design/shaders-react\";\nimport { motion, useReducedMotion } from \"motion/react\";\nimport { cn } from \"@/lib/utils\";\n\nexport type ExpandingFeatureCardProps = {\n  title: string;\n  description: string;\n  detail: string;\n  imageSrc: string;\n  imageAlt?: string;\n  href?: string;\n  /** Gallery embed: hover/focus works without navigating. */\n  preview?: boolean;\n  badge?: string;\n  icon: ReactNode;\n  iconClassName?: string;\n  tone?: \"light\" | \"dark\";\n  tags?: string[];\n  ctaLabel?: string;\n  className?: string;\n};\n\nconst panelEase = [0.22, 1, 0.36, 1] as const;\n\nfunction LiquidMetalBadge({ children }: { children: ReactNode }) {\n  return (\n    <span className=\"absolute top-4 left-4 z-10 inline-flex rounded-full\">\n      <span className=\"pointer-events-none absolute inset-0 overflow-hidden rounded-full\">\n        <LiquidMetal\n          className=\"absolute inset-0 size-full\"\n          shape=\"none\"\n          speed={0.28}\n          repetition={4}\n          softness={0.62}\n          shiftRed={0.3}\n          shiftBlue={0.3}\n          distortion={0}\n          contour={0}\n          angle={45}\n          scale={8}\n          offsetX={0.1}\n          offsetY={-0.1}\n          colorBack=\"#c8c8ca\"\n          colorTint=\"#ffffff\"\n        />\n      </span>\n      <span className=\"relative z-[1] m-[1.5px] rounded-full bg-zinc-950 px-3 py-1 text-[11px] font-medium tracking-wide text-white\">\n        {children}\n      </span>\n    </span>\n  );\n}\n\nexport function ExpandingFeatureCard({\n  title,\n  description,\n  detail,\n  imageSrc,\n  imageAlt = \"\",\n  href = \"#\",\n  preview = false,\n  badge,\n  icon,\n  iconClassName,\n  tone = \"light\",\n  tags = [],\n  ctaLabel = \"View project\",\n  className,\n}: ExpandingFeatureCardProps) {\n  const reduceMotion = useReducedMotion();\n  const [hovered, setHovered] = useState(false);\n  const open = hovered;\n  const Shell = preview ? motion.div : motion.a;\n\n  return (\n    <Shell\n      {...(preview\n        ? { tabIndex: 0, role: \"group\" as const }\n        : { href })}\n      data-slot=\"expanding-feature-card\"\n      onHoverStart={() => setHovered(true)}\n      onHoverEnd={() => setHovered(false)}\n      onFocus={() => setHovered(true)}\n      onBlur={() => setHovered(false)}\n      className={cn(\n        \"group relative block aspect-[4/5] w-full overflow-hidden rounded-[1.75rem] outline-none\",\n        \"focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background\",\n        tone === \"dark\" ? \"bg-zinc-900\" : \"bg-zinc-200\",\n        className,\n      )}\n    >\n      <motion.img\n        src={imageSrc}\n        alt={imageAlt}\n        animate={{ scale: open ? 1.045 : 1 }}\n        transition={\n          reduceMotion\n            ? { duration: 0 }\n            : { duration: 0.85, ease: panelEase }\n        }\n        className={cn(\n          \"absolute inset-0 size-full object-cover\",\n          tone === \"dark\" ? \"opacity-95\" : \"opacity-100\",\n        )}\n      />\n\n      {badge ? <LiquidMetalBadge>{badge}</LiquidMetalBadge> : null}\n\n      <motion.div\n        animate={{ padding: open ? 20 : 16 }}\n        transition={\n          reduceMotion\n            ? { duration: 0 }\n            : {\n                type: \"spring\",\n                stiffness: 160,\n                damping: 26,\n                mass: 0.85,\n              }\n        }\n        className={cn(\n          \"absolute inset-x-3 bottom-3 z-10 overflow-hidden rounded-2xl bg-white shadow-[0_8px_30px_rgba(0,0,0,0.08)]\",\n          \"dark:bg-zinc-50\",\n        )}\n      >\n        <div className=\"flex items-start gap-3\">\n          <span\n            className={cn(\n              \"mt-0.5 flex size-9 shrink-0 items-center justify-center rounded-lg text-white\",\n              iconClassName,\n            )}\n          >\n            {icon}\n          </span>\n          <div className=\"min-w-0 flex-1\">\n            <h3 className=\"truncate text-[15px] font-semibold tracking-tight text-zinc-950\">\n              {title}\n            </h3>\n            <p className=\"mt-1 line-clamp-2 text-[13px] leading-snug text-zinc-500\">\n              {description}\n            </p>\n          </div>\n        </div>\n\n        <motion.div\n          initial={false}\n          animate={\n            open\n              ? { height: \"auto\", opacity: 1, marginTop: 12 }\n              : { height: 0, opacity: 0, marginTop: 0 }\n          }\n          transition={\n            reduceMotion\n              ? { duration: 0 }\n              : {\n                  height: {\n                    type: \"spring\",\n                    stiffness: 140,\n                    damping: 24,\n                    mass: 0.9,\n                  },\n                  opacity: {\n                    duration: open ? 0.45 : 0.22,\n                    delay: open ? 0.08 : 0,\n                    ease: panelEase,\n                  },\n                  marginTop: {\n                    type: \"spring\",\n                    stiffness: 140,\n                    damping: 24,\n                    mass: 0.9,\n                  },\n                }\n          }\n          className=\"overflow-hidden\"\n        >\n          <div className=\"border-t border-zinc-100 pt-3\">\n            <p className=\"text-[13px] leading-relaxed text-zinc-600\">{detail}</p>\n            {tags.length > 0 ? (\n              <ul className=\"mt-3 flex flex-wrap gap-1.5\">\n                {tags.map((tag) => (\n                  <li\n                    key={tag}\n                    className=\"rounded-full bg-zinc-100 px-2.5 py-1 text-[11px] font-medium text-zinc-700\"\n                  >\n                    {tag}\n                  </li>\n                ))}\n              </ul>\n            ) : null}\n            <span className=\"mt-3 inline-flex items-center gap-1 text-[12px] font-semibold text-zinc-950\">\n              {ctaLabel}\n              <motion.span\n                aria-hidden\n                animate={{ x: open ? 2 : 0 }}\n                transition={{\n                  type: \"spring\",\n                  stiffness: 280,\n                  damping: 22,\n                }}\n              >\n                →\n              </motion.span>\n            </span>\n          </div>\n        </motion.div>\n      </motion.div>\n    </Shell>\n  );\n}\n\nexport { ExpandingFeatureCard as ExpandingFeatureCardBlock };\n"}],"meta":{"studioName":"GFA Development & Design Studio","siteUrl":"https://ui.gkhn.dev"}}