{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "how-it-works",
  "type": "registry:block",
  "title": "How it works",
  "description": "Three concrete steps on a spine that draws itself in view, each with a mono numeral and a tiny product photo.",
  "author": "StoreKit <hello@storekit.dev>",
  "categories": [
    "marketing",
    "any"
  ],
  "dependencies": [
    "motion"
  ],
  "registryDependencies": [
    "https://storekit-eight.vercel.app/r/cn.json",
    "https://storekit-eight.vercel.app/r/product-image.json"
  ],
  "files": [
    {
      "path": "marketing/how-it-works.tsx",
      "content": "\"use client\"\n\nimport { motion, useReducedMotion } from \"motion/react\"\nimport { cn } from \"@/components/storekit/lib/cn\"\nimport { ProductImage } from \"@/components/storekit/ui/product-image\"\n\n/* Three steps strung on a spine that draws itself in view: vertical on\n   mobile, horizontal on desktop. Each step pairs a mono numeral and a\n   concrete sentence with a tiny product photo, so it reads as this store's\n   process rather than a generic 1-2-3. */\n\ntype Step = { title: string; body: string; meta: string; image: string }\n\nconst SAMPLE: Step[] = [\n  { title: \"Pick\", body: \"Choose your essentials and how often they ship. Checkout takes under a minute.\", meta: \"2 min\", image: \"/brands/morrow/greens.webp\" },\n  { title: \"Tested\", body: \"Every batch is third-party tested before it leaves our US facility.\", meta: \"Every batch\", image: \"/brands/morrow/electrolytes.webp\" },\n  { title: \"Shipped\", body: \"Packed and handed to the carrier within 24 hours. Refills arrive on schedule.\", meta: \"24 hrs\", image: \"/brands/morrow/magnesium.webp\" },\n]\n\nconst EASE: [number, number, number, number] = [0.16, 1, 0.3, 1]\n\nexport function HowItWorks({\n  eyebrow = \"How it works\",\n  title = \"From order to doorstep in three moves.\",\n  steps = SAMPLE,\n  className,\n}: {\n  eyebrow?: string\n  title?: string\n  steps?: Step[]\n  className?: string\n}) {\n  const reduce = useReducedMotion()\n  // One in-view trigger drives the spine and the steps so they stay in sync.\n  // The spine is a scaled div (transform only), not an SVG stroke, so it draws\n  // as one solid line at any container size.\n  const draw = { duration: reduce ? 0 : 0.9, ease: EASE }\n  const spineY = { hidden: { scaleY: reduce ? 1 : 0 }, show: { scaleY: 1, transition: draw } }\n  const spineX = { hidden: { scaleX: reduce ? 1 : 0 }, show: { scaleX: 1, transition: draw } }\n  const step = {\n    hidden: { opacity: 0, y: reduce ? 0 : 8 },\n    show: { opacity: 1, y: 0, transition: { duration: 0.5, ease: EASE } },\n  }\n  return (\n    <section data-sk-section=\"marketing\" data-sk-variant=\"how-it-works\" className={cn(\"w-full py-16 sm:py-24\", className)}>\n      <div className=\"mx-auto max-w-6xl px-4 sm:px-8\">\n        <p className=\"font-sk-mono text-[11px] uppercase tracking-[0.14em] text-sk-muted\">{eyebrow}</p>\n        <h2 className=\"mt-3 max-w-xl font-sk-display text-3xl font-semibold leading-[1.1] tracking-[-0.02em] sm:text-4xl\">{title}</h2>\n\n        <motion.ol\n          className=\"relative mt-12 grid gap-10 pl-8 md:grid-cols-3 md:gap-8 md:pl-0 md:pt-10\"\n          initial=\"hidden\"\n          whileInView=\"show\"\n          viewport={{ once: true, amount: 0.2 }}\n          variants={{ hidden: {}, show: { transition: { staggerChildren: reduce ? 0 : 0.06, delayChildren: reduce ? 0 : 0.15 } } }}\n        >\n          {/* Vertical spine (mobile) */}\n          <span aria-hidden className=\"absolute bottom-2 left-[5px] top-2 w-0.5 bg-sk-line md:hidden\">\n            <motion.span variants={spineY} className=\"absolute inset-0 origin-top bg-sk-accent\" />\n          </span>\n          {/* Horizontal spine (desktop) */}\n          <span aria-hidden className=\"absolute left-0 right-0 top-[5px] hidden h-0.5 bg-sk-line md:block\">\n            <motion.span variants={spineX} className=\"absolute inset-0 origin-left bg-sk-accent\" />\n          </span>\n\n          {steps.map((s, i) => (\n            <motion.li key={s.title} className=\"relative\" variants={step}>\n              <span aria-hidden className=\"absolute -left-8 top-1 h-3 w-3 rounded-full border-2 border-sk-accent bg-sk-paper md:-top-10 md:left-0\" />\n              <div className=\"flex items-start gap-4\">\n                <ProductImage src={s.image} alt=\"\" fit=\"cover\" className=\"h-16 w-16 shrink-0 rounded-sk-card border border-sk-line\" zoomOnHover={false} />\n                <div className=\"min-w-0\">\n                  <p className=\"flex flex-wrap items-baseline gap-x-3 gap-y-1\">\n                    <span className=\"font-sk-mono text-[11px] tabular-nums tracking-[0.14em] text-sk-accent\">{String(i + 1).padStart(2, \"0\")}</span>\n                    <span className=\"text-[15px] font-semibold text-sk-ink\">{s.title}</span>\n                    <span className=\"font-sk-mono text-[11px] uppercase tracking-[0.14em] text-sk-muted\">{s.meta}</span>\n                  </p>\n                  <p className=\"mt-1.5 max-w-xs text-sm leading-[1.5] text-sk-muted\">{s.body}</p>\n                </div>\n              </div>\n            </motion.li>\n          ))}\n        </motion.ol>\n      </div>\n    </section>\n  )\n}\n",
      "type": "registry:block",
      "target": "components/storekit/marketing/how-it-works.tsx"
    }
  ],
  "meta": {
    "section": "marketing",
    "variant": "spine",
    "niche": [
      "any"
    ],
    "commerce": [
      "education"
    ],
    "previewHeight": 480
  }
}