{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "changeable-pricing-section",
  "type": "registry:component",
  "title": "Changeable Pricing Section",
  "description": "A premium interactive pricing selector with animated billing toggle, expandable plan details, and smooth spring-driven transitions for modern SaaS checkout flows.",
  "dependencies": [
    "framer-motion",
    "lucide-react"
  ],
  "files": [
    {
      "path": "components/watermelon/changeable-pricing-section.tsx",
      "type": "registry:component",
      "content": "import { useState } from \"react\";\nimport { motion, AnimatePresence } from \"framer-motion\";\nimport { Check, Info } from \"lucide-react\";\n\nexport type PlanId = string;\n\nexport interface Feature {\n  text: string;\n  hasInfo?: boolean;\n}\n\nexport interface Plan {\n  id: PlanId;\n  name: string;\n  description: string;\n  priceMonthly: string;\n  priceYearly: string;\n  badge?: string;\n  featuresLabel?: string;\n  features: Feature[];\n}\n\nexport interface ChangeablePricingSectionProps {\n  /** The main title of the section */\n  title?: string;\n  /** Array of pricing plans to display */\n  plans: Plan[];\n  /** Optional ID of the default selected plan */\n  defaultPlanId?: PlanId;\n  /** Default billing cycle */\n  defaultBillingCycle?: \"monthly\" | \"yearly\";\n  /** Custom label for monthly toggle */\n  monthlyLabel?: string;\n  /** Custom label for yearly toggle */\n  yearlyLabel?: string;\n  /** Footer text below plans */\n  footerText?: string;\n  /** CTA button text */\n  buttonText?: string;\n  /** Callback fired when continue button is clicked */\n  onContinue?: (planId: PlanId, billingCycle: \"monthly\" | \"yearly\") => void;\n}\n\nexport default function ChangeablePricingSection({\n  title = \"Select a plan\",\n  plans,\n  defaultPlanId,\n  defaultBillingCycle = \"monthly\",\n  monthlyLabel = \"Monthly\",\n  yearlyLabel = \"Yearly\",\n  footerText = \"Cancel anytime. No long-term contract.\",\n  buttonText = \"Continue\",\n  onContinue,\n}: ChangeablePricingSectionProps) {\n  const [selectedPlan, setSelectedPlan] = useState<PlanId>(\n    defaultPlanId || (plans.length > 0 ? plans[0].id : \"\"),\n  );\n  const [billingCycle, setBillingCycle] = useState<\"monthly\" | \"yearly\">(\n    defaultBillingCycle,\n  );\n\n  return (\n      <div className=\"w-full max-w-[460px] bg-neutral-100 dark:bg-neutral-950 rounded-[24px] p-1.5 shadow-sm ring-1 ring-neutral-200/50 dark:ring-neutral-800/50\">\n        {/* Header */}\n        <div className=\"flex items-center justify-between px-3 py-4\">\n          <h2 className=\"text-[17px] font-medium text-neutral-800 dark:text-neutral-100 tracking-tighter\">\n            {title}\n          </h2>\n          <div className=\"flex items-center bg-neutral-200 dark:bg-neutral-950 p-1 rounded-full relative z-0 ring-1 ring-transparent dark:ring-neutral-600/50\">\n            <motion.div\n              className=\"absolute top-1 bottom-1 w-[calc(50%-4px)] bg-white dark:bg-orange-500/15 rounded-full shadow-sm dark:shadow-none -z-10\"\n              animate={{\n                x: billingCycle === \"monthly\" ? 0 : \"100%\",\n              }}\n              transition={{ type: \"spring\", bounce: 0.4, duration: 0.7 }}\n              style={{ left: 4 }}\n            />\n            <button\n              onClick={() => setBillingCycle(\"monthly\")}\n              className={`jet w-[72px] py-1.5 rounded-full text-[10px] font-bold tracking-widest uppercase transition-colors z-10 ${billingCycle === \"monthly\" ? \"text-neutral-800 dark:text-orange-500\" : \"text-neutral-400 dark:text-neutral-500\"}`}\n            >\n              {monthlyLabel}\n            </button>\n            <button\n              onClick={() => setBillingCycle(\"yearly\")}\n              className={`jet w-[72px] py-1.5 rounded-full text-[10px] font-bold tracking-widest uppercase transition-colors z-10 ${billingCycle === \"yearly\" ? \"text-neutral-800 dark:text-orange-500\" : \"text-neutral-400 dark:text-neutral-500\"}`}\n            >\n              {yearlyLabel}\n            </button>\n          </div>\n        </div>\n\n        {/* Plans */}\n        <div className=\"flex flex-col gap-1\">\n          {plans.map((plan) => {\n            const isSelected = selectedPlan === plan.id;\n\n            return (\n              <motion.div\n                layout\n                key={plan.id}\n                onClick={() => setSelectedPlan(plan.id)}\n                transition={{ type: \"spring\", bounce: 0.45, duration: 0.7 }}\n                className={`relative overflow-hidden cursor-pointer rounded-[18px] transition-colors duration-300 bg-white dark:bg-neutral-800/50 ${\n                  isSelected\n                    ? \"ring-[1px] ring-orange-500 dark:ring-orange-500 shadow-[0_4px_16px_rgba(249,115,22,0.06)] dark:shadow-none\"\n                    : \"ring-1 ring-neutral-200/80 dark:ring-neutral-800 shadow-sm dark:shadow-none hover:ring-neutral-300 dark:hover:ring-neutral-700\"\n                }`}\n              >\n                <div className=\"px-4 py-3.5 sm:px-5 sm:py-4\">\n                  {/* Top row */}\n                  <div className=\"flex justify-between items-start gap-3\">\n                    <div className=\"flex flex-1 gap-3\">\n                      {/* Radio button */}\n                      <div className=\"mt-0.5 shrink-0\">\n                        <div\n                          className={`w-[18px] h-[18px] rounded-full flex items-center justify-center border transition-colors ${\n                            isSelected\n                              ? \"border-orange-500 bg-orange-500\"\n                              : \"border-neutral-300 dark:border-neutral-700 bg-white dark:bg-transparent\"\n                          }`}\n                        >\n                          {isSelected && (\n                            <Check\n                              size={11}\n                              strokeWidth={3.5}\n                              className=\"text-white\"\n                            />\n                          )}\n                        </div>\n                      </div>\n\n                      {/* Plan Info */}\n                      <div className=\"flex flex-1 flex-col\">\n                        <div className=\"flex flex-wrap items-center gap-2\">\n                          <span className=\"text-[16px] font-medium text-neutral-800 dark:text-neutral-100 leading-none\">\n                            {plan.name}\n                          </span>\n                          {plan.badge && (\n                            <span className=\"bg-green-100 dark:bg-green-500/10 text-green-600 text-[9px] font-bold px-2 py-0.5 rounded-full uppercase tracking-wider leading-none\">\n                              {plan.badge}\n                            </span>\n                          )}\n                        </div>\n                        <span className=\"text-[11px] text-neutral-500 dark:text-neutral-400 mt-1.5 leading-snug sm:leading-none\">\n                          {plan.description}\n                        </span>\n                      </div>\n                    </div>\n\n                    {/* Price Info */}\n                    <div className=\"flex flex-col items-end shrink-0\">\n                      <div className=\"flex items-center justify-end text-[15px] sm:text-[16px] font-medium text-neutral-800 dark:text-neutral-100 leading-none overflow-hidden h-[18px]\">\n                        <AnimatePresence mode=\"popLayout\" initial={false}>\n                          <motion.span\n                            key={billingCycle}\n                            initial={{\n                              y: billingCycle === \"yearly\" ? 20 : -20,\n                              opacity: 0,\n                              filter: \"blur(4px)\",\n                            }}\n                            animate={{ y: 0, opacity: 1, filter: \"blur(0px)\" }}\n                            exit={{\n                              y: billingCycle === \"monthly\" ? -20 : 20,\n                              opacity: 0,\n                              filter: \"blur(4px)\",\n                            }}\n                            transition={{\n                              type: \"spring\",\n                              bounce: 0,\n                              duration: 0.4,\n                            }}\n                            className=\"inline-block whitespace-nowrap\"\n                          >\n                            {billingCycle === \"monthly\"\n                              ? plan.priceMonthly\n                              : plan.priceYearly}\n                          </motion.span>\n                        </AnimatePresence>\n                      </div>\n                      <span className=\"jet text-[10px] text-neutral-400 font-bold tracking-widest uppercase mt-1.5 leading-none\">\n                        per user/month\n                      </span>\n                    </div>\n                  </div>\n\n                  {/* Expandable Features */}\n                  <AnimatePresence initial={false}>\n                    {isSelected && (\n                      <motion.div\n                        key=\"features\"\n                        initial={{ height: 0, opacity: 0 }}\n                        animate={{ height: \"auto\", opacity: 1 }}\n                        exit={{ height: 0, opacity: 0 }}\n                        transition={{\n                          opacity: { duration: 0.2 },\n                          height: { duration: 0.3, ease: \"easeOut\" },\n                        }}\n                        className=\"overflow-hidden\"\n                      >\n                        <div className=\"pt-3.5 mt-3.5 sm:pt-4 sm:mt-4 mb-1 border-t border-dashed border-neutral-200 dark:border-neutral-800\">\n                          {plan.featuresLabel && (\n                            <p className=\"jet text-[10px] font-bold text-neutral-400 tracking-widest uppercase mb-3\">\n                              {plan.featuresLabel}\n                            </p>\n                          )}\n                          <div className=\"flex flex-col gap-2.5\">\n                            {plan.features.map((feature, idx) => (\n                              <div\n                                key={idx}\n                                className=\"flex items-center gap-2.5\"\n                              >\n                                <Check\n                                  size={14}\n                                  strokeWidth={3}\n                                  className=\"text-green-500 shrink-0\"\n                                />\n                                <span className=\"text-[12px] text-neutral-600 dark:text-neutral-300 leading-tight\">\n                                  {feature.text}\n                                </span>\n                                {feature.hasInfo && (\n                                  <Info\n                                    size={13}\n                                    className=\"text-neutral-300 dark:text-neutral-600 ml-0.5\"\n                                  />\n                                )}\n                              </div>\n                            ))}\n                          </div>\n                        </div>\n                      </motion.div>\n                    )}\n                  </AnimatePresence>\n                </div>\n              </motion.div>\n            );\n          })}\n        </div>\n\n        {/* Footer info & CTA */}\n        <div className=\"flex flex-col gap-4 items-center sm:flex-row sm:justify-between mt-5 px-3 pb-2\">\n          <span className=\"jet text-[10px] text-neutral-400 uppercase tracking-[0.05em] leading-relaxed text-center sm:text-left\">\n            {footerText}\n          </span>\n          <button\n            onClick={() => onContinue?.(selectedPlan, billingCycle)}\n            className=\"w-full sm:w-auto bg-orange-500 text-white px-8 py-2.5 rounded-full text-[13px] font-medium hover:bg-orange-600 active:scale-95 transition-all outline-none focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:ring-orange-500\"\n          >\n            {buttonText}\n          </button>\n        </div>\n      </div>\n  );\n}\n"
    }
  ]
}
