{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "hero-offer",
  "type": "registry:block",
  "title": "Offer-led hero",
  "description": "The discount is the headline: oversized offer figure, tap-to-copy promo code, eligibility line and a tagged packshot.",
  "author": "StoreKit <hello@storekit.dev>",
  "categories": [
    "hero",
    "any"
  ],
  "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-offer.tsx",
      "content": "\"use client\"\n\nimport { useRef, useState } from \"react\"\nimport { AnimatePresence, motion, useReducedMotion } from \"motion/react\"\nimport { Check, Copy } from \"lucide-react\"\nimport { cn } from \"@/components/storekit/lib/cn\"\nimport { useSkBlock } from \"@/components/storekit/lib/sk-analytics\"\n\n/* Offer-led hero. The offer is the headline: a large figure (\"25% off\"),\n   what it applies to, a promo code that copies on tap, and the eligibility\n   line right under it so nobody feels tricked at checkout. `autoApplied`\n   swaps the code for an \"applied at checkout\" note. The packshot sits on\n   the surface token with a sale tag. Stacks offer first on mobile. */\n\nconst EASE = [0.23, 1, 0.32, 1] as const\n\ntype Cta = { label: string; href: string }\n\nconst PRIMARY =\n  \"sk-btn inline-flex min-h-12 items-center justify-center 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] duration-200 ease-sk-out hover:brightness-[1.06] focus-visible:ring-2 focus-visible:ring-sk-accent focus-visible:ring-offset-2 focus-visible:ring-offset-sk-paper active:scale-[0.97]\"\nconst SECONDARY =\n  \"sk-btn inline-flex min-h-12 items-center justify-center py-2.5 text-center leading-tight rounded-sk-btn border border-sk-line px-7 text-[15px] font-medium text-sk-ink outline-none transition-[background-color,transform] duration-200 ease-sk-out hover:bg-sk-ink/[0.04] focus-visible:ring-2 focus-visible:ring-sk-accent focus-visible:ring-offset-2 focus-visible:ring-offset-sk-paper active:scale-[0.97]\"\n\nexport function HeroOffer({\n  eyebrow = \"Autumn reset sale\",\n  figure = \"25% off\",\n  headline = \"Everything on the shelf.\",\n  subcopy = \"Stack it with Subscribe and Save for up to 35% off your first order.\",\n  code = \"RESET25\",\n  autoApplied = false,\n  eligibility = \"Ends Sunday at 11:59pm ET. Excludes gift cards. One use per customer.\",\n  primaryCta = { label: \"Shop the sale\", href: \"#\" },\n  secondaryCta = { label: \"Shop bundles\", href: \"#\" },\n  image = \"/placeholder.webp\",\n  imageAlt = \"\",\n  tag = \"Sale\",\n  className,\n}: {\n  eyebrow?: string\n  /** The offer itself, set very large. */\n  figure?: string\n  headline?: string\n  subcopy?: string\n  code?: string\n  /** True when the discount applies without a code. */\n  autoApplied?: boolean\n  eligibility?: string\n  primaryCta?: Cta\n  secondaryCta?: Cta\n  image?: string\n  imageAlt?: string\n  tag?: string\n  className?: string\n}) {\n  const reduce = useReducedMotion()\n  const sk = useSkBlock(\"hero\", \"hero-offer\")\n  const [copied, setCopied] = useState(false)\n  const timer = useRef<ReturnType<typeof setTimeout> | undefined>(undefined)\n\n  const copy = async () => {\n    try {\n      await navigator.clipboard.writeText(code)\n    } catch {\n      /* clipboard can be blocked; the code is still visible to type */\n    }\n    setCopied(true)\n    sk.emit(\"interact\", \"copy_code\")\n    clearTimeout(timer.current)\n    timer.current = setTimeout(() => setCopied(false), 2000)\n  }\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.1fr_0.9fr] 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-sale\">{eyebrow}</p>\n          <h1 className=\"mt-3\">\n            <span className=\"block font-sk-display font-semibold leading-[0.92] tracking-[-0.04em] text-sk-ink\" style={{ fontSize: \"clamp(3.75rem, 11vw, 8.5rem)\" }}>\n              {figure}\n            </span>\n            <span className=\"mt-3 block text-balance font-sk-display font-semibold leading-[1.1] tracking-[-0.02em]\" style={{ fontSize: \"clamp(1.5rem, 2.8vw, 2.25rem)\" }}>\n              {headline}\n            </span>\n          </h1>\n          <p className=\"mt-4 max-w-md text-[15px] leading-[1.55] text-sk-muted\">{subcopy}</p>\n\n          <div className=\"mt-7 flex flex-wrap items-center gap-3\">\n            {autoApplied ? (\n              <p className=\"sk-btn inline-flex h-12 items-center gap-2 rounded-sk-btn border border-dashed border-sk-savings/50 bg-sk-savings/[0.08] px-4 text-sm font-medium text-sk-savings\">\n                <Check size={16} aria-hidden /> Discount applied at checkout\n              </p>\n            ) : (\n              <button\n                type=\"button\"\n                onClick={copy}\n                className=\"group inline-flex h-12 items-center gap-3 rounded-sk-btn border border-dashed border-sk-ink/30 bg-sk-surface pl-4 pr-3 outline-none transition-[border-color,transform] duration-200 ease-sk-out hover:border-sk-ink/60 focus-visible:ring-2 focus-visible:ring-sk-accent focus-visible:ring-offset-2 focus-visible:ring-offset-sk-paper active:scale-[0.98]\"\n              >\n                <span className=\"text-[12px] text-sk-muted\">Code</span>\n                <span className=\"font-sk-mono text-[15px] font-medium tracking-[0.08em] text-sk-ink\">{code}</span>\n                <span className=\"relative grid h-8 w-8 place-items-center rounded-full bg-sk-ink/[0.06] text-sk-ink\">\n                  <AnimatePresence initial={false} mode=\"popLayout\">\n                    <motion.span\n                      key={copied ? \"y\" : \"n\"}\n                      initial={{ opacity: 0, scale: reduce ? 1 : 0.6 }}\n                      animate={{ opacity: 1, scale: 1 }}\n                      exit={{ opacity: 0, scale: reduce ? 1 : 0.6 }}\n                      transition={{ type: \"spring\", stiffness: 500, damping: 30 }}\n                      className=\"grid place-items-center\"\n                    >\n                      {copied ? <Check size={15} aria-hidden /> : <Copy size={14} aria-hidden />}\n                    </motion.span>\n                  </AnimatePresence>\n                </span>\n                <span className=\"sr-only\">{copied ? \"Copied\" : \"Copy code\"}</span>\n              </button>\n            )}\n            <span aria-live=\"polite\" className={cn(\"text-[13px] text-sk-savings transition-opacity duration-200\", copied ? \"opacity-100\" : \"opacity-0\")}>\n              {copied ? \"Copied to clipboard\" : \"\"}\n            </span>\n          </div>\n\n          <div className=\"mt-6 flex flex-col gap-3 sm:flex-row\">\n            <a href={primaryCta.href} onClick={() => sk.emit(\"interact\", \"cta\")} className={PRIMARY}>\n              {primaryCta.label}\n            </a>\n            <a href={secondaryCta.href} onClick={() => sk.emit(\"interact\", \"cta_secondary\")} className={SECONDARY}>\n              {secondaryCta.label}\n            </a>\n          </div>\n          {eligibility ? <p className=\"mt-5 max-w-md text-[12px] leading-[1.5] text-sk-muted\">{eligibility}</p> : null}\n        </motion.div>\n\n        <motion.div\n          initial={{ opacity: 0, scale: reduce ? 1 : 0.96 }}\n          animate={{ opacity: 1, scale: 1 }}\n          transition={{ duration: 0.6, ease: EASE, delay: reduce ? 0 : 0.1 }}\n          className=\"relative mx-auto aspect-square w-full max-w-[460px] overflow-hidden rounded-sk-card border border-sk-line bg-sk-surface\"\n        >\n          <img src={image} alt={imageAlt} className=\"absolute inset-0 h-full w-full object-cover\" />\n          {tag ? (\n            <span className=\"absolute left-4 top-4 rotate-[-6deg] rounded-sk-chip bg-sk-sale px-3 py-1.5 font-sk-mono text-[12px] font-medium uppercase tracking-[0.12em] text-sk-paper shadow-[0_10px_24px_-12px_rgb(var(--sk-ink)/0.5)]\">\n              {tag}\n            </span>\n          ) : null}\n        </motion.div>\n      </div>\n    </section>\n  )\n}\n",
      "type": "registry:block",
      "target": "components/storekit/hero/hero-offer.tsx"
    }
  ],
  "docs": "Keep `eligibility` honest and visible. Set `autoApplied` when no code is needed.",
  "meta": {
    "section": "hero",
    "variant": "offer",
    "niche": [
      "any"
    ],
    "commerce": [
      "cta",
      "promo"
    ],
    "previewHeight": 600
  }
}