{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "components-pricings-pricing-1",
  "title": "Pricing 1",
  "description": "Modern pricing grid with animated sliding numbers, billing toggle, and featured plan corner decorations.",
  "dependencies": [
    "motion",
    "react-use-measure"
  ],
  "registryDependencies": [
    "button"
  ],
  "files": [
    {
      "path": "registry/components/pricings/pricing-1/index.tsx",
      "content": "'use client';\n\nimport { useEffect, useId, useState } from 'react';\nimport {\n  motion,\n  MotionValue,\n  motionValue,\n  useSpring,\n  useTransform,\n} from 'motion/react';\nimport useMeasure from 'react-use-measure';\nimport {\n  ArrowUpRight01Icon,\n  CheckmarkBadge01Icon,\n  CustomerService01Icon,\n} from '@hugeicons/core-free-icons';\nimport { HugeiconsIcon } from '@hugeicons/react';\nimport { Button } from '@/components/ui/button';\nimport { cn } from '@/lib/utils';\n\nconst SPRING = {\n  type: 'spring' as const,\n  stiffness: 280,\n  damping: 18,\n  mass: 0.3,\n};\n\nfunction Digit({ value, place }: { value: number; place: number }) {\n  const rounded = Math.floor(value / place) % 10;\n  const initial = motionValue(rounded);\n  const anim = useSpring(initial, SPRING);\n\n  useEffect(() => {\n    anim.set(rounded);\n  }, [anim, rounded]);\n\n  return (\n    <div className=\"relative inline-block w-[1ch] overflow-x-visible overflow-y-clip leading-none tabular-nums\">\n      <div className=\"invisible\">0</div>\n      {Array.from({ length: 10 }, (_, i) => (\n        <Slot key={i} mv={anim} number={i} />\n      ))}\n    </div>\n  );\n}\n\nfunction Slot({ mv, number }: { mv: MotionValue<number>; number: number }) {\n  const id = useId();\n  const [ref, bounds] = useMeasure();\n\n  const y = useTransform(mv, (latest) => {\n    if (!bounds.height) return 0;\n    const offset = (10 + number - (latest % 10)) % 10;\n    return offset > 5 ? (offset - 10) * bounds.height : offset * bounds.height;\n  });\n\n  if (!bounds.height) {\n    return (\n      <span ref={ref} className=\"invisible absolute\">\n        {number}\n      </span>\n    );\n  }\n\n  return (\n    <motion.span\n      style={{ y }}\n      layoutId={`${id}-${number}`}\n      className=\"absolute inset-0 flex items-center justify-center\"\n      transition={SPRING}\n      ref={ref}\n    >\n      {number}\n    </motion.span>\n  );\n}\n\nfunction SlidingNumber({ value }: { value: number }) {\n  const digits = Math.abs(value).toString().split('');\n  const intVal = parseInt(digits.join(''), 10);\n  const places = digits.map((_, i) => Math.pow(10, digits.length - i - 1));\n\n  return (\n    <div className=\"flex items-center\">\n      {digits.map((_, i) => (\n        <Digit key={`p${places[i]}`} value={intVal} place={places[i]} />\n      ))}\n    </div>\n  );\n}\n\nfunction CornerPlus({ className }: { className?: string }) {\n  return (\n    <svg\n      aria-hidden=\"true\"\n      className={cn(\n        'pointer-events-none absolute z-10 size-3 shrink-0 stroke-muted-foreground stroke-1',\n        className,\n      )}\n      fill=\"none\"\n      stroke=\"currentColor\"\n      strokeLinecap=\"round\"\n      strokeLinejoin=\"round\"\n      viewBox=\"0 0 24 24\"\n      xmlns=\"http://www.w3.org/2000/svg\"\n    >\n      <path d=\"M5 12h14\" />\n      <path d=\"M12 5v14\" />\n    </svg>\n  );\n}\n\nfunction BillingToggle({\n  yearly,\n  onToggle,\n}: {\n  yearly: boolean;\n  onToggle: () => void;\n}) {\n  return (\n    <button\n      type=\"button\"\n      role=\"switch\"\n      aria-checked={yearly}\n      onClick={onToggle}\n      className={cn(\n        'relative inline-flex h-5.5 w-9 shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent transition-colors duration-200',\n        'focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background focus-visible:outline-none',\n        yearly ? 'bg-foreground' : 'bg-input',\n      )}\n    >\n      <motion.span\n        animate={{ x: yearly ? '1.125rem' : '0.125rem' }}\n        transition={{ type: 'spring', stiffness: 500, damping: 32 }}\n        className=\"block size-3.5 rounded-full bg-background shadow-sm\"\n      />\n    </button>\n  );\n}\n\nexport type Plan = {\n  id: string;\n  name: string;\n  desc: string;\n  credits: string;\n  monthly: number;\n  yearly: number;\n  cta: string;\n  featured: boolean;\n  features: string[];\n};\n\nconst DEFAULT_PLANS: Plan[] = [\n  {\n    id: 'free',\n    name: 'Starter',\n    desc: 'Everything you need to explore. No card required, no strings attached.',\n    credits: '1,000',\n    monthly: 0,\n    yearly: 0,\n    cta: 'Get started',\n    featured: false,\n    features: [\n      '1,000 credits / month',\n      '1 concurrent request',\n      'Community support',\n    ],\n  },\n  {\n    id: 'pro',\n    name: 'Pro',\n    desc: 'Built for makers shipping real products. Flexible, fast, and reliable.',\n    credits: '10,000',\n    monthly: 29,\n    yearly: 23,\n    cta: 'Start free trial',\n    featured: true,\n    features: [\n      '10,000 credits / month',\n      '10 concurrent requests',\n      'Email support',\n      '$7 per extra 1k credits',\n    ],\n  },\n  {\n    id: 'enterprise',\n    name: 'Enterprise',\n    desc: 'For teams that need reliability at scale. Custom limits, dedicated support.',\n    credits: '500,000',\n    monthly: 149,\n    yearly: 119,\n    cta: 'Contact sales',\n    featured: false,\n    features: [\n      '500,000 credits / month',\n      'Unlimited concurrent requests',\n      'Dedicated support',\n      'Custom rate limits',\n      'SLA guarantee',\n    ],\n  },\n];\n\nexport function Pricing1({ plans = DEFAULT_PLANS }: { plans?: Plan[] }) {\n  const [yearly, setYearly] = useState(false);\n\n  return (\n    <div className=\"w-full space-y-1.5\">\n      {/* Header */}\n      <div className=\"flex flex-col gap-3 p-2 sm:flex-row sm:items-center sm:justify-between\">\n        <h2 className=\"text-2xl font-semibold tracking-tight\">\n          Simple, transparent pricing\n        </h2>\n        <div className=\"flex items-center gap-2.5\">\n          <BillingToggle\n            yearly={yearly}\n            onToggle={() => setYearly((y) => !y)}\n          />\n          <span\n            className={cn(\n              'text-sm font-medium transition-colors duration-200',\n              yearly ? 'text-foreground' : 'text-muted-foreground',\n            )}\n          >\n            Billed yearly (18% OFF)\n          </span>\n        </div>\n      </div>\n\n      <div className=\"grid grid-cols-1 divide-y divide-border rounded-2xl border border-border lg:grid-cols-3 lg:divide-x lg:divide-y-0\">\n        {plans.map((plan, i) => {\n          const price = yearly ? plan.yearly : plan.monthly;\n          const isFirst = i === 0;\n          const isLast = i === plans.length - 1;\n\n          return (\n            <div\n              key={plan.id}\n              className={cn(\n                'relative flex flex-col',\n                isFirst &&\n                  'overflow-hidden rounded-t-2xl lg:rounded-t-none lg:rounded-l-2xl',\n                isLast &&\n                  'overflow-hidden rounded-b-2xl lg:rounded-r-2xl lg:rounded-b-none',\n                !plan.featured && 'bg-muted/30',\n              )}\n            >\n              {plan.featured && (\n                <>\n                  <CornerPlus className=\"top-0 left-0 hidden -translate-x-[calc(50%+0.5px)] -translate-y-[calc(50%+0.5px)] lg:block\" />\n                  <CornerPlus className=\"top-0 right-0 hidden translate-x-[calc(50%+0.5px)] -translate-y-[calc(50%+0.5px)] lg:block\" />\n                </>\n              )}\n\n              <div className=\"relative flex flex-col gap-4 border-b border-border p-6\">\n                {plan.featured && (\n                  <>\n                    <CornerPlus className=\"bottom-0 left-0 hidden -translate-x-[calc(50%+0.5px)] translate-y-[calc(50%+0.5px)] lg:block\" />\n                    <CornerPlus className=\"right-0 bottom-0 hidden translate-x-[calc(50%+0.5px)] translate-y-[calc(50%+0.5px)] lg:block\" />\n                  </>\n                )}\n                <div className=\"flex items-center justify-between gap-2\">\n                  <span className=\"text-xl font-semibold\">{plan.name}</span>\n                  {plan.featured && (\n                    <span className=\"rounded-full bg-foreground px-2.5 py-0.5 text-xs font-semibold text-background\">\n                      Most popular\n                    </span>\n                  )}\n                </div>\n\n                <p className=\"text-sm leading-relaxed text-muted-foreground\">\n                  {plan.desc}\n                </p>\n\n                <div className=\"mt-1 flex items-end gap-1\">\n                  <div className=\"flex items-end text-3xl leading-none font-bold\">\n                    <span>$</span>\n                    <SlidingNumber value={price} />\n                  </div>\n                  <span className=\"mb-0.5 text-sm text-muted-foreground\">\n                    /month\n                  </span>\n                </div>\n\n                <Button\n                  variant={plan.featured ? 'default' : 'outline'}\n                  className={cn(\n                    'w-full rounded-lg',\n                    plan.featured &&\n                      'bg-foreground text-background hover:bg-foreground/90',\n                  )}\n                >\n                  {plan.cta}\n                </Button>\n              </div>\n\n              <div className=\"flex flex-col gap-2.5 p-6\">\n                {plan.features.map((f) => (\n                  <div\n                    key={f}\n                    className=\"flex items-center gap-2 text-sm text-muted-foreground\"\n                  >\n                    <HugeiconsIcon\n                      icon={CheckmarkBadge01Icon}\n                      strokeWidth={2}\n                      className=\"size-4 shrink-0\"\n                    />\n                    <span>{f}</span>\n                  </div>\n                ))}\n              </div>\n            </div>\n          );\n        })}\n      </div>\n\n      <div className=\"flex flex-col gap-4 rounded-2xl border border-border p-4 sm:flex-row sm:items-center sm:justify-between\">\n        <div className=\"flex items-center gap-3\">\n          <div className=\"flex size-9 shrink-0 items-center justify-center rounded-lg border border-border bg-muted/50\">\n            <HugeiconsIcon\n              icon={CustomerService01Icon}\n              strokeWidth={2}\n              className=\"size-4 shrink-0\"\n            />\n          </div>\n          <div>\n            <p className=\"text-sm font-semibold\">Need help deciding?</p>\n            <p className=\"text-sm text-muted-foreground\">\n              Contact our support team for personalized recommendations and\n              guidance.\n            </p>\n          </div>\n        </div>\n        <Button\n          variant=\"link\"\n          className=\"ml-0 flex items-center gap-1 text-sm font-medium text-muted-foreground transition-colors hover:text-foreground sm:ml-4\"\n        >\n          Learn more\n          <HugeiconsIcon\n            icon={ArrowUpRight01Icon}\n            strokeWidth={2}\n            className=\"size-4 shrink-0\"\n          />\n        </Button>\n      </div>\n    </div>\n  );\n}\n\nexport default Pricing1;\n",
      "type": "registry:ui",
      "target": "components/odysseyui/pricing-1.tsx"
    }
  ],
  "type": "registry:ui"
}