{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "feature-spotlight-grid-01",
  "title": "Feature Spotlight Grid",
  "description": "Six icon cards under a centered intro, with one soft highlight that glides to the card you point at",
  "dependencies": [
    "motion@13"
  ],
  "registryDependencies": [
    "https://ui.cortexcn.dev/r/utils.json"
  ],
  "files": [
    {
      "path": "registry/blocks/feature-spotlight-grid-01/components/feature-spotlight-grid.tsx",
      "content": "\"use client\";\n\nimport { motion, useReducedMotion } from \"motion/react\";\nimport { type ReactNode, useState } from \"react\";\nimport { cn } from \"@/lib/utils\";\n\n// Cortexcn item \"feature-spotlight-grid-01\", revision 8d557dddbbbd, MIT license.\n// https://ui.cortexcn.dev/r/v/feature-spotlight-grid-01/8d557dddbbbd.json\n\nexport interface SpotlightFeature {\n  title: string;\n  description: string;\n  icon?: ReactNode;\n}\n\nexport interface FeatureSpotlightGridProps {\n  label?: string;\n  heading?: string;\n  description?: string;\n  /** Up to six reads best; the grid wraps any number. */\n  features?: SpotlightFeature[];\n  className?: string;\n}\n\ninterface Highlight {\n  x: number;\n  y: number;\n  width: number;\n  height: number;\n  visible: boolean;\n  /** Jump straight to the card instead of gliding (first hover after leaving). */\n  snap: boolean;\n}\n\nconst SPRING = { type: \"spring\", stiffness: 420, damping: 38 } as const;\n\nfunction IconFrame({ children }: { children: ReactNode }) {\n  return (\n    <svg\n      aria-hidden=\"true\"\n      className=\"size-5\"\n      fill=\"none\"\n      stroke=\"currentColor\"\n      strokeLinecap=\"round\"\n      strokeLinejoin=\"round\"\n      strokeWidth=\"1.75\"\n      viewBox=\"0 0 24 24\"\n      xmlns=\"http://www.w3.org/2000/svg\"\n    >\n      {children}\n    </svg>\n  );\n}\n\nconst DEFAULT_FEATURES: SpotlightFeature[] = [\n  {\n    title: \"Code you own\",\n    description:\n      \"Components install as source files in your project, so nothing is hidden behind a package.\",\n    icon: (\n      <IconFrame>\n        <path d=\"M8 7l-5 5 5 5M16 7l5 5-5 5\" />\n      </IconFrame>\n    ),\n  },\n  {\n    title: \"Fits every screen\",\n    description:\n      \"Layouts adapt from phones to wide monitors with Tailwind's responsive utilities.\",\n    icon: (\n      <IconFrame>\n        <rect height=\"11\" rx=\"1.5\" width=\"15\" x=\"2\" y=\"4\" />\n        <rect height=\"11\" rx=\"1.5\" width=\"6\" x=\"16\" y=\"9\" />\n        <path d=\"M7 19h5\" />\n      </IconFrame>\n    ),\n  },\n  {\n    title: \"Keyboard friendly\",\n    description:\n      \"Focus states, labels, and keyboard support come built in, not bolted on later.\",\n    icon: (\n      <IconFrame>\n        <rect height=\"12\" rx=\"2\" width=\"20\" x=\"2\" y=\"6\" />\n        <path d=\"M6 10h.01M10 10h.01M14 10h.01M18 10h.01M7 14h10\" />\n      </IconFrame>\n    ),\n  },\n  {\n    title: \"Typed end to end\",\n    description:\n      \"Every prop has a type, so your editor flags mistakes before they reach production.\",\n    icon: (\n      <IconFrame>\n        <rect height=\"18\" rx=\"3\" width=\"18\" x=\"3\" y=\"3\" />\n        <path d=\"M7.5 10h5M10 10v7M14.5 16.5c.4.4 1 .5 1.6.5 1 0 1.9-.5 1.9-1.5 0-2-3.5-1-3.5-3 0-.9.8-1.5 1.8-1.5.6 0 1.1.2 1.5.5\" />\n      </IconFrame>\n    ),\n  },\n  {\n    title: \"Easy to restyle\",\n    description:\n      \"Change colors, spacing, and copy through props and CSS variables, not overrides.\",\n    icon: (\n      <IconFrame>\n        <path d=\"M4 6h10M18 6h2M4 12h4M12 12h8M4 18h12M20 18h0\" />\n        <circle cx=\"16\" cy=\"6\" r=\"2\" />\n        <circle cx=\"10\" cy=\"12\" r=\"2\" />\n        <circle cx=\"18\" cy=\"18\" r=\"2\" />\n      </IconFrame>\n    ),\n  },\n  {\n    title: \"Light on dependencies\",\n    description:\n      \"Most blocks need nothing beyond React, Tailwind, and a small utils file.\",\n    icon: (\n      <IconFrame>\n        <path d=\"M13 2L4 14h7l-1 8 9-12h-7l1-8z\" />\n      </IconFrame>\n    ),\n  },\n];\n\nexport function FeatureSpotlightGrid({\n  label = \"Features\",\n  heading = \"Everything you need to ship the page\",\n  description = \"Open code components you can read, change, and keep. Start with good defaults, then make every detail fit your product.\",\n  features = DEFAULT_FEATURES,\n  className,\n}: FeatureSpotlightGridProps) {\n  const reduceMotion = useReducedMotion();\n  const [highlight, setHighlight] = useState<Highlight | null>(null);\n\n  const moveHighlightTo = (card: HTMLElement) => {\n    setHighlight((current) => ({\n      x: card.offsetLeft,\n      y: card.offsetTop,\n      width: card.offsetWidth,\n      height: card.offsetHeight,\n      visible: true,\n      snap: !current?.visible,\n    }));\n  };\n\n  const hideHighlight = () => {\n    setHighlight((current) => current && { ...current, visible: false });\n  };\n\n  const snap = reduceMotion || highlight?.snap !== false;\n\n  return (\n    <section className={cn(\"px-6 py-24 sm:py-32\", className)}>\n      <div className=\"mx-auto flex max-w-6xl flex-col items-center text-center\">\n        <span className=\"rounded-full border bg-muted/50 px-3 py-1 font-medium text-muted-foreground text-xs uppercase tracking-wider\">\n          {label}\n        </span>\n        <h2 className=\"mt-6 max-w-3xl text-balance font-semibold text-4xl tracking-tight sm:text-5xl\">\n          {heading}\n        </h2>\n        <p className=\"mt-5 max-w-2xl text-balance text-lg text-muted-foreground\">\n          {description}\n        </p>\n\n        <div\n          className=\"relative mt-14 grid w-full grid-cols-1 text-left sm:grid-cols-2 lg:grid-cols-3\"\n          onPointerLeave={hideHighlight}\n        >\n          <motion.div\n            animate={\n              highlight\n                ? {\n                    opacity: highlight.visible ? 1 : 0,\n                    x: highlight.x,\n                    y: highlight.y,\n                    width: highlight.width,\n                    height: highlight.height,\n                  }\n                : { opacity: 0 }\n            }\n            aria-hidden=\"true\"\n            className=\"pointer-events-none absolute top-0 left-0 rounded-3xl bg-muted\"\n            initial={false}\n            transition={\n              snap\n                ? { opacity: { duration: 0.15 }, default: { duration: 0 } }\n                : { opacity: { duration: 0.2 }, default: SPRING }\n            }\n          />\n\n          {features.map((feature) => (\n            <div\n              className=\"relative p-2\"\n              key={feature.title}\n              onPointerEnter={(event) => moveHighlightTo(event.currentTarget)}\n            >\n              <div className=\"relative flex h-full flex-col gap-4 rounded-2xl border bg-card p-6 shadow-xs\">\n                <span className=\"flex size-10 items-center justify-center rounded-xl border bg-muted/60 text-foreground\">\n                  {feature.icon}\n                </span>\n                <div>\n                  <h3 className=\"font-semibold text-lg tracking-tight\">\n                    {feature.title}\n                  </h3>\n                  <p className=\"mt-1.5 text-muted-foreground text-sm leading-relaxed\">\n                    {feature.description}\n                  </p>\n                </div>\n              </div>\n            </div>\n          ))}\n        </div>\n      </div>\n    </section>\n  );\n}\n",
      "type": "registry:component",
      "target": "components/feature-spotlight-grid.tsx"
    }
  ],
  "type": "registry:block",
  "author": "Cortexcn (https://ui.cortexcn.dev)",
  "meta": {
    "license": "MIT",
    "revision": "8d557dddbbbd"
  }
}