{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "features-bento",
  "title": "Bento feature grid",
  "description": "Five-card bento grid with live visuals: integration beams, orbiting icons, a chart, a tag marquee and a globe.",
  "dependencies": [
    "lucide-react"
  ],
  "registryDependencies": [
    "utils",
    "https://velora.colorlib.com/r/animated-beam.json",
    "https://velora.colorlib.com/r/bento-grid.json",
    "https://velora.colorlib.com/r/blur-fade.json",
    "https://velora.colorlib.com/r/globe.json",
    "https://velora.colorlib.com/r/marquee.json",
    "https://velora.colorlib.com/r/number-ticker.json",
    "https://velora.colorlib.com/r/orbiting-circles.json"
  ],
  "files": [
    {
      "path": "src/components/blocks/features-bento.tsx",
      "content": "\"use client\";\n\nimport { useId, useRef, type Ref } from \"react\";\nimport {\n  BellIcon,\n  BotIcon,\n  CalendarIcon,\n  CloudIcon,\n  CommandIcon,\n  CreditCardIcon,\n  DatabaseIcon,\n  GitBranchIcon,\n  MailIcon,\n  MessageSquareIcon,\n  SearchIcon,\n  TrendingUpIcon,\n  WebhookIcon,\n  WorkflowIcon,\n  ZapIcon,\n} from \"lucide-react\";\n\nimport { AnimatedBeam } from \"@/components/velora/animated-beam\";\nimport { BentoCard, BentoGrid } from \"@/components/velora/bento-grid\";\nimport { BlurFade } from \"@/components/velora/blur-fade\";\nimport { Globe, type GlobeArc, type GlobeMarker } from \"@/components/velora/globe\";\nimport { Marquee } from \"@/components/velora/marquee\";\nimport { NumberTicker } from \"@/components/velora/number-ticker\";\nimport { OrbitingCircles } from \"@/components/velora/orbiting-circles\";\nimport { cn } from \"@/lib/utils\";\n\nconst HEADING = {\n  eyebrow: \"Platform\",\n  title: \"Everything your team needs, in one place\",\n  description:\n    \"Acme connects your tools, automates the busywork and shows you what is working — so every release lands a little faster than the last.\",\n};\n\nconst CARDS = {\n  integrations: {\n    name: \"Connect every tool you use\",\n    description: \"Two-way sync with your database, inbox, billing and calendar in a few clicks.\",\n    cta: \"Browse integrations\",\n  },\n  automations: {\n    name: \"Automations that run themselves\",\n    description: \"Trigger workflows from any event and let bots handle the follow-ups.\",\n    cta: \"Explore automations\",\n  },\n  analytics: {\n    name: \"Live analytics\",\n    description: \"Revenue, usage and retention update the moment something changes.\",\n    cta: \"See the dashboards\",\n  },\n  search: {\n    name: \"Find anything instantly\",\n    description: \"One search across issues, docs, people and threads. Press ⌘K from anywhere.\",\n    cta: \"Try search\",\n  },\n  edge: {\n    name: \"Fast everywhere\",\n    description: \"Served from 30 regions, so every page loads in under 100 ms.\",\n    cta: \"View regions\",\n  },\n};\n\nconst TAGS = [\n  \"roadmap\",\n  \"Q3 launch\",\n  \"design review\",\n  \"billing\",\n  \"onboarding\",\n  \"api v2\",\n  \"incident #42\",\n  \"hiring\",\n  \"changelog\",\n  \"pricing page\",\n  \"mobile app\",\n  \"research\",\n];\n\n// Revenue over the last 12 weeks, in thousands.\nconst SERIES = [18, 22, 20, 27, 25, 31, 29, 34, 38, 36, 43, 48];\n\nconst MARKERS: GlobeMarker[] = [\n  { lat: 38.9, lng: -77.0, label: \"Virginia\" },\n  { lat: 50.1, lng: 8.7, label: \"Frankfurt\" },\n  { lat: -23.5, lng: -46.6, label: \"São Paulo\" },\n  { lat: 1.35, lng: 103.8 },\n  { lat: 35.7, lng: 139.7 },\n];\n\nconst ARCS: GlobeArc[] = [\n  { from: [38.9, -77.0], to: [50.1, 8.7] },\n  { from: [38.9, -77.0], to: [-23.5, -46.6] },\n  { from: [50.1, 8.7], to: [1.35, 103.8] },\n];\n\n/**\n * Bento feature grid: five cards, each with a live visual — integration\n * beams, orbiting automations, a revenue chart, a tag marquee and a globe.\n * Edit the consts above; the visuals re-theme from your brand tokens.\n */\nexport function FeaturesBento() {\n  return (\n    <section className=\"relative isolate overflow-hidden px-6 py-24 sm:py-32 lg:px-8\">\n      <div\n        aria-hidden\n        className=\"absolute inset-x-0 top-0 -z-10 h-96 bg-gradient-to-b from-brand/5 to-transparent\"\n      />\n      <div className=\"mx-auto max-w-7xl\">\n        <BlurFade>\n          <div className=\"mx-auto max-w-2xl text-center\">\n            <p className=\"text-sm font-semibold text-primary\">{HEADING.eyebrow}</p>\n            <h2 className=\"mt-3 text-3xl font-semibold tracking-tight text-balance sm:text-5xl\">\n              {HEADING.title}\n            </h2>\n            <p className=\"mt-5 text-lg text-pretty text-muted-foreground\">\n              {HEADING.description}\n            </p>\n          </div>\n        </BlurFade>\n\n        <BlurFade delay={0.1}>\n          <BentoGrid className=\"mt-16 md:grid-cols-2 lg:grid-cols-3\">\n            <BentoCard\n              {...CARDS.integrations}\n              href=\"#\"\n              className=\"md:col-span-2\"\n              background={<IntegrationsVisual />}\n            />\n            <BentoCard {...CARDS.automations} href=\"#\" background={<AutomationsVisual />} />\n            <BentoCard {...CARDS.analytics} href=\"#\" background={<AnalyticsVisual />} />\n            <BentoCard {...CARDS.search} href=\"#\" background={<SearchVisual />} />\n            <BentoCard {...CARDS.edge} href=\"#\" background={<EdgeVisual />} />\n          </BentoGrid>\n        </BlurFade>\n      </div>\n    </section>\n  );\n}\n\nfunction Node({\n  ref,\n  className,\n  children,\n}: {\n  ref?: Ref<HTMLDivElement>;\n  className?: string;\n  children: React.ReactNode;\n}) {\n  return (\n    <div\n      ref={ref}\n      className={cn(\n        \"z-10 grid size-11 place-items-center rounded-full border bg-card text-muted-foreground shadow-md shadow-foreground/5 sm:size-12 [&_svg]:size-5\",\n        className\n      )}\n    >\n      {children}\n    </div>\n  );\n}\n\nfunction IntegrationsVisual() {\n  const container = useRef<HTMLDivElement>(null);\n  const hub = useRef<HTMLDivElement>(null);\n  const l1 = useRef<HTMLDivElement>(null);\n  const l2 = useRef<HTMLDivElement>(null);\n  const l3 = useRef<HTMLDivElement>(null);\n  const r1 = useRef<HTMLDivElement>(null);\n  const r2 = useRef<HTMLDivElement>(null);\n  const r3 = useRef<HTMLDivElement>(null);\n  // Beams start at the hub: the component's highlight eases out, so it\n  // lingers where each beam ends — at the integration it syncs with.\n  const beams = [\n    { to: l1, curvature: -40, delay: 0, reverse: true },\n    { to: l2, curvature: 0, delay: 0.8, reverse: true },\n    { to: l3, curvature: 40, delay: 1.6, reverse: true },\n    { to: r1, curvature: -40, delay: 0.4 },\n    { to: r2, curvature: 0, delay: 1.2 },\n    { to: r3, curvature: 40, delay: 2 },\n  ];\n\n  return (\n    <div aria-hidden className=\"absolute inset-x-0 top-0 h-60 px-6 pt-6 sm:px-16\">\n      <div ref={container} className=\"relative flex h-full items-center justify-between\">\n        <div className=\"flex h-full flex-col justify-between py-2\">\n          <Node ref={l1}>\n            <DatabaseIcon />\n          </Node>\n          <Node ref={l2} className=\"-translate-x-2 sm:-translate-x-6\">\n            <MailIcon />\n          </Node>\n          <Node ref={l3}>\n            <CreditCardIcon />\n          </Node>\n        </div>\n\n        <div\n          ref={hub}\n          className=\"relative z-10 grid size-16 place-items-center rounded-2xl bg-gradient-to-br from-brand-from via-brand-via to-brand-to text-brand-foreground shadow-xl shadow-brand/30 ring-4 ring-background sm:size-20\"\n        >\n          <ZapIcon className=\"size-7 sm:size-9\" />\n        </div>\n\n        <div className=\"flex h-full flex-col justify-between py-2\">\n          <Node ref={r1}>\n            <CalendarIcon />\n          </Node>\n          <Node ref={r2} className=\"translate-x-2 sm:translate-x-6\">\n            <MessageSquareIcon />\n          </Node>\n          <Node ref={r3}>\n            <CloudIcon />\n          </Node>\n        </div>\n\n        {beams.map((beam, i) => (\n          <AnimatedBeam\n            key={i}\n            containerRef={container}\n            fromRef={hub}\n            toRef={beam.to}\n            curvature={beam.curvature}\n            delay={beam.delay}\n            reverse={beam.reverse}\n            duration={4}\n            gradientStartColor=\"var(--brand-from)\"\n            gradientStopColor=\"var(--brand-to)\"\n          />\n        ))}\n      </div>\n    </div>\n  );\n}\n\nfunction Satellite({ children }: { children: React.ReactNode }) {\n  return (\n    <div className=\"grid size-full place-items-center rounded-full border bg-card text-muted-foreground shadow-sm [&_svg]:size-4\">\n      {children}\n    </div>\n  );\n}\n\nfunction AutomationsVisual() {\n  return (\n    <div aria-hidden className=\"absolute inset-x-0 top-0 flex h-64 items-center justify-center\">\n      <div className=\"grid size-14 place-items-center rounded-full border border-primary/30 bg-primary/10 text-primary shadow-lg shadow-primary/20\">\n        <WorkflowIcon className=\"size-6\" />\n      </div>\n      <OrbitingCircles radius={56} iconSize={32} duration={16}>\n        <Satellite>\n          <BellIcon />\n        </Satellite>\n        <Satellite>\n          <BotIcon />\n        </Satellite>\n        <Satellite>\n          <WebhookIcon />\n        </Satellite>\n      </OrbitingCircles>\n      <OrbitingCircles radius={100} iconSize={36} duration={28} reverse>\n        <Satellite>\n          <MailIcon />\n        </Satellite>\n        <Satellite>\n          <GitBranchIcon />\n        </Satellite>\n        <Satellite>\n          <CalendarIcon />\n        </Satellite>\n        <Satellite>\n          <DatabaseIcon />\n        </Satellite>\n      </OrbitingCircles>\n    </div>\n  );\n}\n\nfunction AnalyticsVisual() {\n  const id = useId();\n  const w = 300;\n  const h = 110;\n  const max = Math.max(...SERIES);\n  const points = SERIES.map(\n    (v, i) => [(i / (SERIES.length - 1)) * w, h - (v / max) * (h - 12)] as const\n  );\n  const line = points.map(([x, y], i) => `${i ? \"L\" : \"M\"}${x.toFixed(1)} ${y.toFixed(1)}`).join(\" \");\n  const [lastX, lastY] = points[points.length - 1];\n\n  return (\n    <div aria-hidden className=\"absolute inset-x-0 top-0 flex h-60 flex-col gap-4 p-6\">\n      <div className=\"flex items-start justify-between\">\n        <div>\n          <p className=\"text-xs font-medium text-muted-foreground\">Monthly revenue</p>\n          <p className=\"mt-1 text-3xl font-semibold tracking-tight\">\n            <NumberTicker value={48.2} decimalPlaces={1} prefix=\"$\" suffix=\"k\" />\n          </p>\n        </div>\n        <span className=\"inline-flex items-center gap-1 rounded-full bg-primary/10 px-2 py-1 text-xs font-medium text-primary\">\n          <TrendingUpIcon className=\"size-3.5\" />\n          12.4%\n        </span>\n      </div>\n      <svg\n        viewBox={`0 0 ${w} ${h}`}\n        preserveAspectRatio=\"none\"\n        className=\"w-full flex-1 overflow-visible\"\n      >\n        <defs>\n          <linearGradient id={id} x1=\"0\" x2=\"0\" y1=\"0\" y2=\"1\">\n            <stop offset=\"0%\" style={{ stopColor: \"var(--brand)\", stopOpacity: 0.3 }} />\n            <stop offset=\"100%\" style={{ stopColor: \"var(--brand)\", stopOpacity: 0 }} />\n          </linearGradient>\n        </defs>\n        {[0.25, 0.5, 0.75].map((f) => (\n          <line\n            key={f}\n            x1=\"0\"\n            x2={w}\n            y1={h * f}\n            y2={h * f}\n            className=\"stroke-border\"\n            strokeDasharray=\"3 4\"\n            vectorEffect=\"non-scaling-stroke\"\n          />\n        ))}\n        <path d={`${line} L${w} ${h} L0 ${h} Z`} fill={`url(#${id})`} />\n        <path\n          d={line}\n          fill=\"none\"\n          className=\"stroke-brand\"\n          strokeWidth=\"2\"\n          strokeLinejoin=\"round\"\n          vectorEffect=\"non-scaling-stroke\"\n        />\n        <circle cx={lastX} cy={lastY} r=\"4\" className=\"fill-brand stroke-card\" strokeWidth=\"2\" vectorEffect=\"non-scaling-stroke\" />\n      </svg>\n    </div>\n  );\n}\n\nfunction Tag({ children }: { children: React.ReactNode }) {\n  return (\n    <span className=\"inline-flex items-center gap-1.5 rounded-full border bg-background px-3 py-1 text-xs font-medium whitespace-nowrap text-muted-foreground\">\n      <span className=\"text-primary\">#</span>\n      {children}\n    </span>\n  );\n}\n\nfunction SearchVisual() {\n  const half = Math.ceil(TAGS.length / 2);\n  return (\n    <div aria-hidden className=\"absolute inset-x-0 top-0 flex h-60 flex-col gap-4 pt-6\">\n      <div className=\"mx-6 flex items-center gap-2 rounded-xl border bg-background px-3 py-2.5 text-sm text-muted-foreground shadow-sm\">\n        <SearchIcon className=\"size-4 shrink-0\" />\n        <span className=\"truncate\">Search issues, docs and people…</span>\n        <kbd className=\"ml-auto inline-flex shrink-0 items-center gap-0.5 rounded-md border bg-muted px-1.5 py-0.5 font-sans text-[11px]\">\n          <CommandIcon className=\"size-3\" />K\n        </kbd>\n      </div>\n      <div className=\"flex flex-col gap-2.5\">\n        <Marquee className=\"[--duration:30s] [--gap:0.5rem]\">\n          {TAGS.slice(0, half).map((tag) => (\n            <Tag key={tag}>{tag}</Tag>\n          ))}\n        </Marquee>\n        <Marquee reverse className=\"[--duration:34s] [--gap:0.5rem]\">\n          {TAGS.slice(half).map((tag) => (\n            <Tag key={tag}>{tag}</Tag>\n          ))}\n        </Marquee>\n        <Marquee className=\"[--duration:38s] [--gap:0.5rem]\">\n          {[...TAGS].reverse().map((tag) => (\n            <Tag key={tag}>{tag}</Tag>\n          ))}\n        </Marquee>\n      </div>\n    </div>\n  );\n}\n\nfunction EdgeVisual() {\n  return (\n    <div className=\"absolute inset-x-0 -top-6 flex justify-center\">\n      <Globe\n        markers={MARKERS}\n        arcs={ARCS}\n        center={[30, -20]}\n        className=\"w-72 sm:w-80\"\n        label=\"Globe showing Acme edge regions in Virginia, Frankfurt, São Paulo, Singapore and Tokyo\"\n      />\n    </div>\n  );\n}\n",
      "type": "registry:component",
      "target": "components/blocks/features-bento.tsx"
    }
  ],
  "categories": [
    "feature-sections"
  ],
  "type": "registry:block"
}