{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "feature-02",
  "title": "Feature 02",
  "description": "A process section with a split title/description header and a portrait image flanked by two columns of numbered step cards.",
  "dependencies": [
    "react-wrap-balancer",
    "motion"
  ],
  "registryDependencies": [],
  "files": [
    {
      "path": "registry/blocks/feature/feature-02/feature-02.tsx",
      "content": "'use client'\n\nimport * as React from 'react'\nimport { motion, useReducedMotion, type Variants } from 'motion/react'\nimport Balancer from 'react-wrap-balancer'\n\nimport { cn } from '@/lib/utils'\n\nexport interface Feature02Step {\n  number: string\n  title: string\n  description: string\n}\n\nexport interface Feature02Props {\n  title: string\n  description: string\n  image: string\n  imageAlt?: string\n  steps: Feature02Step[]\n  animation?: 'none' | 'subtle'\n  variant?: 'standard' | 'compact'\n}\n\nconst variantStyles = {\n  standard: {\n    section: 'py-20 sm:py-28',\n    title: 'text-3xl sm:text-4xl md:text-5xl',\n    description: 'max-w-sm text-sm sm:text-base leading-relaxed',\n    header: 'gap-8 sm:gap-16',\n    content: 'gap-12 sm:gap-16',\n    grid: 'gap-4 sm:gap-6',\n    image: 'max-w-sm',\n  },\n  compact: {\n    section: 'py-14 sm:py-20',\n    title: 'text-2xl sm:text-3xl md:text-4xl',\n    description: 'max-w-xs text-sm leading-relaxed',\n    header: 'gap-6 sm:gap-12',\n    content: 'gap-10 sm:gap-12',\n    grid: 'gap-3 sm:gap-4',\n    image: 'max-w-xs',\n  },\n} as const\n\nconst container: Variants = {\n  hidden: {},\n  visible: { transition: { staggerChildren: 0.08, delayChildren: 0.05 } },\n}\n\nconst item: Variants = {\n  hidden: { opacity: 0, y: 12, filter: 'blur(6px)' },\n  visible: {\n    opacity: 1,\n    y: 0,\n    filter: 'blur(0px)',\n    transition: { duration: 0.5, ease: [0.22, 1, 0.36, 1] },\n  },\n}\n\nconst mediaItem: Variants = {\n  hidden: { opacity: 0, scale: 0.96, filter: 'blur(8px)' },\n  visible: {\n    opacity: 1,\n    scale: 1,\n    filter: 'blur(0px)',\n    transition: { duration: 0.6, ease: [0.22, 1, 0.36, 1] },\n  },\n}\n\nfunction Reveal({\n  active,\n  variants,\n  className,\n  children,\n}: Readonly<{\n  active: boolean\n  variants?: Variants\n  className?: string\n  children: React.ReactNode\n}>) {\n  if (!active) return <div className={className}>{children}</div>\n\n  return (\n    <motion.div variants={variants ?? item} className={className}>\n      {children}\n    </motion.div>\n  )\n}\n\nfunction StepCard({\n  step,\n  animate,\n}: Readonly<{ step: Feature02Step; animate: boolean }>) {\n  const cardClassName = 'border-border/80 bg-card rounded-2xl border p-5 sm:p-6'\n\n  const content = (\n    <>\n      <span className=\"text-muted-foreground font-serif text-lg italic\">\n        {step.number}\n      </span>\n      <h3 className=\"text-foreground mt-3 text-base font-semibold\">\n        {step.title}\n      </h3>\n      <p className=\"text-muted-foreground mt-2 text-sm leading-relaxed\">\n        <Balancer>{step.description}</Balancer>\n      </p>\n    </>\n  )\n\n  if (!animate) return <div className={cardClassName}>{content}</div>\n\n  return (\n    <motion.div\n      initial=\"hidden\"\n      whileInView=\"visible\"\n      viewport={{ once: true, margin: '-40px' }}\n      variants={item}\n      className={cardClassName}\n    >\n      {content}\n    </motion.div>\n  )\n}\n\nexport function Feature02({\n  title,\n  description,\n  image,\n  imageAlt = '',\n  steps,\n  animation = 'none',\n  variant = 'standard',\n}: Readonly<Feature02Props>) {\n  const reduce = useReducedMotion()\n  const animate = animation === 'subtle' && !reduce\n  const vs = variantStyles[variant]\n\n  const half = Math.ceil(steps.length / 2)\n  const leftSteps = steps.slice(0, half)\n  const rightSteps = steps.slice(half)\n\n  const titleElement = title && (\n    <h1\n      className={cn(\n        'text-foreground font-semibold tracking-tight text-balance',\n        vs.title,\n      )}\n    >\n      <Balancer>{title}</Balancer>\n    </h1>\n  )\n\n  const descriptionElement = description && (\n    <p className={cn('text-muted-foreground', vs.description)}>\n      <Balancer>{description}</Balancer>\n    </p>\n  )\n\n  const imageElement = image && (\n    <div\n      className={cn(\n        'relative mx-auto w-full overflow-hidden rounded-3xl shadow-sm outline outline-black/10 dark:outline-white/10',\n        vs.image,\n      )}\n    >\n      <img\n        src={image}\n        alt={imageAlt}\n        decoding=\"async\"\n        className=\"aspect-[4/5] w-full object-cover\"\n      />\n    </div>\n  )\n\n  const leftColumnElement = leftSteps.length > 0 && (\n    <div className={cn('flex flex-col', vs.grid)}>\n      {leftSteps.map((step) => (\n        <StepCard key={step.number} step={step} animate={animate} />\n      ))}\n    </div>\n  )\n\n  const rightColumnElement = rightSteps.length > 0 && (\n    <div className={cn('flex flex-col', vs.grid)}>\n      {rightSteps.map((step) => (\n        <StepCard key={step.number} step={step} animate={animate} />\n      ))}\n    </div>\n  )\n\n  return (\n    <section className=\"bg-background relative isolate w-full overflow-hidden\">\n      <motion.div\n        className={cn(\n          'relative z-10 mx-auto flex max-w-6xl flex-col px-6',\n          vs.section,\n          vs.content,\n        )}\n        variants={animate ? container : undefined}\n        initial={animate ? 'hidden' : false}\n        whileInView={animate ? 'visible' : undefined}\n        viewport={{ once: true, margin: '-80px' }}\n      >\n        <Reveal\n          active={animate}\n          className={cn(\n            'flex flex-col items-start justify-between sm:flex-row sm:items-end',\n            vs.header,\n          )}\n        >\n          <div className=\"max-w-xl\">{titleElement}</div>\n          {descriptionElement}\n        </Reveal>\n\n        <div className=\"grid grid-cols-1 items-center gap-8 min-[860px]:grid-cols-[1fr_auto_1fr] min-[860px]:gap-6\">\n          {leftColumnElement}\n          <Reveal\n            active={animate}\n            variants={mediaItem}\n            className=\"order-first min-[860px]:order-0\"\n          >\n            {imageElement}\n          </Reveal>\n          {rightColumnElement}\n        </div>\n      </motion.div>\n    </section>\n  )\n}\n",
      "type": "registry:component",
      "target": "components/flx/blocks/feature/feature-02/feature-02.tsx"
    },
    {
      "path": "registry/blocks/feature/feature-02/feature-02-example.tsx",
      "content": "import { Feature02, type Feature02Props } from './feature-02'\n\nexport const values = {\n  title: 'Turning Your Product Vision into Interface, Simply.',\n  description:\n    'Building with Flexnative is a seamless, guided experience designed to make shipping polished UI effortless and fast.',\n  image:\n    'https://images.unsplash.com/photo-1690848095491-942c798366b8?q=80&w=987&auto=format&fit=crop&ixlib=rb-4.1.0&ixid=M3wxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8fA%3D%3D',\n  imageAlt:\n    'A hand holding a phone showing a product dashboard, with a laptop and monitor displaying UI mockups in the background',\n  steps: [\n    {\n      number: '01',\n      title: 'Explore the Library',\n      description:\n        'Browse hundreds of production-ready blocks across every section type.',\n    },\n    {\n      number: '02',\n      title: 'Customize & Theme',\n      description:\n        'Swap presets, tokens, and copy to match your brand in minutes.',\n    },\n    {\n      number: '03',\n      title: 'Compose Your Pages',\n      description:\n        'Drag blocks into the editor and arrange them into full layouts.',\n    },\n    {\n      number: '04',\n      title: 'Ship to Production',\n      description: 'Copy the code or install via CLI, ready to deploy today.',\n    },\n  ],\n  animation: 'subtle',\n} satisfies Feature02Props\n\nexport function Feature02Example() {\n  return <Feature02 {...values} />\n}\n",
      "type": "registry:component",
      "target": "components/flx/blocks/feature/feature-02/feature-02-example.tsx"
    }
  ],
  "meta": {
    "iframeHeight": 1000
  },
  "type": "registry:block"
}