{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "hero-cover-01",
  "title": "Hero Cover Photo",
  "description": "A full-bleed photo with the title, a small label, a short description, and one call to action along its bottom edge",
  "dependencies": [
    "class-variance-authority",
    "motion@13"
  ],
  "registryDependencies": [
    "https://ui.cortexcn.dev/r/utils.json",
    "button"
  ],
  "files": [
    {
      "path": "registry/blocks/hero-cover-01/components/hero-cover.tsx",
      "content": "\"use client\";\n\nimport { motion, useReducedMotion, type Variants } from \"motion/react\";\nimport type { ReactNode } from \"react\";\n\nimport { cn } from \"@/lib/utils\";\n\nimport { Cta, type CtaProps } from \"./hero-cta\";\n\n// Cortexcn item \"hero-cover-01\", revision 912eb1a56a04, MIT license.\n// https://ui.cortexcn.dev/r/v/hero-cover-01/912eb1a56a04.json\n\nexport interface HeroCoverProps {\n  title?: string;\n  /** Small caps label beside the title, such as a founding year. */\n  established?: string;\n  description?: string;\n  /** Full-bleed photo, darkened toward the bottom so the copy reads. */\n  backgroundImage?: string;\n  backgroundAlt?: string;\n  animation?: \"none\" | \"subtle\";\n  primaryCTA?: CtaProps;\n  variant?: \"standard\" | \"compact\";\n}\n\nconst DEFAULTS = {\n  title: \"Aspen Ridge\",\n  established: \"Est. 2019\",\n  description:\n    \"A secluded mountain retreat set among the aspens, with floor-to-ceiling windows framing uninterrupted views of the Rockies. Wake to still water, quiet forest, and nothing on the schedule.\",\n  // Sample photo from Unsplash (free to use under the Unsplash License).\n  backgroundImage:\n    \"https://images.unsplash.com/photo-1626849440347-a491d028c0cf?q=80&w=1631&auto=format&fit=crop\",\n  backgroundAlt: \"A calm mountain lake at dusk beneath a forested ridge\",\n  primaryCTA: {\n    ctaEnabled: true,\n    text: \"Reserve a Stay\",\n    link: \"\",\n    size: \"default\",\n  },\n} satisfies HeroCoverProps;\n\nconst variantStyles = {\n  standard: {\n    section: \"min-h-[560px] sm:min-h-[600px]\",\n    padding: \"px-6 py-10 sm:px-10 sm:py-12\",\n    title: \"text-4xl sm:text-5xl md:text-6xl\",\n    established: \"text-xs sm:text-sm\",\n    description: \"max-w-lg text-sm sm:text-base\",\n    copy: \"gap-5 sm:gap-6\",\n  },\n  compact: {\n    section: \"min-h-[440px] sm:min-h-[480px]\",\n    padding: \"px-6 py-8 sm:px-8 sm:py-10\",\n    title: \"text-3xl sm:text-4xl md:text-5xl\",\n    established: \"text-[0.65rem] sm:text-xs\",\n    description: \"max-w-md text-sm\",\n    copy: \"gap-4 sm:gap-5\",\n  },\n} as const;\n\nconst container: Variants = {\n  hidden: {},\n  visible: { transition: { staggerChildren: 0.12, delayChildren: 0.1 } },\n};\n\nconst item: Variants = {\n  hidden: { opacity: 0, y: 16, filter: \"blur(6px)\" },\n  visible: {\n    opacity: 1,\n    y: 0,\n    filter: \"blur(0px)\",\n    transition: { duration: 0.5, ease: [0.22, 1, 0.36, 1] },\n  },\n};\n\nconst media: Variants = {\n  hidden: { opacity: 0, scale: 1.08 },\n  visible: {\n    opacity: 1,\n    scale: 1,\n    transition: { duration: 0.8, ease: [0.22, 1, 0.36, 1] },\n  },\n};\n\nfunction Reveal({\n  active,\n  variants,\n  className,\n  children,\n}: Readonly<{\n  active: boolean;\n  variants?: Variants;\n  className?: string;\n  children: ReactNode;\n}>) {\n  if (!active) {\n    return <div className={className}>{children}</div>;\n  }\n\n  return (\n    <motion.div className={className} variants={variants ?? item}>\n      {children}\n    </motion.div>\n  );\n}\n\n/**\n * A full-bleed photo with the title, a small label, a short description, and\n * one light call to action set along its bottom edge.\n */\nexport function HeroCover({\n  title = DEFAULTS.title,\n  established = DEFAULTS.established,\n  description = DEFAULTS.description,\n  backgroundImage = DEFAULTS.backgroundImage,\n  backgroundAlt = DEFAULTS.backgroundAlt,\n  animation = \"subtle\",\n  primaryCTA = DEFAULTS.primaryCTA,\n  variant = \"standard\",\n}: Readonly<HeroCoverProps>) {\n  const reduce = useReducedMotion();\n  const animate = animation === \"subtle\" && !reduce;\n  const vs = variantStyles[variant];\n\n  return (\n    <section\n      className={cn(\n        \"relative isolate flex w-full flex-col justify-end overflow-hidden bg-background\",\n        vs.section,\n      )}\n    >\n      {backgroundImage && (\n        <div className=\"absolute inset-0 z-0 overflow-hidden\">\n          {/* biome-ignore lint/performance/noImgElement: framework-agnostic registry block */}\n          <motion.img\n            alt={backgroundAlt}\n            className=\"size-full object-cover\"\n            decoding=\"async\"\n            height={1088}\n            initial={animate ? \"hidden\" : false}\n            src={backgroundImage}\n            variants={animate ? media : undefined}\n            viewport={{ once: true, margin: \"-80px\" }}\n            whileInView={animate ? \"visible\" : undefined}\n            width={1631}\n          />\n          <div\n            aria-hidden=\"true\"\n            className=\"absolute inset-0 bg-linear-to-t from-black/70 via-black/25 to-black/10\"\n          />\n        </div>\n      )}\n\n      <motion.div\n        className={cn(\n          \"relative z-10 flex w-full flex-col gap-6 sm:flex-row sm:items-end sm:justify-between\",\n          vs.padding,\n        )}\n        initial={animate ? \"hidden\" : false}\n        variants={animate ? container : undefined}\n        viewport={{ once: true, margin: \"-80px\" }}\n        whileInView={animate ? \"visible\" : undefined}\n      >\n        <Reveal active={animate} className=\"min-w-0\">\n          <div className={cn(\"flex flex-col\", vs.copy)}>\n            {title && (\n              <div className=\"flex flex-wrap items-baseline gap-x-4 gap-y-1\">\n                <h1\n                  className={cn(\n                    \"text-balance font-normal text-white tracking-tight\",\n                    vs.title,\n                  )}\n                >\n                  {title}\n                </h1>\n                {established && (\n                  <span\n                    className={cn(\n                      \"font-medium text-white/70 uppercase tracking-widest\",\n                      vs.established,\n                    )}\n                  >\n                    {established}\n                  </span>\n                )}\n              </div>\n            )}\n            {description && (\n              <p\n                className={cn(\n                  \"text-balance text-white/80 leading-relaxed\",\n                  vs.description,\n                )}\n              >\n                {description}\n              </p>\n            )}\n          </div>\n        </Reveal>\n\n        {primaryCTA?.ctaEnabled && (\n          <Reveal active={animate}>\n            <Cta className=\"shrink-0\" cta={primaryCTA} invert />\n          </Reveal>\n        )}\n      </motion.div>\n    </section>\n  );\n}\n",
      "type": "registry:component",
      "target": "components/hero-cover.tsx"
    },
    {
      "path": "registry/blocks/hero-cover-01/components/hero-cta.tsx",
      "content": "import { cva, type VariantProps } from \"class-variance-authority\";\n\nimport { Button, buttonVariants } from \"@/components/ui/button\";\nimport { cn } from \"@/lib/utils\";\n\n// Cortexcn item \"hero-cover-01\", revision 912eb1a56a04, MIT license.\n// https://ui.cortexcn.dev/r/v/hero-cover-01/912eb1a56a04.json\n\ntype ButtonVariants = VariantProps<typeof buttonVariants>;\n\nexport type ButtonVariant = NonNullable<ButtonVariants[\"variant\"]>;\n\nexport interface CtaProps {\n  ctaEnabled?: boolean;\n  text: string;\n  /** Leave empty to render a button instead of a link. */\n  link: string;\n  variant?: ButtonVariant;\n  size?: \"default\" | \"sm\" | \"lg\";\n}\n\nconst ctaVariants = cva(\"w-fit rounded-full px-4\", {\n  variants: {\n    invert: {\n      true: \"border-transparent! bg-white! text-zinc-900! hover:bg-zinc-100!\",\n      false: \"\",\n    },\n  },\n  defaultVariants: {\n    invert: false,\n  },\n});\n\nexport function Cta({\n  cta,\n  className,\n  invert,\n}: Readonly<{ cta?: CtaProps; className?: string; invert?: boolean }>) {\n  if (!cta?.ctaEnabled) {\n    return null;\n  }\n\n  const variant = cta.variant ?? (invert ? \"secondary\" : \"default\");\n\n  if (!cta.link) {\n    return (\n      <Button\n        aria-label={cta.text}\n        className={cn(ctaVariants({ invert }), className)}\n        size={cta.size ?? \"default\"}\n        type=\"button\"\n        variant={variant}\n      >\n        {cta.text}\n      </Button>\n    );\n  }\n\n  return (\n    // No aria-label here, so screen readers also hear \"(opens in new tab)\".\n    <a\n      className={cn(\n        buttonVariants({\n          variant,\n          size: cta.size ?? \"default\",\n          className: cn(ctaVariants({ invert }), className),\n        }),\n      )}\n      href={cta.link}\n      rel=\"noopener noreferrer\"\n      target=\"_blank\"\n    >\n      {cta.text}\n      <span className=\"sr-only\">{`${cta.text} (opens in new tab)`}</span>\n    </a>\n  );\n}\n",
      "type": "registry:component",
      "target": "components/hero-cta.tsx"
    }
  ],
  "type": "registry:block",
  "author": "Cortexcn (https://ui.cortexcn.dev)",
  "meta": {
    "license": "MIT",
    "revision": "912eb1a56a04"
  }
}