{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "page-hero",
  "title": "Page Hero",
  "author": "ilinxa",
  "description": "Full-bleed gradient hero band — badge, title, highlight, description, stats row, and a reveal-on-mount animation.",
  "dependencies": [
    "lucide-react"
  ],
  "registryDependencies": [],
  "files": [
    {
      "path": "src/registry/components/marketing/page-hero/page-hero.tsx",
      "content": "\"use client\";\n\nimport { memo, useId } from \"react\";\nimport { cn } from \"@/lib/utils\";\nimport type {\n  PageHeroDensity,\n  PageHeroHeadingLevel,\n  PageHeroProps,\n} from \"./types\";\n\nconst DENSITY_CLASS: Record<PageHeroDensity, string> = {\n  compact: \"min-h-[40vh]\",\n  default: \"min-h-[70vh]\",\n  full: \"min-h-screen\",\n};\n\n/**\n * PageHero — full-bleed gradient hero band with badge / title /\n * highlight / description / children slot. Reveal animation uses the\n * existing pro-ui `reveal-up` keyframe (no framer-motion peer dep) with\n * 60ms staggered delays per the project's Motion mandate.\n *\n * Pair with the exported `HeroStats` sub-component for the typical\n * icon-circle + value + label triplet inside `children`.\n */\nfunction PageHeroImpl(props: PageHeroProps) {\n  const {\n    title,\n    titleSlot,\n    titleHighlight,\n    badge,\n    badgeIcon: BadgeIcon,\n    description,\n    children,\n    density = \"default\",\n    headingAs = \"h1\",\n    disableReveal = false,\n    className,\n  } = props;\n\n  const generatedId = useId();\n  const titleId = `${generatedId}-title`;\n  const HeadingTag = headingAs as PageHeroHeadingLevel;\n\n  const revealClass = disableReveal ? \"\" : \"reveal-up\";\n\n  return (\n    <section\n      aria-labelledby={titleId}\n      className={cn(\n        \"relative flex items-center justify-center overflow-hidden\",\n        DENSITY_CLASS[density],\n        className,\n      )}\n    >\n      {/* Gradient background + subtle noise overlay */}\n      <div className=\"absolute inset-0\">\n        <div className=\"absolute inset-0 bg-linear-to-br from-primary via-primary/95 to-primary/80\" />\n        <div\n          aria-hidden=\"true\"\n          className=\"absolute inset-0 opacity-50 bg-[url('data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNjAiIGhlaWdodD0iNjAiIHZpZXdCb3g9IjAgMCA2MCA2MCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48ZyBmaWxsPSJub25lIiBmaWxsLXJ1bGU9ImV2ZW5vZGQiPjxnIGZpbGw9IiNmZmZmZmYiIGZpbGwtb3BhY2l0eT0iMC4wMyI+PHBhdGggZD0iTTM2IDM0djItSDI0di0yaDEyek0zNiAyNHYySDI0di0yaDEyeiIvPjwvZz48L2c+PC9zdmc+')]\"\n        />\n      </div>\n\n      {/* Content stack */}\n      <div className=\"container relative z-10 mx-auto max-w-4xl px-4 py-24 text-center\">\n        {badge ? (\n          <span\n            className={cn(\n              \"mb-6 inline-flex items-center gap-2 rounded-full bg-primary-foreground/10 px-4 py-2 text-sm font-medium text-primary-foreground\",\n              revealClass,\n            )}\n            style={disableReveal ? undefined : { animationDelay: \"0ms\" }}\n          >\n            {BadgeIcon ? <BadgeIcon className=\"h-4 w-4\" aria-hidden=\"true\" /> : null}\n            {badge}\n          </span>\n        ) : null}\n\n        {titleSlot ? (\n          <div\n            className={revealClass}\n            style={disableReveal ? undefined : { animationDelay: \"60ms\" }}\n          >\n            {titleSlot}\n          </div>\n        ) : (\n          <HeadingTag\n            id={titleId}\n            className={cn(\n              \"mb-6 font-bold text-4xl text-primary-foreground md:text-5xl lg:text-6xl\",\n              revealClass,\n            )}\n            style={disableReveal ? undefined : { animationDelay: \"60ms\" }}\n          >\n            {title}\n            {titleHighlight ? (\n              <span className=\"block italic text-primary-foreground\">{titleHighlight}</span>\n            ) : null}\n          </HeadingTag>\n        )}\n\n        {description ? (\n          <p\n            className={cn(\n              \"mx-auto max-w-3xl text-lg text-primary-foreground/80 md:text-xl\",\n              revealClass,\n            )}\n            style={disableReveal ? undefined : { animationDelay: \"120ms\" }}\n          >\n            {description}\n          </p>\n        ) : null}\n\n        {children ? (\n          <div\n            className={cn(\"mt-10\", revealClass)}\n            style={disableReveal ? undefined : { animationDelay: \"180ms\" }}\n          >\n            {children}\n          </div>\n        ) : null}\n      </div>\n\n      {/* Bottom wave — fills with the page background so the section transitions cleanly */}\n      <div aria-hidden=\"true\" className=\"absolute -bottom-px left-0 right-0\">\n        <svg\n          viewBox=\"0 0 1440 120\"\n          fill=\"none\"\n          xmlns=\"http://www.w3.org/2000/svg\"\n          className=\"fill-background\"\n        >\n          <path d=\"M0 120L60 110C120 100 240 80 360 70C480 60 600 60 720 65C840 70 960 80 1080 85C1200 90 1320 90 1380 90L1440 90V120H1380C1320 120 1200 120 1080 120C960 120 840 120 720 120C600 120 480 120 360 120C240 120 120 120 60 120H0Z\" />\n        </svg>\n      </div>\n    </section>\n  );\n}\n\nexport const PageHero = memo(PageHeroImpl);\nPageHero.displayName = \"PageHero\";\n\nexport default PageHero;\nexport { HeroStats } from \"./parts/hero-stats\";\n",
      "type": "registry:component",
      "target": "components/page-hero/page-hero.tsx"
    },
    {
      "path": "src/registry/components/marketing/page-hero/index.ts",
      "content": "export { PageHero, HeroStats, default } from \"./page-hero\";\nexport type {\n  HeroStat,\n  HeroStatsProps,\n  PageHeroDensity,\n  PageHeroHeadingLevel,\n  PageHeroProps,\n} from \"./types\";\n",
      "type": "registry:component",
      "target": "components/page-hero/index.ts"
    },
    {
      "path": "src/registry/components/marketing/page-hero/types.ts",
      "content": "import type { ComponentType, ReactNode } from \"react\";\n\nexport type PageHeroDensity = \"compact\" | \"default\" | \"full\";\n\nexport type PageHeroHeadingLevel = \"h1\" | \"h2\" | \"h3\";\n\nexport interface HeroStat {\n  /** Optional Lucide-style icon. */\n  icon?: ComponentType<{ className?: string }>;\n  /** Bold value text (e.g. \"500+\", \"Daily\"). */\n  value: string;\n  /** Small label below the value (e.g. \"Articles\", \"Updates\"). */\n  label: string;\n}\n\nexport interface HeroStatsProps {\n  stats: HeroStat[];\n  className?: string;\n}\n\nexport interface PageHeroProps {\n  /** Title is required. */\n  title: string;\n  /** Override `title` with a custom node (e.g. mixed bold + colors). */\n  titleSlot?: ReactNode;\n  /** Optional accent-colored highlight rendered as a `<span class=\"block\">` below the title. */\n  titleHighlight?: string;\n  /** Optional badge text rendered above the title. */\n  badge?: string;\n  /** Optional Lucide-style icon for the badge. */\n  badgeIcon?: ComponentType<{ className?: string }>;\n  /** Optional description paragraph rendered below the title. */\n  description?: string;\n  /** Optional content slot rendered below the description (stats / CTAs / search / anything). */\n  children?: ReactNode;\n\n  /** Section minimum height. Default: 'default' (70vh). */\n  density?: PageHeroDensity;\n  /** Heading semantic level. Default: 'h1'. */\n  headingAs?: PageHeroHeadingLevel;\n  /** Disable the entrance animation entirely. Default: false. */\n  disableReveal?: boolean;\n\n  /** Override classes for the root <section>. */\n  className?: string;\n}\n",
      "type": "registry:component",
      "target": "components/page-hero/types.ts"
    },
    {
      "path": "src/registry/components/marketing/page-hero/parts/hero-stats.tsx",
      "content": "import { cn } from \"@/lib/utils\";\nimport type { HeroStatsProps } from \"../types\";\n\n/**\n * 3-stat row pattern from the kasder NewsHero — icon-circle + bold value\n * + small label, repeated horizontally. Designed to live inside the hero's\n * `children` slot; inherits primary-foreground (near-black) text from the\n * lime gradient background per the design-system mandate.\n */\nexport function HeroStats({ stats, className }: HeroStatsProps) {\n  return (\n    <div className={cn(\"flex flex-wrap justify-center gap-8\", className)}>\n      {stats.map((stat, index) => {\n        const Icon = stat.icon;\n        return (\n          <div\n            key={index}\n            className=\"flex items-center gap-3 text-primary-foreground/90\"\n          >\n            {Icon ? (\n              <div className=\"flex h-12 w-12 items-center justify-center rounded-full bg-primary-foreground/10\">\n                <Icon className=\"h-5 w-5\" />\n              </div>\n            ) : null}\n            <div className=\"text-left\">\n              <div className=\"text-2xl font-bold\">{stat.value}</div>\n              <div className=\"text-sm text-primary-foreground/70\">{stat.label}</div>\n            </div>\n          </div>\n        );\n      })}\n    </div>\n  );\n}\n",
      "type": "registry:component",
      "target": "components/page-hero/parts/hero-stats.tsx"
    }
  ],
  "categories": [
    "marketing",
    "news"
  ],
  "type": "registry:block"
}