{
  "$schema": "https://shadcn-vue.com/schema/registry-item.json",
  "name": "cart-drawer",
  "title": "Cart Drawer",
  "type": "registry:block",
  "files": [
    {
      "path": "packages/registry-vue/blocks/cart-drawer/CartDrawer.vue",
      "content": "<script lang=\"ts\">\nexport interface CartItem {\n  id: string\n  name: string\n  variant: string\n  price: number\n  originalPrice?: number\n  qty: number\n  inStock?: boolean\n  image: string\n}\n\nexport const DEFAULT_ITEMS: CartItem[] = [\n  {\n    id: 'item-1',\n    name: 'Aero Minimalist Runner',\n    variant: 'Size: 10.5 · Color: Matte Black',\n    price: 120,\n    originalPrice: 140,\n    qty: 1,\n    inStock: true,\n    image: 'https://images.unsplash.com/photo-1542291026-7eec264c27ff?w=300&auto=format&fit=crop&q=80',\n  },\n  {\n    id: 'item-2',\n    name: 'Technical Shell Parka',\n    variant: 'Size: L · Color: Mineral Gray',\n    price: 95,\n    originalPrice: 110,\n    qty: 1,\n    inStock: true,\n    image: 'https://images.unsplash.com/photo-1591047139829-d91aecb6caea?w=300&auto=format&fit=crop&q=80',\n  },\n  {\n    id: 'item-3',\n    name: 'Minimalist Leather Cardholder',\n    variant: 'Size: Slim · Color: Saddle Brown',\n    price: 70,\n    originalPrice: 85,\n    qty: 1,\n    inStock: true,\n    image: 'https://images.unsplash.com/photo-1627123424574-724758594e93?w=300&auto=format&fit=crop&q=80',\n  },\n]\n</script>\n\n<script setup lang=\"ts\">\nimport { computed, ref, watch } from 'vue'\nimport type { HTMLAttributes } from 'vue'\nimport { Leaf, Lock, Minus, Plus, RotateCcw, ShieldCheck, ShoppingBag, Tag, Trash2, Truck, X } from 'lucide-vue-next'\nimport { cn } from '@/lib/utils'\nimport { Badge } from '@/components/ui/badge'\nimport { Button } from '@/components/ui/button'\nimport { Input } from '@/components/ui/input'\nimport { Progress } from '@/components/ui/progress'\nimport { Separator } from '@/components/ui/separator'\n\ninterface Props {\n  variant?: 'drawer' | 'page'\n  items?: CartItem[]\n  currency?: string\n  freeShippingThreshold?: number\n  taxRate?: number\n  initialPromoCode?: string\n  class?: HTMLAttributes['class']\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n  variant: 'drawer',\n  items: () => DEFAULT_ITEMS,\n  currency: 'USD',\n  freeShippingThreshold: 300,\n  taxRate: 0.08,\n  initialPromoCode: '',\n})\n\nconst emit = defineEmits<{\n  checkout: [items: CartItem[], total: number]\n  continueShopping: []\n  close: []\n  updateQuantity: [id: string, qty: number]\n  removeItem: [id: string]\n  applyPromo: [code: string]\n  removePromo: []\n}>()\n\nconst cartItems = ref<CartItem[]>(props.items.map((item) => ({ ...item })))\nconst promoCodeInput = ref('')\nconst appliedPromo = ref<string>(props.initialPromoCode)\nconst promoDiscount = ref<number>(props.initialPromoCode ? 20 : 0)\nconst promoError = ref('')\nconst promoSuccess = ref('')\n\nwatch(\n  () => props.items,\n  (newItems) => {\n    cartItems.value = newItems.map((item) => ({ ...item }))\n  },\n  { deep: true },\n)\n\nconst totalItemsCount = computed(() => cartItems.value.reduce((acc, item) => acc + item.qty, 0))\n\nconst subtotal = computed(() => cartItems.value.reduce((acc, item) => acc + item.price * item.qty, 0))\n\nconst isFreeShippingUnlocked = computed(\n  () => subtotal.value >= props.freeShippingThreshold && cartItems.value.length > 0,\n)\n\nconst amountAwayFromFreeShipping = computed(() => Math.max(0, props.freeShippingThreshold - subtotal.value))\n\nconst shippingProgress = computed(() => {\n  if (cartItems.value.length === 0) return 0\n  return Math.min(100, Math.round((subtotal.value / props.freeShippingThreshold) * 100))\n})\n\nconst shippingFee = computed(() => {\n  if (cartItems.value.length === 0) return 0\n  return isFreeShippingUnlocked.value ? 0 : 15\n})\n\nconst discountedSubtotal = computed(() => Math.max(0, subtotal.value - promoDiscount.value))\n\nconst estimatedTax = computed(() => {\n  if (cartItems.value.length === 0) return 0\n  return Number((discountedSubtotal.value * props.taxRate).toFixed(2))\n})\n\nconst total = computed(() => {\n  if (cartItems.value.length === 0) return 0\n  return Number((discountedSubtotal.value + shippingFee.value + estimatedTax.value).toFixed(2))\n})\n\nfunction formatCurrency(amount: number) {\n  try {\n    return new Intl.NumberFormat('en-US', {\n      style: 'currency',\n      currency: props.currency,\n      minimumFractionDigits: 2,\n    }).format(amount)\n  } catch {\n    return `$${amount.toFixed(2)}`\n  }\n}\n\nfunction updateQuantity(id: string, delta: number) {\n  const item = cartItems.value.find((i) => i.id === id)\n  if (!item) return\n  const newQty = item.qty + delta\n  if (newQty <= 0) {\n    removeItem(id)\n  } else {\n    item.qty = newQty\n    emit('updateQuantity', id, newQty)\n  }\n}\n\nfunction removeItem(id: string) {\n  cartItems.value = cartItems.value.filter((i) => i.id !== id)\n  emit('removeItem', id)\n}\n\nfunction handleApplyPromo() {\n  promoError.value = ''\n  promoSuccess.value = ''\n  const trimmed = promoCodeInput.value.trim().toUpperCase()\n  if (!trimmed) return\n\n  if (trimmed === 'SUMMER20' || trimmed === 'SAVE20') {\n    appliedPromo.value = trimmed\n    promoDiscount.value = 20\n    promoSuccess.value = '$20.00 coupon discount applied!'\n    promoCodeInput.value = ''\n    emit('applyPromo', trimmed)\n  } else if (trimmed === 'SAVE10') {\n    appliedPromo.value = trimmed\n    promoDiscount.value = 10\n    promoSuccess.value = '$10.00 coupon discount applied!'\n    promoCodeInput.value = ''\n    emit('applyPromo', trimmed)\n  } else {\n    appliedPromo.value = trimmed\n    promoDiscount.value = 15\n    promoSuccess.value = 'Promo code applied!'\n    promoCodeInput.value = ''\n    emit('applyPromo', trimmed)\n  }\n}\n\nfunction handleRemovePromo() {\n  appliedPromo.value = ''\n  promoDiscount.value = 0\n  promoSuccess.value = ''\n  promoError.value = ''\n  emit('removePromo')\n}\n\nfunction handleCheckout() {\n  emit('checkout', cartItems.value, total.value)\n}\n\nfunction handleContinueShopping() {\n  emit('continueShopping')\n}\n\nfunction handleClose() {\n  emit('close')\n}\n\nfunction resetCart() {\n  cartItems.value = DEFAULT_ITEMS.map((item) => ({ ...item }))\n}\n</script>\n\n<template>\n  <div data-slot=\"cart-drawer\" :class=\"cn('w-full', props.class)\">\n    <!-- DRAWER VARIANT -->\n    <div\n      v-if=\"variant === 'drawer'\"\n      class=\"bg-card text-card-foreground border-border/80 mx-auto flex h-full max-h-[820px] min-h-[640px] w-full max-w-md flex-col overflow-hidden rounded-2xl border shadow-xs\"\n    >\n      <!-- Drawer Header -->\n      <div class=\"border-border/60 flex shrink-0 items-center justify-between border-b px-5 py-4\">\n        <div class=\"flex items-center gap-2\">\n          <h2 class=\"text-base font-semibold tracking-tight\">Shopping Cart</h2>\n          <Badge v-if=\"totalItemsCount > 0\" variant=\"secondary\" class=\"tabular-nums\">\n            {{ totalItemsCount }}\n          </Badge>\n        </div>\n        <Button variant=\"ghost\" size=\"icon-sm\" aria-label=\"Close cart drawer\" @click=\"handleClose\">\n          <X class=\"size-4\" />\n        </Button>\n      </div>\n\n      <!-- Free Shipping Meter -->\n      <div v-if=\"cartItems.length > 0\" class=\"bg-muted/30 border-border/40 shrink-0 border-b px-5 py-3.5\">\n        <div class=\"flex items-center justify-between gap-2 text-xs\">\n          <span v-if=\"isFreeShippingUnlocked\" class=\"text-primary flex items-center gap-1.5 font-medium\">\n            <Truck class=\"size-3.5\" />\n            You've unlocked Free Express Shipping!\n          </span>\n          <span v-else class=\"text-muted-foreground\">\n            🎉 You're\n            <strong class=\"text-foreground font-semibold tabular-nums\">{{\n              formatCurrency(amountAwayFromFreeShipping)\n            }}</strong>\n            away from Free Shipping!\n          </span>\n          <span class=\"text-muted-foreground font-medium tabular-nums\">{{ shippingProgress }}%</span>\n        </div>\n        <Progress :model-value=\"shippingProgress\" class=\"mt-2 h-1.5\" />\n      </div>\n\n      <!-- Drawer Body: Line Items or Empty State -->\n      <div class=\"flex-1 overflow-y-auto p-5\">\n        <div v-if=\"cartItems.length === 0\" class=\"flex h-full flex-col items-center justify-center py-12 text-center\">\n          <div class=\"bg-muted text-muted-foreground mb-4 flex size-14 items-center justify-center rounded-full\">\n            <ShoppingBag class=\"size-7 stroke-[1.5]\" />\n          </div>\n          <h3 class=\"text-base font-semibold\">Your cart is empty</h3>\n          <p class=\"text-muted-foreground mt-1 max-w-xs text-xs leading-relaxed\">\n            Looks like you haven't added any products to your cart yet. Explore our latest items!\n          </p>\n          <Button class=\"mt-5 gap-2\" size=\"sm\" @click=\"resetCart\">\n            <ShoppingBag class=\"size-3.5\" />\n            Explore Products\n          </Button>\n        </div>\n\n        <div v-else class=\"space-y-4\">\n          <ul class=\"divide-border/60 divide-y\" role=\"list\">\n            <li v-for=\"item in cartItems\" :key=\"item.id\" class=\"flex gap-3.5 py-4 first:pt-0 last:pb-0\">\n              <div\n                class=\"border-border/60 bg-muted/40 relative size-20 shrink-0 overflow-hidden rounded-lg border shadow-xs\"\n              >\n                <img :src=\"item.image\" :alt=\"item.name\" class=\"size-full object-cover\" />\n              </div>\n\n              <div class=\"flex min-w-0 flex-1 flex-col justify-between\">\n                <div>\n                  <div class=\"flex items-start justify-between gap-2\">\n                    <h3 class=\"text-foreground truncate text-sm leading-snug font-medium\">\n                      {{ item.name }}\n                    </h3>\n                    <Button\n                      variant=\"ghost\"\n                      size=\"icon-sm\"\n                      class=\"text-muted-foreground hover:text-destructive -mt-1 -mr-1.5 size-7 shrink-0\"\n                      :aria-label=\"`Remove ${item.name} from cart`\"\n                      @click=\"removeItem(item.id)\"\n                    >\n                      <Trash2 class=\"size-3.5\" />\n                    </Button>\n                  </div>\n                  <p class=\"text-muted-foreground mt-0.5 text-xs\">\n                    {{ item.variant }}\n                  </p>\n                  <div class=\"mt-1 flex items-center gap-1.5\">\n                    <span class=\"bg-success size-1.5 rounded-full\"></span>\n                    <span class=\"text-success text-xs font-medium\">In stock</span>\n                  </div>\n                </div>\n\n                <div class=\"mt-2.5 flex items-center justify-between\">\n                  <div class=\"border-border/80 bg-background flex items-center rounded-md border shadow-xs\">\n                    <Button\n                      variant=\"ghost\"\n                      size=\"icon-sm\"\n                      class=\"size-7 rounded-none rounded-l-md\"\n                      :aria-label=\"`Decrease quantity for ${item.name}`\"\n                      @click=\"updateQuantity(item.id, -1)\"\n                    >\n                      <Minus class=\"size-3\" />\n                    </Button>\n                    <span class=\"w-7 text-center text-xs font-medium tabular-nums\">{{ item.qty }}</span>\n                    <Button\n                      variant=\"ghost\"\n                      size=\"icon-sm\"\n                      class=\"size-7 rounded-none rounded-r-md\"\n                      :aria-label=\"`Increase quantity for ${item.name}`\"\n                      @click=\"updateQuantity(item.id, 1)\"\n                    >\n                      <Plus class=\"size-3\" />\n                    </Button>\n                  </div>\n\n                  <div class=\"text-right\">\n                    <span\n                      v-if=\"item.originalPrice\"\n                      class=\"text-muted-foreground mr-1.5 text-xs tabular-nums line-through\"\n                    >\n                      {{ formatCurrency(item.originalPrice * item.qty) }}\n                    </span>\n                    <span class=\"text-foreground text-sm font-semibold tabular-nums\">\n                      {{ formatCurrency(item.price * item.qty) }}\n                    </span>\n                  </div>\n                </div>\n              </div>\n            </li>\n          </ul>\n\n          <Separator class=\"my-3\" />\n\n          <!-- Promo Code Section -->\n          <div class=\"space-y-2\">\n            <div\n              v-if=\"appliedPromo\"\n              class=\"bg-primary/5 border-primary/20 flex items-center justify-between rounded-lg border px-3 py-2 text-xs\"\n            >\n              <div class=\"flex items-center gap-2\">\n                <Tag class=\"text-primary size-3.5\" />\n                <span class=\"text-foreground font-medium\">{{ appliedPromo }}</span>\n                <span class=\"text-success text-success font-semibold tabular-nums\">\n                  -{{ formatCurrency(promoDiscount) }}\n                </span>\n              </div>\n              <Button\n                variant=\"ghost\"\n                size=\"icon-sm\"\n                class=\"text-muted-foreground hover:text-foreground size-6\"\n                aria-label=\"Remove promo code\"\n                @click=\"handleRemovePromo\"\n              >\n                <X class=\"size-3.5\" />\n              </Button>\n            </div>\n\n            <div v-else class=\"flex gap-2\">\n              <Input\n                v-model=\"promoCodeInput\"\n                placeholder=\"Promo code (e.g. SUMMER20)\"\n                size=\"small\"\n                class=\"text-xs\"\n                @keydown.enter.prevent=\"handleApplyPromo\"\n              />\n              <Button\n                variant=\"outline\"\n                size=\"sm\"\n                class=\"shrink-0 text-xs\"\n                :disabled=\"!promoCodeInput.trim()\"\n                @click=\"handleApplyPromo\"\n              >\n                Apply\n              </Button>\n            </div>\n            <p v-if=\"promoSuccess\" class=\"text-success text-xs font-medium\">\n              {{ promoSuccess }}\n            </p>\n            <p v-if=\"promoError\" class=\"text-destructive text-xs\">\n              {{ promoError }}\n            </p>\n          </div>\n        </div>\n      </div>\n\n      <!-- Drawer Footer: Summary & Actions -->\n      <div v-if=\"cartItems.length > 0\" class=\"border-border/60 bg-card shrink-0 space-y-3 border-t p-5\">\n        <div class=\"space-y-1.5 text-xs\">\n          <div class=\"flex justify-between\">\n            <span class=\"text-muted-foreground\">Subtotal</span>\n            <span class=\"text-foreground font-medium tabular-nums\">{{ formatCurrency(subtotal) }}</span>\n          </div>\n\n          <div v-if=\"promoDiscount > 0\" class=\"text-success flex justify-between\">\n            <span>Coupon ({{ appliedPromo }})</span>\n            <span class=\"font-medium tabular-nums\">-{{ formatCurrency(promoDiscount) }}</span>\n          </div>\n\n          <div class=\"flex justify-between\">\n            <span class=\"text-muted-foreground\">Estimated Shipping</span>\n            <span v-if=\"shippingFee === 0\" class=\"text-success font-medium\">Free</span>\n            <span v-else class=\"text-foreground font-medium tabular-nums\">{{ formatCurrency(shippingFee) }}</span>\n          </div>\n\n          <div class=\"flex justify-between\">\n            <span class=\"text-muted-foreground\">Estimated Tax</span>\n            <span class=\"text-foreground font-medium tabular-nums\">{{ formatCurrency(estimatedTax) }}</span>\n          </div>\n\n          <Separator class=\"my-2\" />\n\n          <div class=\"flex flex-wrap items-baseline justify-between gap-x-2 gap-y-0.5 text-sm\">\n            <span class=\"font-semibold\">Total</span>\n            <span class=\"font-semibold tabular-nums\">{{ formatCurrency(total) }}</span>\n          </div>\n        </div>\n\n        <div class=\"space-y-2 pt-1\">\n          <Button class=\"w-full justify-center gap-2 font-medium shadow-xs\" size=\"default\" @click=\"handleCheckout\">\n            <Lock class=\"size-3.5\" />\n            Proceed to Checkout\n          </Button>\n\n          <Button\n            variant=\"ghost\"\n            class=\"text-muted-foreground hover:text-foreground w-full text-xs\"\n            size=\"sm\"\n            @click=\"handleContinueShopping\"\n          >\n            Continue Shopping\n          </Button>\n        </div>\n\n        <!-- Guarantee badges -->\n        <div\n          class=\"border-border/40 text-muted-foreground grid grid-cols-1 gap-2 border-t pt-3 text-center text-xs sm:grid-cols-3\"\n        >\n          <div class=\"flex flex-col items-center gap-1\">\n            <RotateCcw class=\"size-3.5\" />\n            <span>30-day returns</span>\n          </div>\n          <div class=\"flex flex-col items-center gap-1\">\n            <ShieldCheck class=\"size-3.5\" />\n            <span>256-bit secure</span>\n          </div>\n          <div class=\"flex flex-col items-center gap-1\">\n            <Leaf class=\"size-3.5\" />\n            <span>Carbon neutral</span>\n          </div>\n        </div>\n      </div>\n    </div>\n\n    <!-- FULL PAGE VARIANT -->\n    <div v-else class=\"mx-auto w-full max-w-6xl space-y-6\">\n      <!-- Page Header -->\n      <div class=\"flex flex-col gap-1 sm:flex-row sm:items-center sm:justify-between\">\n        <div>\n          <h1 class=\"text-2xl font-bold tracking-tight\">Shopping Cart</h1>\n          <p class=\"text-muted-foreground mt-0.5 text-xs\">\n            Review your selected items and calculate shipping before checkout.\n          </p>\n        </div>\n        <Badge v-if=\"totalItemsCount > 0\" variant=\"outline\" class=\"w-fit text-xs tabular-nums\">\n          {{ totalItemsCount }} items in cart\n        </Badge>\n      </div>\n\n      <!-- Free Shipping Banner -->\n      <div v-if=\"cartItems.length > 0\" class=\"bg-card border-border/80 rounded-xl border p-4 shadow-xs\">\n        <div class=\"flex flex-col gap-2 sm:flex-row sm:items-center sm:justify-between\">\n          <div class=\"flex items-center gap-2 text-xs\">\n            <Truck v-if=\"isFreeShippingUnlocked\" class=\"text-primary size-4\" />\n            <span v-if=\"isFreeShippingUnlocked\" class=\"text-primary font-semibold\">\n              You've unlocked Free Express Shipping on this order!\n            </span>\n            <span v-else class=\"text-muted-foreground\">\n              🎉 You're\n              <strong class=\"text-foreground font-semibold tabular-nums\">{{\n                formatCurrency(amountAwayFromFreeShipping)\n              }}</strong>\n              away from Free Shipping!\n            </span>\n          </div>\n          <span class=\"text-muted-foreground text-xs font-medium tabular-nums\">{{ shippingProgress }}% completed</span>\n        </div>\n        <Progress :model-value=\"shippingProgress\" class=\"mt-2.5 h-2\" />\n      </div>\n\n      <!-- Empty State for Page -->\n      <div\n        v-if=\"cartItems.length === 0\"\n        class=\"bg-card border-border/80 flex flex-col items-center justify-center rounded-2xl border py-16 text-center shadow-xs\"\n      >\n        <div class=\"bg-muted text-muted-foreground mb-4 flex size-16 items-center justify-center rounded-full\">\n          <ShoppingBag class=\"size-8 stroke-[1.5]\" />\n        </div>\n        <h2 class=\"text-lg font-semibold\">Your cart is currently empty</h2>\n        <p class=\"text-muted-foreground mt-1 max-w-sm text-sm\">\n          Before you proceed to checkout you must add some products to your shopping cart.\n        </p>\n        <Button class=\"mt-6 gap-2\" size=\"default\" @click=\"resetCart\">\n          <ShoppingBag class=\"size-4\" />\n          Explore Products\n        </Button>\n      </div>\n\n      <!-- Page Grid: Items (Left) & Order Summary (Right) -->\n      <div v-else class=\"grid grid-cols-1 items-start gap-8 lg:grid-cols-12\">\n        <!-- Left: Line Items list -->\n        <div class=\"space-y-4 lg:col-span-8\">\n          <div class=\"bg-card border-border/80 divide-border/60 divide-y rounded-2xl border shadow-xs\">\n            <div\n              v-for=\"item in cartItems\"\n              :key=\"item.id\"\n              class=\"flex flex-col gap-4 p-5 sm:flex-row sm:items-center sm:justify-between\"\n            >\n              <div class=\"flex items-center gap-4\">\n                <div\n                  class=\"border-border/60 bg-muted/40 relative size-20 shrink-0 overflow-hidden rounded-lg border shadow-xs\"\n                >\n                  <img :src=\"item.image\" :alt=\"item.name\" class=\"size-full object-cover\" />\n                </div>\n                <div>\n                  <h3 class=\"text-foreground text-sm font-semibold\">\n                    {{ item.name }}\n                  </h3>\n                  <p class=\"text-muted-foreground mt-0.5 text-xs\">\n                    {{ item.variant }}\n                  </p>\n                  <div class=\"mt-1.5 flex items-center gap-2\">\n                    <span class=\"bg-success size-1.5 rounded-full\"></span>\n                    <span class=\"text-success text-xs font-medium\">In stock</span>\n                    <span class=\"text-muted-foreground text-xs font-normal tabular-nums\">\n                      · {{ formatCurrency(item.price) }} each\n                    </span>\n                  </div>\n                </div>\n              </div>\n\n              <div class=\"flex items-center justify-between gap-6 sm:justify-end\">\n                <div class=\"border-border/80 bg-background flex items-center rounded-md border shadow-xs\">\n                  <Button\n                    variant=\"ghost\"\n                    size=\"icon-sm\"\n                    class=\"size-8 rounded-none rounded-l-md\"\n                    :aria-label=\"`Decrease quantity for ${item.name}`\"\n                    @click=\"updateQuantity(item.id, -1)\"\n                  >\n                    <Minus class=\"size-3.5\" />\n                  </Button>\n                  <span class=\"w-8 text-center text-xs font-medium tabular-nums\">{{ item.qty }}</span>\n                  <Button\n                    variant=\"ghost\"\n                    size=\"icon-sm\"\n                    class=\"size-8 rounded-none rounded-r-md\"\n                    :aria-label=\"`Increase quantity for ${item.name}`\"\n                    @click=\"updateQuantity(item.id, 1)\"\n                  >\n                    <Plus class=\"size-3.5\" />\n                  </Button>\n                </div>\n\n                <div class=\"w-24 text-right\">\n                  <span v-if=\"item.originalPrice\" class=\"text-muted-foreground block text-xs tabular-nums line-through\">\n                    {{ formatCurrency(item.originalPrice * item.qty) }}\n                  </span>\n                  <span class=\"text-foreground text-base font-semibold tabular-nums\">\n                    {{ formatCurrency(item.price * item.qty) }}\n                  </span>\n                </div>\n\n                <Button\n                  variant=\"ghost\"\n                  size=\"icon-sm\"\n                  class=\"text-muted-foreground hover:text-destructive size-8\"\n                  :aria-label=\"`Remove ${item.name} from cart`\"\n                  @click=\"removeItem(item.id)\"\n                >\n                  <Trash2 class=\"size-4\" />\n                </Button>\n              </div>\n            </div>\n          </div>\n\n          <!-- Bottom bar: Guarantees -->\n          <div class=\"bg-card border-border/80 grid grid-cols-1 gap-4 rounded-xl border p-4 shadow-xs sm:grid-cols-3\">\n            <div class=\"flex items-center gap-3 text-xs\">\n              <div class=\"bg-muted text-foreground flex size-8 shrink-0 items-center justify-center rounded-md\">\n                <RotateCcw class=\"size-4\" />\n              </div>\n              <div>\n                <p class=\"font-medium\">Free 30-Day Returns</p>\n                <p class=\"text-muted-foreground\">Hassle-free return policy</p>\n              </div>\n            </div>\n            <div class=\"flex items-center gap-3 text-xs\">\n              <div class=\"bg-muted text-foreground flex size-8 shrink-0 items-center justify-center rounded-md\">\n                <ShieldCheck class=\"size-4\" />\n              </div>\n              <div>\n                <p class=\"font-medium\">256-Bit SSL Security</p>\n                <p class=\"text-muted-foreground\">Bank-grade data encryption</p>\n              </div>\n            </div>\n            <div class=\"flex items-center gap-3 text-xs\">\n              <div class=\"bg-muted text-foreground flex size-8 shrink-0 items-center justify-center rounded-md\">\n                <Leaf class=\"size-4\" />\n              </div>\n              <div>\n                <p class=\"font-medium\">Carbon Neutral</p>\n                <p class=\"text-muted-foreground\">Offset delivery emissions</p>\n              </div>\n            </div>\n          </div>\n        </div>\n\n        <!-- Right: Sticky Order Summary Card -->\n        <div class=\"space-y-4 lg:sticky lg:top-6 lg:col-span-4\">\n          <div class=\"bg-card border-border/80 space-y-4 rounded-2xl border p-5 shadow-xs\">\n            <h2 class=\"text-base font-semibold\">Order Summary</h2>\n\n            <!-- Promo Input -->\n            <div class=\"space-y-2\">\n              <label class=\"text-muted-foreground text-xs font-medium\">Have a coupon code?</label>\n              <div\n                v-if=\"appliedPromo\"\n                class=\"bg-primary/5 border-primary/20 flex items-center justify-between rounded-lg border px-3 py-2 text-xs\"\n              >\n                <div class=\"flex items-center gap-2\">\n                  <Tag class=\"text-primary size-3.5\" />\n                  <span class=\"text-foreground font-medium\">{{ appliedPromo }}</span>\n                  <span class=\"text-success text-success font-semibold tabular-nums\">\n                    -{{ formatCurrency(promoDiscount) }}\n                  </span>\n                </div>\n                <Button\n                  variant=\"ghost\"\n                  size=\"icon-sm\"\n                  class=\"text-muted-foreground hover:text-foreground size-6\"\n                  aria-label=\"Remove coupon\"\n                  @click=\"handleRemovePromo\"\n                >\n                  <X class=\"size-3.5\" />\n                </Button>\n              </div>\n              <div v-else class=\"flex gap-2\">\n                <Input\n                  v-model=\"promoCodeInput\"\n                  placeholder=\"Enter code (SUMMER20)\"\n                  size=\"small\"\n                  class=\"text-xs\"\n                  @keydown.enter.prevent=\"handleApplyPromo\"\n                />\n                <Button\n                  variant=\"outline\"\n                  size=\"sm\"\n                  class=\"shrink-0 text-xs\"\n                  :disabled=\"!promoCodeInput.trim()\"\n                  @click=\"handleApplyPromo\"\n                >\n                  Apply\n                </Button>\n              </div>\n            </div>\n\n            <Separator />\n\n            <!-- Cost Breakdown -->\n            <div class=\"space-y-2 text-xs\">\n              <div class=\"flex justify-between\">\n                <span class=\"text-muted-foreground\">Subtotal</span>\n                <span class=\"text-foreground font-medium tabular-nums\">{{ formatCurrency(subtotal) }}</span>\n              </div>\n\n              <div v-if=\"promoDiscount > 0\" class=\"text-success flex justify-between\">\n                <span>Coupon ({{ appliedPromo }})</span>\n                <span class=\"font-medium tabular-nums\">-{{ formatCurrency(promoDiscount) }}</span>\n              </div>\n\n              <div class=\"flex justify-between\">\n                <span class=\"text-muted-foreground\">Estimated Shipping</span>\n                <span v-if=\"shippingFee === 0\" class=\"text-success font-medium\">Free</span>\n                <span v-else class=\"text-foreground font-medium tabular-nums\">{{ formatCurrency(shippingFee) }}</span>\n              </div>\n\n              <div class=\"flex justify-between\">\n                <span class=\"text-muted-foreground\">Estimated Tax (8%)</span>\n                <span class=\"text-foreground font-medium tabular-nums\">{{ formatCurrency(estimatedTax) }}</span>\n              </div>\n\n              <Separator class=\"my-2\" />\n\n              <div class=\"flex flex-wrap items-baseline justify-between gap-x-2 gap-y-0.5 text-base font-semibold\">\n                <span>Total</span>\n                <span class=\"tabular-nums\">{{ formatCurrency(total) }}</span>\n              </div>\n            </div>\n\n            <Button class=\"w-full justify-center gap-2 font-medium shadow-xs\" size=\"lg\" @click=\"handleCheckout\">\n              <Lock class=\"size-4\" />\n              Proceed to Checkout\n            </Button>\n\n            <Button\n              variant=\"ghost\"\n              class=\"text-muted-foreground hover:text-foreground w-full text-xs\"\n              size=\"sm\"\n              @click=\"handleContinueShopping\"\n            >\n              Continue Shopping\n            </Button>\n          </div>\n        </div>\n      </div>\n    </div>\n  </div>\n</template>\n",
      "type": "registry:block",
      "target": "~/app/components/blocks/CartDrawer.vue"
    }
  ],
  "dependencies": [
    "lucide-vue-next"
  ],
  "devDependencies": [],
  "registryDependencies": [
    "https://uipkge.dev/r/vue/badge.json",
    "https://uipkge.dev/r/vue/button.json",
    "https://uipkge.dev/r/vue/input.json",
    "https://uipkge.dev/r/vue/progress.json",
    "https://uipkge.dev/r/vue/separator.json"
  ],
  "description": "Shopping cart drawer & full cart page view featuring free shipping progress meter, interactive line items with quantity steppers and variant tags, promo code application, order summary with tax & shipping calculation, trust badges, and empty state.",
  "categories": [
    "commerce",
    "ecommerce"
  ]
}