{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "cart-protection",
  "type": "registry:component",
  "title": "Shipping protection",
  "description": "Opt-in shipping protection switch, off by default, with a computed fee and plain-language terms.",
  "author": "StoreKit <hello@storekit.dev>",
  "categories": [
    "cart",
    "any"
  ],
  "dependencies": [
    "motion",
    "lucide-react"
  ],
  "registryDependencies": [
    "https://storekit-eight.vercel.app/r/cn.json",
    "https://storekit-eight.vercel.app/r/sk-analytics.json"
  ],
  "files": [
    {
      "path": "cart/cart-protection.tsx",
      "content": "\"use client\"\n\nimport * as React from \"react\"\nimport { AnimatePresence, motion, useReducedMotion } from \"motion/react\"\nimport { ChevronDown, ShieldCheck } from \"lucide-react\"\nimport { cn, money } from \"@/components/storekit/lib/cn\"\nimport { useSkBlock } from \"@/components/storekit/lib/sk-analytics\"\n\n/* Shipping protection as a true opt-in. Off by default, price on the label,\n   and the terms written in plain language right under it, with the full\n   policy one tap away. */\n\nexport function CartProtection({\n  subtotal = 14800,\n  rate = 2,\n  minFee = 195,\n  defaultOn = false,\n  terms = [\n    \"Covers loss, theft and damage while in transit.\",\n    \"Report a problem within 30 days of the delivery date.\",\n    \"We reship the order or refund it, your choice.\",\n  ],\n  policyHref = \"#\",\n  onChange,\n  className,\n}: {\n  /** Cart subtotal in cents. */\n  subtotal?: number\n  /** Percent of subtotal. */\n  rate?: number\n  /** Minimum fee in cents. */\n  minFee?: number\n  defaultOn?: boolean\n  terms?: string[]\n  policyHref?: string\n  onChange?: (on: boolean, fee: number) => void\n  className?: string\n}) {\n  const reduce = useReducedMotion()\n  const sk = useSkBlock(\"cart\", \"cart-protection\")\n  const [on, setOn] = React.useState(defaultOn)\n  const [details, setDetails] = React.useState(false)\n  const fee = Math.max(minFee, Math.round((subtotal * rate) / 100))\n  const regionId = React.useId()\n\n  return (\n    <div ref={sk.ref as React.Ref<HTMLDivElement>} {...sk.attrs} className={cn(\"w-full rounded-sk-card border border-sk-line bg-sk-card\", className)}>\n      <button\n        type=\"button\"\n        role=\"switch\"\n        aria-checked={on}\n        onClick={() => {\n          setOn(!on)\n          onChange?.(!on, fee)\n          sk.emit(on ? \"interact\" : \"convert\", on ? \"protection_off\" : \"protection_on\", fee)\n        }}\n        className=\"flex min-h-[64px] w-full items-center gap-3 rounded-sk-card px-4 py-3 text-left transition-colors duration-200 hover:bg-sk-ink/[0.03] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-sk-accent active:scale-[0.99]\"\n      >\n        <span className={cn(\"grid h-9 w-9 shrink-0 place-items-center rounded-sk-chip transition-colors duration-200\", on ? \"bg-sk-savings/15 text-sk-savings\" : \"bg-sk-ink/[0.06] text-sk-muted\")}>\n          <ShieldCheck size={17} />\n        </span>\n        <span className=\"min-w-0 flex-1\">\n          <span className=\"flex flex-wrap items-baseline gap-x-2 text-sm font-medium text-sk-ink\">\n            Shipping protection\n            <span className=\"tabular-nums text-sk-muted\">{money(fee)}</span>\n          </span>\n          <span className=\"block text-[13px] text-sk-muted\">{on ? \"Added. Your order is covered in transit.\" : \"Optional. Not added unless you turn it on.\"}</span>\n        </span>\n        <span aria-hidden className={cn(\"relative flex h-6 w-10 shrink-0 items-center rounded-sk-chip p-0.5 transition-colors duration-200\", on ? \"bg-sk-accent\" : \"bg-sk-ink/20\")}>\n          <motion.span\n            initial={false}\n            animate={{ x: on ? 16 : 0 }}\n            transition={reduce ? { duration: 0 } : { type: \"spring\", stiffness: 600, damping: 34 }}\n            className={cn(\"h-5 w-5 rounded-sk-chip shadow-[0_1px_2px_rgb(0_0_0/0.25)]\", on ? \"bg-sk-accent-ink\" : \"bg-sk-paper\")}\n          />\n        </span>\n      </button>\n      <div className=\"border-t border-sk-line px-4\">\n        <button\n          type=\"button\"\n          aria-expanded={details}\n          aria-controls={regionId}\n          onClick={() => setDetails((d) => !d)}\n          className=\"flex h-11 w-full items-center justify-between rounded-sk-btn text-[13px] text-sk-muted transition-colors duration-200 hover:text-sk-ink focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-sk-accent\"\n        >\n          What it covers\n          <ChevronDown size={14} className={cn(\"transition-transform duration-200\", details && \"rotate-180\")} />\n        </button>\n        <AnimatePresence initial={false}>\n          {details ? (\n            <motion.div\n              id={regionId}\n              initial={{ height: 0, opacity: 0 }}\n              animate={{ height: \"auto\", opacity: 1 }}\n              exit={{ height: 0, opacity: 0 }}\n              transition={{ duration: reduce ? 0 : 0.28, ease: [0.16, 1, 0.3, 1] }}\n              className=\"overflow-hidden\"\n            >\n              <ul className=\"grid gap-1.5 pb-3 text-[13px] leading-[1.5] text-sk-ink\">\n                {terms.map((t) => (\n                  <li key={t} className=\"flex gap-2\">\n                    <span aria-hidden className=\"mt-[0.6em] h-1 w-1 shrink-0 rounded-sk-chip bg-sk-muted\" />\n                    {t}\n                  </li>\n                ))}\n              </ul>\n              <a href={policyHref} className=\"mb-3 inline-block rounded-sk-btn text-[13px] font-medium text-sk-ink underline underline-offset-4 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-sk-accent\">\n                Read the full policy\n              </a>\n            </motion.div>\n          ) : null}\n        </AnimatePresence>\n      </div>\n    </div>\n  )\n}\n",
      "type": "registry:component",
      "target": "components/storekit/cart/cart-protection.tsx"
    }
  ],
  "meta": {
    "section": "cart",
    "variant": "switch",
    "niche": [
      "any"
    ],
    "commerce": [
      "addon",
      "protection"
    ],
    "previewHeight": 360
  }
}