{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "hero-quiz",
  "type": "registry:block",
  "title": "Quiz entry hero",
  "description": "The finder's first question lives in the hero as a card radio group; the start button carries the chosen goal into the quiz.",
  "author": "StoreKit <hello@storekit.dev>",
  "categories": [
    "hero",
    "supplements",
    "wellness",
    "beauty"
  ],
  "dependencies": [
    "motion",
    "lucide-react"
  ],
  "registryDependencies": [
    "https://storekit-eight.vercel.app/r/cn.json",
    "https://storekit-eight.vercel.app/r/sk-analytics.json"
  ],
  "files": [
    {
      "path": "hero/hero-quiz.tsx",
      "content": "\"use client\"\n\nimport { useId, useState } from \"react\"\nimport { motion, useReducedMotion } from \"motion/react\"\nimport { ArrowRight, Check, Clock } from \"lucide-react\"\nimport { cn } from \"@/components/storekit/lib/cn\"\nimport { useSkBlock } from \"@/components/storekit/lib/sk-analytics\"\n\n/* Quiz entry hero. The first question of the finder lives in the hero, so\n   the first tap is an answer rather than a \"Take the quiz\" click. Picking a\n   goal enables the start button, which carries the answer forward as\n   `?goal=` on `href` (or hands it to `onStart`). The options are a native\n   radio group styled as cards, so Arrow keys and screen readers work for\n   free. Social proof and the time cost sit under the button. A product\n   stack fills the visual side and stacks below on mobile. */\n\nconst EASE = [0.23, 1, 0.32, 1] as const\n\nexport type QuizOption = { value: string; label: string; hint?: string }\n\nconst SAMPLE: QuizOption[] = [\n  { value: \"energy\", label: \"Steady energy\", hint: \"No 3pm crash\" },\n  { value: \"sleep\", label: \"Better sleep\", hint: \"Fall asleep faster\" },\n  { value: \"focus\", label: \"Focus\", hint: \"Clearer workdays\" },\n  { value: \"gut\", label: \"Gut health\", hint: \"Less bloat\" },\n  { value: \"hydration\", label: \"Hydration\", hint: \"Training and heat\" },\n  { value: \"recovery\", label: \"Recovery\", hint: \"After workouts\" },\n]\n\nexport function HeroQuiz({\n  eyebrow = \"Find your routine\",\n  headline = \"Not sure where to start? Start here.\",\n  question = \"What do you want help with first?\",\n  options = SAMPLE,\n  startLabel = \"Start the 2 minute quiz\",\n  href = \"#\",\n  onStart,\n  meta = \"6 questions, about 2 minutes\",\n  proof = \"Over 38,000 routines built\",\n  images = [],\n  className,\n}: {\n  eyebrow?: string\n  headline?: string\n  question?: string\n  options?: QuizOption[]\n  startLabel?: string\n  /** Quiz page. The chosen goal is appended as ?goal=value. */\n  href?: string\n  onStart?: (goal: string) => void\n  meta?: string\n  proof?: string\n  /** Up to three product images for the visual side. */\n  images?: { src: string; alt: string }[]\n  className?: string\n}) {\n  const reduce = useReducedMotion()\n  const sk = useSkBlock(\"hero\", \"hero-quiz\")\n  const name = useId()\n  const [goal, setGoal] = useState<string | null>(null)\n  const target = goal ? `${href}${href.includes(\"?\") ? \"&\" : \"?\"}goal=${encodeURIComponent(goal)}` : href\n\n  return (\n    <section ref={sk.ref} {...sk.attrs} className={cn(\"bg-sk-paper text-sk-ink\", className)}>\n      <div className=\"mx-auto grid w-full max-w-6xl items-center gap-10 px-4 py-10 sm:px-8 sm:py-14 lg:grid-cols-[1.15fr_0.85fr] lg:gap-14\">\n        <motion.div initial={{ opacity: 0, y: reduce ? 0 : 8 }} animate={{ opacity: 1, y: 0 }} transition={{ duration: 0.5, ease: EASE }}>\n          <p className=\"font-sk-mono text-[11px] uppercase tracking-[0.14em] text-sk-muted\">{eyebrow}</p>\n          <h1 className=\"mt-4 max-w-xl text-balance font-sk-display font-semibold leading-[1.08] tracking-[-0.02em]\" style={{ fontSize: \"clamp(2rem, 4.2vw, 3.25rem)\" }}>\n            {headline}\n          </h1>\n\n          <fieldset className=\"mt-8\">\n            <legend className=\"text-[15px] font-medium text-sk-ink\">{question}</legend>\n            <div className=\"mt-4 grid grid-cols-2 gap-2 sm:grid-cols-3 sm:gap-3\">\n              {options.map((o) => {\n                const on = goal === o.value\n                return (\n                  <label\n                    key={o.value}\n                    className={cn(\n                      \"relative flex min-h-[64px] cursor-pointer flex-col justify-center rounded-sk-card border px-3.5 py-3 transition-[border-color,background-color,transform] duration-200 ease-sk-out active:scale-[0.98] has-[:focus-visible]:ring-2 has-[:focus-visible]:ring-sk-accent has-[:focus-visible]:ring-offset-2 has-[:focus-visible]:ring-offset-sk-paper\",\n                      on ? \"border-sk-accent bg-sk-accent/[0.07]\" : \"border-sk-line bg-sk-card hover:border-sk-ink/30\"\n                    )}\n                  >\n                    <input\n                      type=\"radio\"\n                      name={name}\n                      value={o.value}\n                      checked={on}\n                      onChange={() => {\n                        setGoal(o.value)\n                        sk.emit(\"interact\", `goal_${o.value}`)\n                      }}\n                      className=\"sr-only\"\n                    />\n                    <span className=\"pr-6 text-[14px] font-medium leading-tight\">{o.label}</span>\n                    {o.hint ? <span className=\"mt-1 text-[12px] leading-tight text-sk-muted\">{o.hint}</span> : null}\n                    <motion.span\n                      aria-hidden\n                      initial={false}\n                      animate={{ scale: on ? 1 : 0.4, opacity: on ? 1 : 0 }}\n                      transition={{ type: \"spring\", stiffness: 520, damping: 30 }}\n                      className=\"absolute right-2.5 top-2.5 grid h-5 w-5 place-items-center rounded-full bg-sk-accent text-sk-accent-ink\"\n                    >\n                      <Check size={12} strokeWidth={3} />\n                    </motion.span>\n                  </label>\n                )\n              })}\n            </div>\n          </fieldset>\n\n          <div className=\"mt-6 flex flex-col gap-4 sm:flex-row sm:items-center\">\n            <a\n              href={target}\n              aria-disabled={!goal}\n              onClick={(e) => {\n                if (!goal) {\n                  e.preventDefault()\n                  return\n                }\n                sk.emit(\"convert\", \"quiz_start\")\n                if (onStart) {\n                  e.preventDefault()\n                  onStart(goal)\n                }\n              }}\n              className={cn(\n                \"sk-btn group inline-flex min-h-12 items-center justify-center gap-2 py-2.5 text-center leading-tight rounded-sk-btn bg-sk-accent px-7 text-[15px] font-medium text-sk-accent-ink outline-none transition-[filter,transform,opacity] duration-200 ease-sk-out focus-visible:ring-2 focus-visible:ring-sk-accent focus-visible:ring-offset-2 focus-visible:ring-offset-sk-paper\",\n                goal ? \"hover:brightness-[1.06] active:scale-[0.97]\" : \"cursor-not-allowed opacity-50\"\n              )}\n            >\n              {startLabel}\n              <ArrowRight size={16} aria-hidden className=\"transition-transform duration-300 ease-sk-out group-hover:translate-x-0.5\" />\n            </a>\n            <p className=\"flex items-center gap-1.5 text-[13px] text-sk-muted\">\n              <Clock size={14} aria-hidden />\n              {meta}\n            </p>\n          </div>\n          {proof ? <p className=\"mt-5 border-t border-sk-line pt-4 text-[13px] text-sk-muted\">{proof}</p> : null}\n        </motion.div>\n\n        {images.length ? (\n          <div className=\"relative mx-auto aspect-square w-full max-w-[420px] lg:max-w-none\">\n            <div className=\"absolute inset-[6%] rounded-full bg-sk-surface\" aria-hidden />\n            {images.slice(0, 3).map((im, i) => {\n              const pos = [\"left-[2%] top-[18%] w-[52%] rotate-[-6deg]\", \"right-[2%] top-[6%] w-[48%] rotate-[5deg]\", \"left-[26%] bottom-[2%] w-[50%] rotate-[-1deg]\"][i]\n              return (\n                <motion.img\n                  key={im.src + i}\n                  src={im.src}\n                  alt={im.alt}\n                  initial={{ opacity: 0, y: reduce ? 0 : 16 }}\n                  animate={{ opacity: 1, y: 0 }}\n                  transition={{ duration: 0.6, ease: EASE, delay: reduce ? 0 : 0.12 + i * 0.08 }}\n                  className={cn(\"absolute aspect-square rounded-sk-card border border-sk-line bg-sk-card object-cover shadow-[0_30px_60px_-30px_rgb(var(--sk-ink)/0.45)]\", pos)}\n                />\n              )\n            })}\n          </div>\n        ) : null}\n      </div>\n    </section>\n  )\n}\n",
      "type": "registry:block",
      "target": "components/storekit/hero/hero-quiz.tsx"
    }
  ],
  "docs": "The goal is appended to `href` as ?goal=, or passed to `onStart`.",
  "meta": {
    "section": "hero",
    "variant": "quiz",
    "niche": [
      "supplements",
      "wellness",
      "beauty"
    ],
    "commerce": [
      "cta",
      "quiz"
    ],
    "previewHeight": 620
  }
}