{
  "$schema": "https://shadcn-vue.com/schema/registry-item.json",
  "name": "product-comparison-drawer",
  "title": "Product Comparison Drawer",
  "type": "registry:block",
  "files": [
    {
      "path": "packages/registry-vue/blocks/product-comparison-drawer/ProductComparisonDrawer.vue",
      "content": "<script lang=\"ts\">\nexport interface ComparisonSpec {\n  price: string\n  driverSize: string\n  batteryLife: string\n  ancType: string\n  waterResistance: string\n  weight: string\n  accessories: string\n  connectivity?: string\n  fastCharging?: string\n  microphone?: string\n  warranty?: string\n}\n\nexport interface ComparisonProduct {\n  id: string\n  name: string\n  tagline: string\n  badge: string\n  badgeVariant?: 'default' | 'secondary' | 'outline'\n  price: string\n  numericPrice: number\n  rating: number\n  reviewsCount: number\n  image: string\n  inStock: boolean\n  shipping: string\n  specs: ComparisonSpec\n}\n\nexport interface SpecField {\n  key: keyof ComparisonSpec\n  label: string\n  category: 'Key Specifications' | 'Audio & Connectivity' | 'Package & Warranty'\n  description?: string\n}\n\nexport const DEFAULT_COMPARISON_PRODUCTS: ComparisonProduct[] = [\n  {\n    id: 'prod-headphones',\n    name: 'Pro Wireless Headphones',\n    tagline: 'Flagship Over-Ear Studio Sound',\n    badge: 'Best Overall',\n    badgeVariant: 'default',\n    price: '$299.00',\n    numericPrice: 299,\n    rating: 4.9,\n    reviewsCount: 1240,\n    image: 'https://images.unsplash.com/photo-1505740420928-5e560c06d30e?w=400&auto=format&fit=crop&q=80',\n    inStock: true,\n    shipping: 'Free Next-Day Delivery',\n    specs: {\n      price: '$299.00',\n      driverSize: '40mm Graphene',\n      batteryLife: '40 Hours',\n      ancType: 'Adaptive ANC',\n      waterResistance: 'IPX4',\n      weight: '245g',\n      accessories: 'Hard Travel Case, 3.5mm Cable, USB-C Cable, Airplane Adapter',\n      connectivity: 'Bluetooth 5.3 + Multipoint',\n      fastCharging: '10 min charge = 3 hrs playback',\n      microphone: '6 Mics with Beamforming AI',\n      warranty: '2-Year Manufacturer Warranty',\n    },\n  },\n  {\n    id: 'prod-earbuds',\n    name: 'Aero Studio Earbuds',\n    tagline: 'Compact True Wireless In-Ear',\n    badge: 'Editor Choice',\n    badgeVariant: 'secondary',\n    price: '$199.00',\n    numericPrice: 199,\n    rating: 4.7,\n    reviewsCount: 890,\n    image: 'https://images.unsplash.com/photo-1590658268037-6bf12165a8df?w=400&auto=format&fit=crop&q=80',\n    inStock: true,\n    shipping: 'Free 2-Day Delivery',\n    specs: {\n      price: '$199.00',\n      driverSize: '11mm Dynamic',\n      batteryLife: '28 Hours',\n      ancType: 'Standard ANC',\n      waterResistance: 'IPX5',\n      weight: '54g',\n      accessories: 'Wireless Charging Case, 4 Pairs Silicone Tips (XS/S/M/L), USB-C Cable',\n      connectivity: 'Bluetooth 5.3 + Multipoint',\n      fastCharging: '10 min charge = 3 hrs playback',\n      microphone: '4 Mics with Wind Noise Guard',\n      warranty: '2-Year Manufacturer Warranty',\n    },\n  },\n  {\n    id: 'prod-sport',\n    name: 'Active ANC Sport',\n    tagline: 'Rugged Ergonomic Workout Earphones',\n    badge: 'Best Value',\n    badgeVariant: 'secondary',\n    price: '$149.00',\n    numericPrice: 149,\n    rating: 4.6,\n    reviewsCount: 620,\n    image: 'https://images.unsplash.com/photo-1572536147248-ac59a8abfa4b?w=400&auto=format&fit=crop&q=80',\n    inStock: true,\n    shipping: 'Free Standard Delivery',\n    specs: {\n      price: '$149.00',\n      driverSize: '10mm Hybrid',\n      batteryLife: '24 Hours',\n      ancType: 'Passive Noise Isolation',\n      waterResistance: 'IPX7 Waterproof',\n      weight: '62g',\n      accessories: 'Compact Case, Secure Wingtips, 3 Pairs Memory Foam Tips, USB-C Cable',\n      connectivity: 'Bluetooth 5.3',\n      fastCharging: '10 min charge = 3 hrs playback',\n      microphone: '2 Mics with Environmental Noise Cancellation',\n      warranty: '2-Year Manufacturer Warranty',\n    },\n  },\n]\n\nexport const SPEC_FIELDS: SpecField[] = [\n  {\n    key: 'price',\n    label: 'Price',\n    category: 'Key Specifications',\n    description: 'Manufacturer suggested retail price',\n  },\n  {\n    key: 'driverSize',\n    label: 'Driver Size',\n    category: 'Key Specifications',\n    description: 'Acoustic transducer diameter and diaphragm material',\n  },\n  {\n    key: 'batteryLife',\n    label: 'Battery Life',\n    category: 'Key Specifications',\n    description: 'Total listening duration with active cancellation enabled',\n  },\n  {\n    key: 'ancType',\n    label: 'ANC Type',\n    category: 'Key Specifications',\n    description: 'Acoustic cancellation and transparency algorithm type',\n  },\n  {\n    key: 'waterResistance',\n    label: 'Water Resistance',\n    category: 'Key Specifications',\n    description: 'Ingress protection rating against moisture and dust',\n  },\n  {\n    key: 'weight',\n    label: 'Weight',\n    category: 'Key Specifications',\n    description: 'Total physical mass including ear cushions/enclosures',\n  },\n  {\n    key: 'accessories',\n    label: 'In-Box Accessories',\n    category: 'Package & Warranty',\n    description: 'Included bundled cables, adapters, and travel protection',\n  },\n  {\n    key: 'connectivity',\n    label: 'Connectivity',\n    category: 'Audio & Connectivity',\n    description: 'Wireless Bluetooth specification and dual-device pairing',\n  },\n  {\n    key: 'fastCharging',\n    label: 'Fast Charging',\n    category: 'Audio & Connectivity',\n    description: 'Quick-boost charging time for emergency playback',\n  },\n  {\n    key: 'microphone',\n    label: 'Microphone Array',\n    category: 'Audio & Connectivity',\n    description: 'Voice pickup sensors and beamforming algorithms',\n  },\n  {\n    key: 'warranty',\n    label: 'Warranty',\n    category: 'Package & Warranty',\n    description: 'Manufacturer warranty coverage period',\n  },\n]\n</script>\n\n<script setup lang=\"ts\">\nimport { computed, ref, watch } from 'vue'\nimport type { HTMLAttributes } from 'vue'\nimport {\n  Check,\n  ChevronDown,\n  ChevronUp,\n  GitCompare,\n  Layers,\n  RotateCcw,\n  ShoppingCart,\n  SlidersHorizontal,\n  Star,\n  Trash2,\n  X,\n} from 'lucide-vue-next'\nimport { Badge } from '@/components/ui/badge'\nimport { Button } from '@/components/ui/button'\nimport { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'\nimport { Separator } from '@/components/ui/separator'\nimport { Switch } from '@/components/ui/switch'\nimport { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@/components/ui/table'\nimport { cn } from '@/lib/utils'\n\ninterface Props {\n  defaultOpen?: boolean\n  defaultHighlightDiffs?: boolean\n  products?: ComparisonProduct[]\n  mode?: 'dock' | 'expanded'\n  class?: HTMLAttributes['class']\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n  defaultOpen: false,\n  defaultHighlightDiffs: false,\n  mode: 'dock',\n})\n\nconst emit = defineEmits<{\n  'update:open': [open: boolean]\n  addToCart: [product: ComparisonProduct]\n  removeProduct: [productId: string]\n  clearAll: []\n  restoreProducts: []\n}>()\n\nconst isExpanded = ref(props.defaultOpen || props.mode === 'expanded')\nconst highlightDiffs = ref(props.defaultHighlightDiffs)\nconst selectedProducts = ref<ComparisonProduct[]>([...(props.products ?? DEFAULT_COMPARISON_PRODUCTS)])\nconst addedProductId = ref<string | null>(null)\n\nwatch(\n  () => props.products,\n  (newProducts) => {\n    selectedProducts.value = [...(newProducts ?? [])]\n  },\n  { deep: true },\n)\n\nwatch(isExpanded, (val) => {\n  emit('update:open', val)\n})\n\nfunction toggleExpanded() {\n  isExpanded.value = !isExpanded.value\n}\n\nfunction toggleProduct(product: ComparisonProduct) {\n  if (selectedProducts.value.some((p) => p.id === product.id)) {\n    handleRemoveProduct(product.id)\n  } else {\n    selectedProducts.value = [...selectedProducts.value, product]\n  }\n}\n\nfunction handleRemoveProduct(id: string) {\n  selectedProducts.value = selectedProducts.value.filter((p) => p.id !== id)\n  emit('removeProduct', id)\n}\n\nfunction handleClearAll() {\n  selectedProducts.value = []\n  emit('clearAll')\n}\n\nfunction handleRestoreProducts() {\n  selectedProducts.value = [...DEFAULT_COMPARISON_PRODUCTS]\n  emit('restoreProducts')\n}\n\nfunction handleAddToCart(product: ComparisonProduct) {\n  addedProductId.value = product.id\n  emit('addToCart', product)\n  setTimeout(() => {\n    if (addedProductId.value === product.id) {\n      addedProductId.value = null\n    }\n  }, 1800)\n}\n\n// Diff detection: checks if values differ across the currently selected products\nfunction isRowDiff(specKey: keyof ComparisonSpec): boolean {\n  if (selectedProducts.value.length <= 1) return false\n  const firstVal = selectedProducts.value[0]?.specs[specKey]\n  return selectedProducts.value.some((p) => p.specs[specKey] !== firstVal)\n}\n\nconst categories = computed(() => {\n  const cats: Array<{ name: string; fields: SpecField[] }> = []\n  for (const field of SPEC_FIELDS) {\n    let group = cats.find((c) => c.name === field.category)\n    if (!group) {\n      group = { name: field.category, fields: [] }\n      cats.push(group)\n    }\n    group.fields.push(field)\n  }\n  return cats\n})\n\nconst diffCount = computed(() => {\n  return SPEC_FIELDS.filter((f) => isRowDiff(f.key)).length\n})\n</script>\n\n<template>\n  <div\n    data-slot=\"product-comparison-drawer\"\n    :class=\"\n      cn('bg-background text-foreground relative flex w-full flex-col overflow-hidden rounded-xl border', props.class)\n    \"\n  >\n    <!-- Background Mock Catalog Page Preview (Context for Dock) -->\n    <div v-if=\"mode === 'dock'\" class=\"bg-muted/10 flex flex-col p-4 sm:p-6 lg:p-8\">\n      <div class=\"mb-6 flex flex-col justify-between gap-3 sm:flex-row sm:items-center\">\n        <div>\n          <div class=\"flex items-center gap-2\">\n            <span class=\"bg-primary/10 text-primary rounded px-2 py-0.5 text-xs font-semibold tracking-wider uppercase\">\n              Audio Lab\n            </span>\n            <span class=\"text-muted-foreground text-xs font-medium\">Over-Ear & In-Ear Systems</span>\n          </div>\n          <h2 class=\"text-xl font-bold tracking-tight sm:text-2xl\">High-Fidelity Audio Lineup</h2>\n          <p class=\"text-muted-foreground mt-1 text-xs sm:text-sm\">\n            Select flagship models below to compare acoustic architectures, battery runtime, and diffs side by side.\n          </p>\n        </div>\n\n        <div class=\"flex items-center gap-2\">\n          <Button\n            v-if=\"selectedProducts.length < DEFAULT_COMPARISON_PRODUCTS.length\"\n            variant=\"outline\"\n            size=\"sm\"\n            class=\"text-xs\"\n            @click=\"handleRestoreProducts\"\n          >\n            <RotateCcw class=\"mr-1.5 size-3.5\" />\n            Reset Selection\n          </Button>\n          <Button variant=\"default\" size=\"sm\" class=\"text-xs\" @click=\"toggleExpanded\">\n            <SlidersHorizontal class=\"mr-1.5 size-3.5\" />\n            {{ isExpanded ? 'Hide Comparison' : `Compare (${selectedProducts.length})` }}\n          </Button>\n        </div>\n      </div>\n\n      <!-- Mock Catalog Cards Grid -->\n      <div class=\"grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3\">\n        <div\n          v-for=\"product in DEFAULT_COMPARISON_PRODUCTS\"\n          :key=\"product.id\"\n          class=\"bg-card hover:border-border group relative flex flex-col justify-between rounded-lg border p-4 shadow-xs transition-colors\"\n          :class=\"{\n            'ring-primary/20 border-primary/40 ring-1': selectedProducts.some((p) => p.id === product.id),\n          }\"\n        >\n          <div>\n            <div class=\"bg-muted/40 relative aspect-4/3 w-full overflow-hidden rounded-md\">\n              <img\n                :src=\"product.image\"\n                :alt=\"product.name\"\n                class=\"size-full object-cover transition-transform duration-300 group-hover:scale-105\"\n                loading=\"lazy\"\n              />\n              <div class=\"absolute top-2.5 left-2.5\">\n                <Badge :variant=\"product.badgeVariant || 'default'\" class=\"text-xs font-medium shadow-xs\">\n                  {{ product.badge }}\n                </Badge>\n              </div>\n            </div>\n\n            <div class=\"mt-3.5 space-y-1\">\n              <div class=\"flex items-center justify-between\">\n                <div class=\"text-warning flex items-center gap-1 text-xs\">\n                  <Star class=\"size-3.5 fill-current\" />\n                  <span class=\"text-foreground font-semibold tabular-nums\">{{ product.rating }}</span>\n                  <span class=\"text-muted-foreground\">({{ product.reviewsCount.toLocaleString() }})</span>\n                </div>\n                <span class=\"text-sm font-bold tabular-nums\">{{ product.price }}</span>\n              </div>\n              <h3 class=\"text-foreground text-sm font-semibold tracking-tight\">{{ product.name }}</h3>\n              <p class=\"text-muted-foreground line-clamp-1 text-xs\">{{ product.tagline }}</p>\n            </div>\n          </div>\n\n          <div class=\"mt-4 flex items-center justify-between gap-2 border-t pt-3\">\n            <button\n              type=\"button\"\n              class=\"text-muted-foreground hover:text-foreground flex min-h-6 items-center gap-1.5 text-xs font-medium transition-colors\"\n              @click=\"toggleProduct(product)\"\n            >\n              <div\n                class=\"flex size-4 items-center justify-center rounded border transition-colors\"\n                :class=\"\n                  selectedProducts.some((p) => p.id === product.id)\n                    ? 'border-primary bg-primary text-primary-foreground'\n                    : 'border-muted-foreground/40 bg-background'\n                \"\n              >\n                <Check v-if=\"selectedProducts.some((p) => p.id === product.id)\" class=\"size-3 stroke-[3]\" />\n              </div>\n              <span>{{ selectedProducts.some((p) => p.id === product.id) ? 'Comparing' : 'Add to compare' }}</span>\n            </button>\n\n            <Button\n              size=\"sm\"\n              variant=\"outline\"\n              class=\"h-8 text-xs\"\n              :disabled=\"addedProductId === product.id\"\n              @click=\"handleAddToCart(product)\"\n            >\n              <Check v-if=\"addedProductId === product.id\" class=\"text-success mr-1 size-3.5\" />\n              <ShoppingCart v-else class=\"mr-1 size-3.5\" />\n              {{ addedProductId === product.id ? 'Added' : 'Add' }}\n            </Button>\n          </div>\n        </div>\n      </div>\n    </div>\n\n    <!-- Floating Sticky Comparison Bar (Dock at Bottom) -->\n    <div\n      v-if=\"mode === 'dock' && !isExpanded\"\n      class=\"bg-background/95 supports-[backdrop-filter]:bg-background/85 sticky bottom-0 z-30 w-full border-t p-3 backdrop-blur-md sm:p-4\"\n    >\n      <div class=\"mx-auto flex max-w-6xl flex-col items-stretch justify-between gap-3 sm:flex-row sm:items-center\">\n        <!-- Selected Products List -->\n        <div class=\"flex items-center gap-2 overflow-x-auto pb-1 sm:gap-3 sm:pb-0\">\n          <div class=\"flex shrink-0 items-center gap-1.5 pr-2\">\n            <div class=\"bg-primary/10 text-primary flex size-7 items-center justify-center rounded-md\">\n              <Layers class=\"size-4\" />\n            </div>\n            <div class=\"flex flex-col\">\n              <span class=\"text-xs leading-tight font-semibold\">Compare Dock</span>\n              <span class=\"text-muted-foreground text-xs tabular-nums\">\n                {{ selectedProducts.length }} / {{ DEFAULT_COMPARISON_PRODUCTS.length }} selected\n              </span>\n            </div>\n          </div>\n\n          <Separator orientation=\"vertical\" class=\"hidden h-8 sm:block\" />\n\n          <!-- Selected Thumbnails -->\n          <div v-if=\"selectedProducts.length > 0\" class=\"flex items-center gap-2\">\n            <div\n              v-for=\"product in selectedProducts\"\n              :key=\"product.id\"\n              class=\"bg-card group hover:border-primary/40 relative flex shrink-0 items-center gap-2 rounded-lg border p-1.5 pr-2.5 shadow-2xs transition-colors\"\n            >\n              <img :src=\"product.image\" :alt=\"product.name\" class=\"size-9 rounded-md object-cover\" />\n              <div class=\"flex flex-col\">\n                <span class=\"max-w-[110px] truncate text-xs font-medium sm:max-w-[130px]\">{{ product.name }}</span>\n                <span class=\"text-muted-foreground text-xs font-semibold tabular-nums\">{{ product.price }}</span>\n              </div>\n              <button\n                type=\"button\"\n                class=\"bg-background/80 hover:bg-destructive hover:text-destructive-foreground text-muted-foreground absolute -top-1.5 -right-1.5 flex size-4 items-center justify-center rounded-full border opacity-0 shadow-2xs transition-opacity group-hover:opacity-100 focus-visible:opacity-100\"\n                :aria-label=\"`Remove ${product.name} from comparison`\"\n                @click.stop=\"handleRemoveProduct(product.id)\"\n              >\n                <X class=\"size-2.5\" />\n              </button>\n            </div>\n          </div>\n\n          <div v-else class=\"text-muted-foreground flex items-center gap-2 py-1 text-xs\">\n            <span>No products in comparison dock.</span>\n            <button type=\"button\" class=\"text-primary font-medium hover:underline\" @click=\"handleRestoreProducts\">\n              Restore 3 Items\n            </button>\n          </div>\n        </div>\n\n        <!-- Action Buttons -->\n        <div class=\"flex shrink-0 items-center justify-end gap-2\">\n          <Button\n            v-if=\"selectedProducts.length > 0\"\n            variant=\"ghost\"\n            size=\"sm\"\n            class=\"text-muted-foreground hover:text-foreground h-8 text-xs font-medium\"\n            @click=\"handleClearAll\"\n          >\n            Clear All\n          </Button>\n\n          <Button\n            variant=\"default\"\n            size=\"sm\"\n            class=\"h-8 gap-1.5 text-xs font-medium shadow-xs\"\n            :disabled=\"selectedProducts.length === 0\"\n            @click=\"toggleExpanded\"\n          >\n            <span>Compare {{ selectedProducts.length }} Items</span>\n            <ChevronUp class=\"size-3.5\" />\n          </Button>\n        </div>\n      </div>\n    </div>\n\n    <!-- Expanded Full Specification Matrix Drawer / Container -->\n    <div\n      v-if=\"isExpanded || mode === 'expanded'\"\n      class=\"bg-background motion-safe:animate-in motion-safe:fade-in motion-safe:slide-in-from-bottom-2 relative flex w-full flex-col border-t shadow-lg motion-safe:duration-200\"\n    >\n      <!-- Matrix Header Controls Bar -->\n      <div\n        class=\"bg-card/90 supports-[backdrop-filter]:bg-card/75 sticky top-0 z-30 border-b px-4 py-3.5 backdrop-blur-md sm:px-6\"\n      >\n        <div class=\"flex flex-col justify-between gap-3 sm:flex-row sm:items-center\">\n          <div class=\"flex items-center gap-3\">\n            <div class=\"bg-primary/10 text-primary flex size-8 items-center justify-center rounded-lg\">\n              <SlidersHorizontal class=\"size-4\" />\n            </div>\n            <div>\n              <div class=\"flex items-center gap-2\">\n                <h3 class=\"text-base font-semibold tracking-tight\">Specification Matrix</h3>\n                <Badge variant=\"secondary\" class=\"text-xs font-semibold tabular-nums\">\n                  {{ selectedProducts.length }} Selected\n                </Badge>\n                <Badge\n                  v-if=\"highlightDiffs\"\n                  variant=\"outline\"\n                  class=\"border-primary/40 bg-primary/5 text-primary text-xs\"\n                >\n                  <GitCompare class=\"mr-1 size-3\" />\n                  Diffs Highlighted ({{ diffCount }})\n                </Badge>\n              </div>\n              <p class=\"text-muted-foreground text-xs\">\n                Side-by-side technical breakdown across drivers, battery, acoustics, and box contents.\n              </p>\n            </div>\n          </div>\n\n          <!-- Controls: Diff Switch & Close -->\n          <div class=\"flex items-center gap-4\">\n            <div class=\"flex items-center space-x-2\">\n              <Switch\n                id=\"vue-diff-toggle\"\n                size=\"sm\"\n                :model-value=\"highlightDiffs\"\n                @update:model-value=\"(val) => (highlightDiffs = val)\"\n              />\n              <label for=\"vue-diff-toggle\" class=\"cursor-pointer text-xs font-medium select-none\">\n                Highlight Differences Only\n              </label>\n            </div>\n\n            <Button\n              v-if=\"mode === 'dock'\"\n              variant=\"outline\"\n              size=\"sm\"\n              class=\"h-8 gap-1 text-xs\"\n              @click=\"toggleExpanded\"\n            >\n              <span>Collapse</span>\n              <ChevronDown class=\"size-3.5\" />\n            </Button>\n          </div>\n        </div>\n      </div>\n\n      <!-- Specification Matrix Content -->\n      <div v-if=\"selectedProducts.length === 0\" class=\"flex flex-col items-center justify-center p-12 text-center\">\n        <div class=\"bg-muted text-muted-foreground flex size-12 items-center justify-center rounded-full\">\n          <Trash2 class=\"size-6\" />\n        </div>\n        <h4 class=\"mt-3 text-sm font-semibold\">No Products Selected</h4>\n        <p class=\"text-muted-foreground mt-1 max-w-sm text-xs\">\n          You have cleared all items from comparison. Restore the baseline audio products to explore differences.\n        </p>\n        <Button variant=\"default\" size=\"sm\" class=\"mt-4 text-xs\" @click=\"handleRestoreProducts\">\n          <RotateCcw class=\"mr-1.5 size-3.5\" />\n          Restore 3 Items\n        </Button>\n      </div>\n\n      <div v-else class=\"w-full overflow-x-auto\">\n        <table class=\"w-full max-w-[760px] min-w-full border-separate border-spacing-0 text-left text-xs\">\n          <!-- Sticky Product Card Header Row -->\n          <thead>\n            <tr>\n              <th\n                scope=\"col\"\n                class=\"bg-background text-muted-foreground sticky top-0 left-0 z-20 w-[200px] min-w-[180px] border-b p-4 align-bottom font-medium\"\n              >\n                <div class=\"space-y-1\">\n                  <span class=\"text-foreground text-xs font-semibold tracking-wider uppercase\">Attributes</span>\n                  <p class=\"text-muted-foreground text-xs font-normal\">\n                    {{ selectedProducts.length }} products compared\n                  </p>\n                </div>\n              </th>\n\n              <!-- Product Columns -->\n              <th\n                v-for=\"product in selectedProducts\"\n                :key=\"product.id\"\n                scope=\"col\"\n                class=\"bg-background relative w-[240px] min-w-[220px] border-b p-4 align-top\"\n              >\n                <div class=\"flex flex-col gap-3\">\n                  <!-- Remove button -->\n                  <div class=\"flex items-center justify-between gap-2\">\n                    <Badge :variant=\"product.badgeVariant || 'default'\" class=\"text-xs font-medium\">\n                      {{ product.badge }}\n                    </Badge>\n                    <button\n                      type=\"button\"\n                      class=\"text-muted-foreground hover:bg-muted hover:text-foreground flex size-6 items-center justify-center rounded-md transition-colors\"\n                      :aria-label=\"`Remove ${product.name}`\"\n                      @click=\"handleRemoveProduct(product.id)\"\n                    >\n                      <X class=\"size-3.5\" />\n                    </button>\n                  </div>\n\n                  <!-- Product Hero Visual -->\n                  <div class=\"flex items-center gap-3\">\n                    <img\n                      :src=\"product.image\"\n                      :alt=\"product.name\"\n                      class=\"size-16 rounded-md border object-cover shadow-2xs\"\n                    />\n                    <div class=\"flex flex-col\">\n                      <span class=\"text-foreground text-xs leading-tight font-semibold\">{{ product.name }}</span>\n                      <div class=\"text-warning mt-1 flex items-center gap-1 text-xs\">\n                        <Star class=\"size-3 fill-current\" />\n                        <span class=\"text-foreground font-medium tabular-nums\">{{ product.rating }}</span>\n                      </div>\n                      <span class=\"text-foreground mt-1 text-sm font-bold tabular-nums\">{{ product.price }}</span>\n                    </div>\n                  </div>\n\n                  <!-- Quick Buy Trigger -->\n                  <Button\n                    size=\"sm\"\n                    variant=\"default\"\n                    class=\"w-full gap-1.5 text-xs shadow-xs\"\n                    :disabled=\"addedProductId === product.id\"\n                    @click=\"handleAddToCart(product)\"\n                  >\n                    <Check v-if=\"addedProductId === product.id\" class=\"text-success size-3.5\" />\n                    <ShoppingCart v-else class=\"size-3.5\" />\n                    {{ addedProductId === product.id ? 'Added to Cart' : 'Add to Cart' }}\n                  </Button>\n                </div>\n              </th>\n            </tr>\n          </thead>\n\n          <!-- Table Body grouped by Category -->\n          <tbody v-for=\"category in categories\" :key=\"category.name\">\n            <!-- Category Subheading Header Row -->\n            <tr>\n              <th\n                :colspan=\"selectedProducts.length + 1\"\n                scope=\"colgroup\"\n                class=\"bg-muted/60 text-muted-foreground sticky left-0 z-10 border-b px-4 py-2 text-xs font-semibold tracking-wider uppercase\"\n              >\n                {{ category.name }}\n              </th>\n            </tr>\n\n            <!-- Specification Rows -->\n            <tr\n              v-for=\"field in category.fields\"\n              :key=\"field.key\"\n              class=\"group/row transition-colors\"\n              :class=\"[\n                isRowDiff(field.key) && highlightDiffs\n                  ? 'bg-primary/[0.04] dark:bg-primary/[0.08]'\n                  : 'hover:bg-muted/20',\n                !isRowDiff(field.key) && highlightDiffs ? 'opacity-40' : 'opacity-100',\n              ]\"\n            >\n              <!-- Spec Label Cell (Sticky Left) -->\n              <th\n                scope=\"row\"\n                class=\"bg-background group-hover/row:bg-muted/30 sticky left-0 z-10 border-b p-3.5 align-middle text-xs font-medium\"\n              >\n                <div class=\"flex items-center justify-between gap-1.5\">\n                  <div class=\"flex flex-col\">\n                    <span class=\"text-foreground font-medium\">{{ field.label }}</span>\n                    <span v-if=\"field.description\" class=\"text-muted-foreground text-xs font-normal\">\n                      {{ field.description }}\n                    </span>\n                  </div>\n                  <span\n                    v-if=\"isRowDiff(field.key) && highlightDiffs\"\n                    class=\"bg-primary/10 text-primary shrink-0 rounded px-1.5 py-0.5 text-xs font-semibold\"\n                  >\n                    Diff\n                  </span>\n                </div>\n              </th>\n\n              <!-- Spec Values for Each Selected Product -->\n              <td\n                v-for=\"product in selectedProducts\"\n                :key=\"product.id\"\n                class=\"text-foreground border-b p-3.5 align-middle text-xs\"\n              >\n                <div class=\"flex items-center gap-1.5\">\n                  <span\n                    :class=\"{\n                      'font-semibold tabular-nums':\n                        field.key === 'price' || field.key === 'weight' || field.key === 'batteryLife',\n                      'text-foreground font-medium': isRowDiff(field.key),\n                      'text-muted-foreground': !isRowDiff(field.key),\n                    }\"\n                  >\n                    {{ product.specs[field.key] || '—' }}\n                  </span>\n                </div>\n              </td>\n            </tr>\n          </tbody>\n\n          <!-- Sticky Bottom Buy Triggers Footer -->\n          <tfoot>\n            <tr class=\"bg-card sticky bottom-0 z-20\">\n              <th scope=\"row\" class=\"bg-card sticky left-0 z-20 border-t p-4 align-middle\">\n                <div class=\"space-y-0.5\">\n                  <span class=\"text-foreground text-xs font-semibold\">Sticky Buy Trigger</span>\n                  <p class=\"text-muted-foreground text-xs\">All purchases backed by 30-day money-back guarantee.</p>\n                </div>\n              </th>\n\n              <td v-for=\"product in selectedProducts\" :key=\"product.id\" class=\"border-t p-4 align-middle\">\n                <div class=\"flex flex-col gap-1.5\">\n                  <div class=\"flex items-center justify-between\">\n                    <span class=\"text-foreground text-xs font-bold tabular-nums\">{{ product.price }}</span>\n                    <span class=\"text-muted-foreground text-xs\">{{ product.shipping }}</span>\n                  </div>\n                  <Button\n                    size=\"sm\"\n                    variant=\"default\"\n                    class=\"w-full gap-1.5 text-xs shadow-xs\"\n                    :disabled=\"addedProductId === product.id\"\n                    @click=\"handleAddToCart(product)\"\n                  >\n                    <Check v-if=\"addedProductId === product.id\" class=\"text-success size-3.5\" />\n                    <ShoppingCart v-else class=\"size-3.5\" />\n                    {{ addedProductId === product.id ? 'Added' : 'Buy Now' }}\n                  </Button>\n                </div>\n              </td>\n            </tr>\n          </tfoot>\n        </table>\n      </div>\n    </div>\n  </div>\n</template>\n",
      "type": "registry:block",
      "target": "~/app/components/blocks/ProductComparisonDrawer.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/card.json",
    "https://uipkge.dev/r/vue/separator.json",
    "https://uipkge.dev/r/vue/switch.json",
    "https://uipkge.dev/r/vue/table.json"
  ],
  "description": "Floating multi-product specification comparison bar with attribute diff highlighting, expanded full-matrix drawer comparison, and sticky buy triggers.",
  "categories": [
    "commerce",
    "ecommerce"
  ]
}