{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "hero-video-card",
  "type": "registry:block",
  "title": "Video card hero",
  "description": "Product demo clip contained in a card beside the copy, poster first, with one play and pause control and a caption with run time.",
  "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-video-card.tsx",
      "content": "\"use client\"\n\nimport { useEffect, useRef, useState } from \"react\"\nimport { motion, useReducedMotion } from \"motion/react\"\nimport { Pause, Play } from \"lucide-react\"\nimport { cn } from \"@/components/storekit/lib/cn\"\nimport { useSkBlock } from \"@/components/storekit/lib/sk-analytics\"\n\n/* Product demo video in a card beside the copy, not behind it. The poster\n   paints first. With motion allowed the clip autoplays muted and looped;\n   with reduced motion it waits for the play button. One control toggles\n   play and pause, and a caption under the card says what the clip shows and\n   how long it runs. Stacks with the card first under lg. */\n\nconst EASE = [0.23, 1, 0.32, 1] as const\n\ntype Cta = { label: string; href: string }\n\nexport function HeroVideoCard({\n  poster = \"/placeholder.webp\",\n  src,\n  caption = \"How a batch gets made\",\n  duration = \"0:42\",\n  eyebrow = \"From farm to scoop\",\n  headline = \"Watch a pouch go from the field to your door.\",\n  subcopy = \"Whole-food ingredients, blended and packed in the USA, then third-party tested before it ships.\",\n  primaryCta = { label: \"Shop the range\", href: \"#\" },\n  secondaryCta = { label: \"See lab results\", href: \"#\" },\n  className,\n}: {\n  poster?: string\n  /** Video file. Without it the card shows the poster only. */\n  src?: string\n  caption?: string\n  duration?: string\n  eyebrow?: string\n  headline?: string\n  subcopy?: string\n  primaryCta?: Cta\n  secondaryCta?: Cta\n  className?: string\n}) {\n  const reduce = useReducedMotion()\n  const sk = useSkBlock(\"hero\", \"hero-video-card\")\n  const video = useRef<HTMLVideoElement>(null)\n  const [playing, setPlaying] = useState(false)\n\n  useEffect(() => {\n    const v = video.current\n    if (!v || !src) return\n    if (reduce) {\n      v.pause()\n      return\n    }\n    v.play().catch(() => setPlaying(false))\n  }, [reduce, src])\n\n  const toggle = () => {\n    const v = video.current\n    if (!v || !src) return\n    if (v.paused) {\n      v.play().catch(() => {})\n      sk.emit(\"interact\", \"video_play\")\n    } else v.pause()\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-12 sm:px-8 sm:py-16 lg:grid-cols-2 lg:gap-16\">\n        <motion.div\n          initial={{ opacity: 0, y: reduce ? 0 : 8 }}\n          animate={{ opacity: 1, y: 0 }}\n          transition={{ duration: 0.5, ease: EASE }}\n          className=\"order-2 lg:order-1\"\n        >\n          <p className=\"font-sk-mono text-[11px] uppercase tracking-[0.14em] text-sk-muted\">{eyebrow}</p>\n          <h1\n            className=\"mt-4 max-w-xl text-balance font-sk-display font-semibold leading-[1.1] tracking-[-0.02em]\"\n            style={{ fontSize: \"clamp(2rem, 4vw, 3.25rem)\" }}\n          >\n            {headline}\n          </h1>\n          <p className=\"mt-5 max-w-md text-[15px] leading-[1.5] text-sk-muted\">{subcopy}</p>\n          <div className=\"mt-8 flex flex-col gap-3 sm:flex-row\">\n            <a\n              href={primaryCta.href}\n              onClick={() => sk.emit(\"interact\", \"cta\")}\n              className=\"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]\"\n            >\n              {primaryCta.label}\n            </a>\n            <a\n              href={secondaryCta.href}\n              onClick={() => sk.emit(\"interact\", \"cta_secondary\")}\n              className=\"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            >\n              {secondaryCta.label}\n            </a>\n          </div>\n        </motion.div>\n\n        <figure className=\"order-1 lg:order-2\">\n          <div className=\"relative aspect-video overflow-hidden rounded-sk-card border border-sk-line bg-sk-surface\">\n            <video\n              ref={video}\n              poster={poster}\n              muted\n              loop\n              playsInline\n              preload=\"metadata\"\n              onPlay={() => setPlaying(true)}\n              onPause={() => setPlaying(false)}\n              className=\"absolute inset-0 h-full w-full object-cover\"\n            >\n              {src ? <source src={src} /> : null}\n            </video>\n            {src ? (\n              <button\n                type=\"button\"\n                onClick={toggle}\n                aria-label={playing ? \"Pause video\" : \"Play video\"}\n                className=\"absolute bottom-3 left-3 grid h-11 w-11 place-items-center rounded-full bg-[rgb(0_0_0/0.6)] text-[rgb(255_255_255)] outline-none transition-[background-color,transform] duration-200 ease-sk-out hover:bg-[rgb(0_0_0/0.75)] focus-visible:ring-2 focus-visible:ring-[rgb(255_255_255)] active:scale-[0.97]\"\n              >\n                {playing ? <Pause size={16} aria-hidden /> : <Play size={16} aria-hidden className=\"translate-x-px\" />}\n              </button>\n            ) : null}\n          </div>\n          <figcaption className=\"mt-3 flex items-center justify-between gap-4 font-sk-mono text-[11px] uppercase tracking-[0.14em] text-sk-muted\">\n            <span>{caption}</span>\n            <span className=\"tabular-nums\">{duration}</span>\n          </figcaption>\n        </figure>\n      </div>\n    </section>\n  )\n}\n",
      "type": "registry:block",
      "target": "components/storekit/hero/hero-video-card.tsx"
    }
  ],
  "docs": "Pass `src`; it autoplays muted unless reduced motion is on, where it waits for the play button.",
  "meta": {
    "section": "hero",
    "variant": "video-card",
    "niche": [
      "any"
    ],
    "commerce": [
      "cta"
    ],
    "previewHeight": 560
  }
}