{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "components-pricings-pricing-4",
  "title": "Pricing 4",
  "description": "Pastel pricing cards with animated billing toggle, tag badges, and info rows.",
  "dependencies": [
    "motion",
    "react-use-measure"
  ],
  "registryDependencies": [
    "button",
    "badge"
  ],
  "files": [
    {
      "path": "registry/components/pricings/pricing-4/index.tsx",
      "content": "'use client';\n\nimport { useEffect, useId, useState } from 'react';\nimport Link from 'next/link';\nimport {\n  motion,\n  MotionValue,\n  motionValue,\n  useSpring,\n  useTransform,\n} from 'motion/react';\nimport useMeasure from 'react-use-measure';\nimport React from 'react';\nimport { Badge } from '@/components/ui/badge';\nimport { Button } from '@/components/ui/button';\nimport { cn } from '@/lib/utils';\n\nexport type Plan4 = {\n  id: string;\n  name: string;\n  description: string;\n  tags: string[];\n  targetedFor: string;\n  credits: string;\n  monthly: number | 'Custom';\n  yearly: number | 'Custom';\n  ctaLabel: string;\n  ctaHref: string;\n  pastel: 'rose' | 'amber' | 'sky' | 'violet' | 'emerald' | 'lime';\n};\n\nconst DEFAULT_PLANS: Plan4[] = [\n  {\n    id: 'starter',\n    name: 'Starter Plan',\n    description:\n      'Kickstart your workflow with essential tools tailored for lean teams.',\n    tags: ['Resume AI', 'Analytics'],\n    targetedFor: 'Startups, Small Teams',\n    credits: '100 / month',\n    monthly: 0,\n    yearly: 0,\n    ctaLabel: 'Get Started',\n    ctaHref: '#',\n    pastel: 'rose',\n  },\n  {\n    id: 'pro',\n    name: 'Growth Plan',\n    description:\n      'Scale automation with deeper analytics, ATS workflows, and compliance reports.',\n    tags: ['AI Interviews', 'ATS', 'Compliance'],\n    targetedFor: 'Growing Businesses',\n    credits: '200 / month',\n    monthly: 119,\n    yearly: 97,\n    ctaLabel: 'Get Started',\n    ctaHref: '#',\n    pastel: 'amber',\n  },\n  {\n    id: 'enterprise',\n    name: 'Enterprise Plan',\n    description:\n      'White-label controls, custom SLAs, and dedicated pods for global organizations.',\n    tags: ['White-label', 'Custom SLA'],\n    targetedFor: 'Large Enterprises',\n    credits: 'Unlimited',\n    monthly: 'Custom',\n    yearly: 'Custom',\n    ctaLabel: 'Contact Sales',\n    ctaHref: '#',\n    pastel: 'sky',\n  },\n];\n\n// Light mode: true pastels. Dark mode: vibrant mid-opacity tints on dark surfaces.\nconst pastelBg: Record<Plan4['pastel'], string> = {\n  rose: 'bg-rose-200/80 dark:bg-rose-400/[0.22]',\n  amber: 'bg-amber-200/80 dark:bg-amber-400/[0.22]',\n  sky: 'bg-sky-200/80 dark:bg-sky-400/[0.22]',\n  violet: 'bg-violet-200/80 dark:bg-violet-400/[0.22]',\n  emerald: 'bg-emerald-200/80 dark:bg-emerald-400/[0.22]',\n  lime: 'bg-lime-200/80 dark:bg-lime-400/[0.22]',\n};\n\nconst pastelBadgeVariant: Record<\n  Plan4['pastel'],\n  React.ComponentProps<typeof Badge>['variant']\n> = {\n  rose: 'rose',\n  amber: 'amber',\n  sky: 'sky',\n  violet: 'violet',\n  emerald: 'emerald',\n  lime: 'lime',\n};\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 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\nfunction InfoRow({ label, value }: { label: string; value: string }) {\n  return (\n    <div className=\"flex items-center justify-between gap-2 border-b border-dashed border-foreground/30 py-3 last:border-0\">\n      <span className=\"text-sm font-medium\">{label}</span>\n      <span className=\"text-sm text-foreground\">{value}</span>\n    </div>\n  );\n}\n\nfunction PricingCard({ plan, yearly }: { plan: Plan4; yearly: boolean }) {\n  const raw = yearly ? plan.yearly : plan.monthly;\n\n  return (\n    <div className={cn('flex flex-col rounded-3xl p-6', pastelBg[plan.pastel])}>\n      {/* Tags */}\n      <div className=\"flex flex-wrap gap-1.5\">\n        {plan.tags.map((tag) => (\n          <Badge\n            key={tag}\n            variant={pastelBadgeVariant[plan.pastel]}\n            className=\"rounded-full text-xs font-medium\"\n          >\n            {tag}\n          </Badge>\n        ))}\n      </div>\n\n      {/* Spacer */}\n      <div className=\"min-h-24 flex-1\" />\n\n      {/* Plan info */}\n      <div className=\"space-y-1\">\n        <h3 className=\"text-2xl font-bold tracking-tight\">{plan.name}</h3>\n        <p className=\"text-sm leading-relaxed text-muted-foreground\">\n          {plan.description}\n        </p>\n      </div>\n\n      {/* Rows */}\n      <div className=\"mt-6\">\n        <InfoRow label=\"Perfect for\" value={plan.targetedFor} />\n        <InfoRow label=\"Credits\" value={plan.credits} />\n        {/* Animated price row */}\n        <div className=\"flex items-center justify-between gap-2 py-3\">\n          <span className=\"text-sm font-semibold\">Price</span>\n          <span className=\"text-sm font-semibold text-foreground\">\n            {raw === 'Custom' ? (\n              'Custom'\n            ) : raw === 0 ? (\n              'Free'\n            ) : (\n              <span className=\"flex items-center gap-px\">\n                <span>$</span>\n                <SlidingNumber value={raw as number} />\n                <span>/mo</span>\n              </span>\n            )}\n          </span>\n        </div>\n      </div>\n\n      {/* CTA */}\n      <div className=\"mt-6\">\n        <Button\n          asChild\n          className=\"w-full rounded-xl bg-foreground text-background hover:bg-foreground/85\"\n        >\n          <Link href={plan.ctaHref}>{plan.ctaLabel}</Link>\n        </Button>\n      </div>\n    </div>\n  );\n}\n\nexport default function Pricing4({\n  plans = DEFAULT_PLANS,\n  label = 'Pricing Plans',\n  yearlyLabel = 'Billed yearly (18% OFF)',\n  defaultYearly = false,\n}: {\n  plans?: Plan4[];\n  label?: string;\n  yearlyLabel?: string;\n  defaultYearly?: boolean;\n}) {\n  const [yearly, setYearly] = useState(defaultYearly);\n\n  return (\n    <div className=\"w-full space-y-5\">\n      <div className=\"flex items-center justify-between gap-4\">\n        <h2 className=\"text-4xl font-bold tracking-tight\">{label}</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            {yearlyLabel}\n          </span>\n        </div>\n      </div>\n\n      <div className=\"grid gap-4 md:grid-cols-3\">\n        {plans.map((plan) => (\n          <PricingCard key={plan.id} plan={plan} yearly={yearly} />\n        ))}\n      </div>\n    </div>\n  );\n}\n",
      "type": "registry:ui",
      "target": "components/odysseyui/pricing-4.tsx"
    }
  ],
  "type": "registry:ui"
}