{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "pricing-plans",
  "type": "registry:component",
  "title": "Pricing plans",
  "description": "A React pricing section with a monthly or yearly switch that rolls prices to the new value, a featured ink plan, and feature rows marked included or not.",
  "dependencies": [
    "lucide-react"
  ],
  "registryDependencies": [
    "https://ui.minidev.pro/r/button.json",
    "https://ui.minidev.pro/r/number-roll.json",
    "https://ui.minidev.pro/r/segmented-control.json",
    "utils"
  ],
  "files": [
    {
      "path": "registry/blocks/pricing-plans.tsx",
      "type": "registry:ui",
      "target": "components/ui/pricing-plans.tsx",
      "content": "\"use client\"\nimport * as React from \"react\"\nimport { CheckIcon, MinusIcon } from \"lucide-react\"\nimport { cn } from \"@/lib/utils\"\nimport { Button } from \"@/components/ui/button\"\nimport { NumberRoll } from \"@/components/ui/number-roll\"\nimport { SegmentedControl } from \"@/components/ui/segmented-control\"\n\n/*\n * PricingPlans: plans with a period switch whose prices roll to the new\n * number, a featured plan in ink with a lit top edge, and feature rows that\n * say yes or no plainly. Seats slider optional.\n */\n\ntype Plan = {\n  name: string\n  blurb: string\n  monthly: number\n  yearly: number\n  cta: string\n  featured?: boolean\n  features: (string | { label: string; included: false })[]\n}\n\ntype PricingPlansProps = {\n  eyebrow?: string\n  title?: React.ReactNode\n  description?: React.ReactNode\n  plans?: Plan[]\n  currency?: string\n  /** Discount badge on the yearly option. */\n  yearlyBadge?: string\n  onSelect?: (plan: string, period: \"monthly\" | \"yearly\") => void\n  /** Price suffix, e.g. \"/ seat / mo\" or \"/ mo\". */\n  unit?: string\n  /** Used in \"Billed $X per seat yearly\". Empty string drops it. */\n  per?: string\n  className?: string\n}\n\nconst DEFAULT_PLANS: Plan[] = [\n  { name: \"Starter\", blurb: \"For a founder watching their own numbers.\", monthly: 0, yearly: 0, cta: \"Start free\", features: [\"1 workspace\", \"3 data sources\", \"Weekly digest\", { label: \"Ask Lumen\", included: false }, { label: \"Alerts\", included: false }] },\n  { name: \"Team\", blurb: \"For finance and ops teams up to 25.\", monthly: 49, yearly: 39, cta: \"Start 14-day trial\", featured: true, features: [\"Unlimited workspaces\", \"All 40+ data sources\", \"Ask Lumen, unlimited\", \"Real-time alerts\", \"Slack and email delivery\"] },\n  { name: \"Scale\", blurb: \"For companies with a security review.\", monthly: 129, yearly: 99, cta: \"Talk to sales\", features: [\"Everything in Team\", \"SSO, SCIM, audit log\", \"EU or US residency\", \"Dedicated analyst\", \"99.9% uptime SLA\"] },\n]\n\nfunction PricingPlans({\n  eyebrow = \"Pricing\",\n  title = \"Priced like a tool, not a hire.\",\n  description = \"Per seat, per month. Change plans any time; we prorate to the day.\",\n  plans = DEFAULT_PLANS,\n  currency = \"USD\",\n  yearlyBadge = \"-20%\",\n  onSelect,\n  unit = \"/ seat / mo\",\n  per = \"per seat\",\n  className,\n}: PricingPlansProps) {\n  const [period, setPeriod] = React.useState<\"monthly\" | \"yearly\">(\"yearly\")\n  const fmt = { style: \"currency\", currency, maximumFractionDigits: 0 } as Intl.NumberFormatOptions\n  return (\n    <section data-slot=\"pricing-plans\" className={cn(\"mx-auto max-w-7xl px-4 py-24 sm:px-6 sm:py-32 lg:px-8\", className)}>\n      <div className=\"mx-auto max-w-2xl text-center\">\n        {eyebrow ? <p className=\"font-mono text-[11px] tracking-[0.08em] text-accent-fg uppercase\">{eyebrow}</p> : null}\n        <h2 className=\"mt-3 text-4xl leading-[1.05] font-medium tracking-[-0.04em] text-balance text-fg sm:text-5xl\">{title}</h2>\n        {description ? <p className=\"mt-4 text-[1.0625rem] leading-[1.65] text-fg-muted\">{description}</p> : null}\n        <div className=\"mt-8 flex justify-center\">\n          <SegmentedControl\n            aria-label=\"Billing period\"\n            value={period}\n            onChange={(v) => setPeriod(v as \"monthly\" | \"yearly\")}\n            options={[\n              { value: \"monthly\", label: \"Monthly\" },\n              { value: \"yearly\", label: \"Yearly\", badge: yearlyBadge },\n            ]}\n          />\n        </div>\n      </div>\n      <div className=\"mx-auto mt-12 grid max-w-6xl gap-4 lg:grid-cols-3 lg:items-stretch\">\n        {plans.map((p) => {\n          const price = period === \"yearly\" ? p.yearly : p.monthly\n          return (\n            <article\n              key={p.name}\n              data-featured={p.featured || undefined}\n              className={cn(\n                \"relative flex flex-col rounded-3xl p-7\",\n                p.featured\n                  ? \"bg-ink text-on-ink shadow-ink lg:-my-4 lg:py-11\"\n                  : \"border border-border bg-surface text-fg shadow-raised\"\n              )}\n            >\n              {p.featured ? (\n                <>\n                  <span aria-hidden className=\"absolute inset-x-10 top-0 h-px bg-[linear-gradient(90deg,transparent,var(--accent),transparent)]\" />\n                  <span className=\"absolute top-6 right-6 rounded-full bg-accent px-2.5 py-1 text-[11px] font-medium text-on-accent\">Most teams pick this</span>\n                </>\n              ) : null}\n              <h3 className=\"text-[15px] font-medium\">{p.name}</h3>\n              <p className={cn(\"mt-1 text-[13.5px] leading-[1.5]\", p.featured ? \"opacity-70\" : \"text-fg-muted\")}>{p.blurb}</p>\n              <p className=\"mt-6 flex items-baseline gap-1.5\">\n                <span className=\"text-[52px] leading-[56px] font-medium tracking-[-0.045em]\">\n                  {price === 0 ? \"Free\" : <NumberRoll value={price} format={fmt} />}\n                </span>\n                {price > 0 ? <span className={cn(\"text-[13px]\", p.featured ? \"opacity-60\" : \"text-fg-subtle\")}>{unit}</span> : null}\n              </p>\n              <p className={cn(\"mt-1 h-5 text-[12.5px]\", p.featured ? \"opacity-60\" : \"text-fg-subtle\")}>\n                {price > 0 && period === \"yearly\" ? (\n                  <>\n                    Billed <NumberRoll value={price * 12} format={fmt} /> {per} yearly\n                  </>\n                ) : price > 0 ? (\n                  \"Billed monthly, cancel any time\"\n                ) : (\n                  \"Free forever for one person\"\n                )}\n              </p>\n              <Button\n                size=\"lg\"\n                variant={p.featured ? \"accent\" : \"outline\"}\n                className=\"mt-7 w-full\"\n                onClick={() => onSelect?.(p.name, period)}\n              >\n                {p.cta}\n              </Button>\n              <ul className={cn(\"mt-7 space-y-3 border-t pt-7 text-[13.5px]\", p.featured ? \"border-on-ink/15\" : \"border-border\")}>\n                {p.features.map((f) => {\n                  const inc = typeof f === \"string\"\n                  const label = inc ? f : f.label\n                  return (\n                    <li key={label} className={cn(\"flex items-center gap-2.5\", !inc && (p.featured ? \"opacity-45\" : \"text-fg-subtle\"))}>\n                      <span\n                        className={cn(\n                          \"grid size-5 shrink-0 place-items-center rounded-full\",\n                          inc ? (p.featured ? \"bg-accent text-on-accent\" : \"bg-accent-soft text-accent-fg\") : \"bg-fg/5\"\n                        )}\n                      >\n                        {inc ? <CheckIcon className=\"size-3\" strokeWidth={3} /> : <MinusIcon className=\"size-3\" />}\n                      </span>\n                      {label}\n                      {!inc ? <span className=\"sr-only\">(not included)</span> : null}\n                    </li>\n                  )\n                })}\n              </ul>\n            </article>\n          )\n        })}\n      </div>\n    </section>\n  )\n}\n\nexport { PricingPlans }\nexport type { PricingPlansProps, Plan }\n"
    }
  ]
}
