{
  "$schema": "https://shadcn-vue.com/schema/registry-item.json",
  "name": "virtual-card-manager",
  "title": "Virtual Card Manager",
  "type": "registry:block",
  "files": [
    {
      "path": "packages/registry-vue/blocks/virtual-card-manager/VirtualCardManager.vue",
      "content": "<script setup lang=\"ts\">\nimport { computed, ref } from 'vue'\nimport type { HTMLAttributes } from 'vue'\nimport {\n  Check,\n  CheckCircle2,\n  Copy,\n  CreditCard,\n  Eye,\n  EyeOff,\n  Plus,\n  Radio,\n  ShieldCheck,\n  SlidersHorizontal,\n  Snowflake,\n  Trash2,\n  Zap,\n} from 'lucide-vue-next'\nimport { cn } from '@/lib/utils'\nimport { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar'\nimport { Badge } from '@/components/ui/badge'\nimport { Button } from '@/components/ui/button'\nimport { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'\nimport { Progress } from '@/components/ui/progress'\nimport { Switch } from '@/components/ui/switch'\n\ninterface VirtualCard {\n  id: string\n  name: string\n  brand: 'mastercard' | 'visa'\n  last4: string\n  fullNumber: string\n  holder: string\n  avatar: string\n  initials: string\n  expiry: string\n  cvv: string\n  spent: number\n  limit: number\n  type: 'Monthly Recurring' | 'Single-use'\n  status: 'Active' | 'Frozen'\n  billingCycle: string\n  purpose: string\n}\n\nconst props = defineProps<{\n  class?: HTMLAttributes['class']\n}>()\n\nconst initialCards: VirtualCard[] = [\n  {\n    id: 'vc-1',\n    name: 'AWS & Cloud Infrastructure',\n    brand: 'mastercard',\n    last4: '8492',\n    fullNumber: '5532 8920 4108 8492',\n    holder: 'Elena Rostova',\n    avatar: 'https://images.unsplash.com/photo-1534528741775-53994a69daeb?w=100&auto=format&fit=crop&q=80',\n    initials: 'ER',\n    expiry: '08/29',\n    cvv: '482',\n    spent: 4200,\n    limit: 5000,\n    type: 'Monthly Recurring',\n    status: 'Active',\n    billingCycle: 'Resets on 1st of month',\n    purpose: 'Cloud compute, S3 buckets, and RDS instances',\n  },\n  {\n    id: 'vc-2',\n    name: 'Marketing & Ad Spend',\n    brand: 'visa',\n    last4: '3190',\n    fullNumber: '4012 8831 9204 3190',\n    holder: 'Marcus Chen',\n    avatar: 'https://images.unsplash.com/photo-1507003211169-0a1dd7228f2d?w=100&auto=format&fit=crop&q=80',\n    initials: 'MC',\n    expiry: '11/28',\n    cvv: '915',\n    spent: 8750,\n    limit: 10000,\n    type: 'Monthly Recurring',\n    status: 'Active',\n    billingCycle: 'Resets on 1st of month',\n    purpose: 'Google Ads, LinkedIn campaigns, and Meta Ads',\n  },\n  {\n    id: 'vc-3',\n    name: 'Travel & Conferences',\n    brand: 'visa',\n    last4: '6021',\n    fullNumber: '4111 5900 1284 6021',\n    holder: 'Sarah Jenkins',\n    avatar: 'https://images.unsplash.com/photo-1494790108377-be9c29b29330?w=100&auto=format&fit=crop&q=80',\n    initials: 'SJ',\n    expiry: '03/27',\n    cvv: '304',\n    spent: 1850,\n    limit: 2500,\n    type: 'Single-use',\n    status: 'Frozen',\n    billingCycle: 'Single event allowance',\n    purpose: 'Q3 Design Systems Summit flights and lodging',\n  },\n  {\n    id: 'vc-4',\n    name: 'SaaS Subscriptions',\n    brand: 'mastercard',\n    last4: '9455',\n    fullNumber: '5241 7719 3302 9455',\n    holder: 'Elena Rostova',\n    avatar: 'https://images.unsplash.com/photo-1534528741775-53994a69daeb?w=100&auto=format&fit=crop&q=80',\n    initials: 'ER',\n    expiry: '05/29',\n    cvv: '729',\n    spent: 620,\n    limit: 1200,\n    type: 'Monthly Recurring',\n    status: 'Active',\n    billingCycle: 'Resets on 1st of month',\n    purpose: 'GitHub Enterprise, Figma, and Slack licenses',\n  },\n]\n\nconst cards = ref<VirtualCard[]>(initialCards)\nconst selectedId = ref<string>('vc-1')\nconst showDetails = ref<boolean>(false)\nconst copied = ref<boolean>(false)\nconst actionFeedback = ref<string | null>(null)\n\nconst selectedCard = computed(() => cards.value.find((c) => c.id === selectedId.value) ?? cards.value[0])\n\nconst selectedPercent = computed(() => {\n  if (!selectedCard.value || selectedCard.value.limit === 0) return 0\n  return Math.min(100, Math.round((selectedCard.value.spent / selectedCard.value.limit) * 100))\n})\n\nconst isSelectedFrozen = computed(() => selectedCard.value?.status === 'Frozen')\n\nfunction toggleFreeze(id: string) {\n  cards.value = cards.value.map((c) => {\n    if (c.id === id) {\n      const nextStatus = c.status === 'Active' ? 'Frozen' : 'Active'\n      return { ...c, status: nextStatus }\n    }\n    return c\n  })\n}\n\nfunction handleCopyNumber() {\n  if (!selectedCard.value) return\n  if (navigator?.clipboard) {\n    navigator.clipboard.writeText(selectedCard.value.fullNumber.replace(/\\s+/g, ''))\n  }\n  copied.value = true\n  setTimeout(() => {\n    copied.value = false\n  }, 2000)\n}\n\nfunction adjustLimit(cardId: string) {\n  cards.value = cards.value.map((c) => {\n    if (c.id === cardId) {\n      const newLimit = c.limit === 5000 ? 7500 : c.limit === 10000 ? 12000 : c.limit + 1000\n      return { ...c, limit: newLimit }\n    }\n    return c\n  })\n  showFeedback(`Limit updated to $${selectedCard.value.limit.toLocaleString()}`)\n}\n\nfunction terminateCard(cardId: string) {\n  if (cards.value.length <= 1) {\n    showFeedback('Cannot terminate the last remaining card')\n    return\n  }\n  const remaining = cards.value.filter((c) => c.id !== cardId)\n  cards.value = remaining\n  if (selectedId.value === cardId) {\n    selectedId.value = remaining[0].id\n  }\n  showFeedback('Card terminated permanently')\n}\n\nfunction issueNewCard() {\n  const newId = `vc-${Date.now().toString().slice(-4)}`\n  const newLast4 = Math.floor(1000 + Math.random() * 9000).toString()\n  const newCard: VirtualCard = {\n    id: newId,\n    name: 'AI & API Workloads',\n    brand: 'visa',\n    last4: newLast4,\n    fullNumber: `4400 1284 9912 ${newLast4}`,\n    holder: 'Elena Rostova',\n    avatar: 'https://images.unsplash.com/photo-1534528741775-53994a69daeb?w=100&auto=format&fit=crop&q=80',\n    initials: 'ER',\n    expiry: '09/30',\n    cvv: '814',\n    spent: 0,\n    limit: 3000,\n    type: 'Monthly Recurring',\n    status: 'Active',\n    billingCycle: 'Resets on 1st of month',\n    purpose: 'OpenAI, Anthropic, and Vector DB infrastructure',\n  }\n  cards.value = [newCard, ...cards.value]\n  selectedId.value = newId\n  showFeedback('New virtual card issued successfully')\n}\n\nfunction showFeedback(msg: string) {\n  actionFeedback.value = msg\n  setTimeout(() => {\n    if (actionFeedback.value === msg) {\n      actionFeedback.value = null\n    }\n  }, 3000)\n}\n</script>\n\n<template>\n  <div data-slot=\"virtual-card-manager\" :class=\"cn('mx-auto w-full max-w-6xl space-y-6', props.class)\">\n    <!-- Header -->\n    <div class=\"flex flex-col gap-4 sm:flex-row sm:items-center sm:justify-between\">\n      <div class=\"space-y-1\">\n        <div class=\"flex items-center gap-2.5\">\n          <h2 class=\"text-foreground text-xl font-semibold tracking-tight sm:text-2xl\">Virtual Cards</h2>\n          <Badge wrap variant=\"secondary\" class=\"font-mono text-xs tabular-nums\">{{ cards.length }} Cards</Badge>\n        </div>\n        <p class=\"text-muted-foreground text-sm\">\n          Generate instant corporate cards for subscriptions, vendors, and team expense limits.\n        </p>\n      </div>\n\n      <div class=\"flex items-center gap-2\">\n        <Button size=\"sm\" class=\"gap-1.5 shadow-xs\" @click=\"issueNewCard\">\n          <Plus class=\"size-4\" />\n          Issue New Card\n        </Button>\n      </div>\n    </div>\n\n    <!-- Notification / Action Toast feedback -->\n    <div\n      v-if=\"actionFeedback\"\n      class=\"bg-primary/10 text-primary border-primary/20 flex items-center justify-between rounded-lg border px-4 py-2.5 text-xs font-medium transition-colors\"\n    >\n      <div class=\"flex items-center gap-2\">\n        <CheckCircle2 class=\"size-4 shrink-0\" />\n        <span>{{ actionFeedback }}</span>\n      </div>\n      <Button\n        aria-label=\"Dismiss notification\"\n        variant=\"ghost\"\n        size=\"xs\"\n        class=\"h-6 px-2 text-xs\"\n        @click=\"actionFeedback = null\"\n        >Dismiss</Button\n      >\n    </div>\n\n    <!-- Virtual Card Visual Hero -->\n    <Card class=\"border-border bg-card shadow-xs\">\n      <CardHeader class=\"border-b pb-4\">\n        <div class=\"flex flex-wrap items-center justify-between gap-2\">\n          <div>\n            <div class=\"flex items-center gap-2\">\n              <CardTitle class=\"text-base font-semibold\">{{ selectedCard.name }}</CardTitle>\n              <Badge\n                :variant=\"selectedCard.status === 'Active' ? 'success' : 'warning'\"\n                class=\"text-xs whitespace-normal\"\n              >\n                {{ selectedCard.status }}\n              </Badge>\n            </div>\n            <CardDescription class=\"mt-0.5 text-xs\">\n              {{ selectedCard.purpose }} · {{ selectedCard.billingCycle }}\n            </CardDescription>\n          </div>\n          <Badge wrap variant=\"outline\" class=\"font-mono text-xs\"> Ending in {{ selectedCard.last4 }} </Badge>\n        </div>\n      </CardHeader>\n\n      <CardContent class=\"pt-6\">\n        <div class=\"grid gap-6 lg:grid-cols-12 lg:items-center\">\n          <!-- Stylized Dark Credit Card Container -->\n          <div class=\"lg:col-span-6 xl:col-span-5\">\n            <div\n              :class=\"\n                cn(\n                  'relative aspect-[1.586/1] w-full max-w-[420px] rounded-2xl p-6 text-white transition-[filter] duration-300 lg:max-w-full',\n                  'border border-zinc-700/60 bg-gradient-to-br from-zinc-900 via-neutral-900 to-zinc-950 shadow-xl',\n                  isSelectedFrozen && 'contrast-95 grayscale filter',\n                )\n              \"\n            >\n              <!-- Ambient light accents -->\n              <div\n                class=\"bg-chart-1/15 pointer-events-none absolute -top-16 -right-16 size-48 rounded-full blur-2xl\"\n                aria-hidden=\"true\"\n              />\n              <div\n                class=\"bg-success/10 pointer-events-none absolute -bottom-16 -left-16 size-48 rounded-full blur-2xl\"\n                aria-hidden=\"true\"\n              />\n\n              <!-- Frozen watermark overlay -->\n              <div\n                v-if=\"isSelectedFrozen\"\n                class=\"absolute inset-0 z-20 flex flex-col items-center justify-center gap-2 rounded-2xl bg-zinc-950/70 backdrop-blur-xs\"\n              >\n                <div\n                  class=\"border-warning/40 bg-warning/20 text-warning inline-flex items-center gap-1.5 rounded-full border px-3 py-1 text-xs font-semibold tracking-wider uppercase\"\n                >\n                  <Snowflake class=\"size-3.5\" />\n                  Card Frozen\n                </div>\n                <p class=\"text-muted-foreground text-xs\">Transactions are currently blocked</p>\n              </div>\n\n              <!-- Top Row: Chip & Contactless + Brand Logo -->\n              <div class=\"relative z-10 flex items-center justify-between\">\n                <div class=\"flex items-center gap-3\">\n                  <!-- Metallic EMV Chip -->\n                  <div\n                    class=\"border-warning/20/40 relative flex h-8 w-11 items-center justify-center rounded-md border bg-gradient-to-br from-amber-200/30 via-amber-400/20 to-amber-600/30 shadow-inner\"\n                    aria-hidden=\"true\"\n                  >\n                    <div class=\"border-warning/20/30 absolute inset-0 grid grid-cols-3 grid-rows-2\">\n                      <div class=\"border-warning/30 border-r border-b\" />\n                      <div class=\"border-warning/30 border-r border-b\" />\n                      <div class=\"border-warning/30 border-b\" />\n                      <div class=\"border-warning/30 border-r\" />\n                      <div class=\"border-warning/30 border-r\" />\n                      <div />\n                    </div>\n                  </div>\n\n                  <!-- NFC Wave icon -->\n                  <div class=\"text-muted-foreground/80 rotate-90\" aria-hidden=\"true\">\n                    <Radio class=\"size-4\" />\n                  </div>\n                </div>\n\n                <!-- Brand Indicator -->\n                <div class=\"flex items-center gap-2\">\n                  <span class=\"text-muted-foreground font-mono text-xs font-medium tracking-wider uppercase\"\n                    >Virtual</span\n                  >\n                  <div v-if=\"selectedCard.brand === 'mastercard'\" class=\"flex -space-x-2\" aria-label=\"Mastercard\">\n                    <div class=\"bg-destructive/90 size-6 rounded-full\" />\n                    <div class=\"bg-warning/90 size-6 rounded-full mix-blend-screen\" />\n                  </div>\n                  <div v-else class=\"text-base font-bold tracking-widest text-zinc-100 italic\" aria-label=\"Visa\">\n                    VISA\n                  </div>\n                </div>\n              </div>\n\n              <!-- Middle Row: Card Number & Quick Actions -->\n              <div class=\"relative z-10 my-auto pt-4\">\n                <div class=\"flex items-center justify-between gap-2\">\n                  <p\n                    class=\"font-mono text-lg font-medium tracking-[0.16em] text-zinc-100 tabular-nums drop-shadow-sm sm:text-xl\"\n                  >\n                    {{ showDetails ? selectedCard.fullNumber : `•••• •••• •••• ${selectedCard.last4}` }}\n                  </p>\n                  <div class=\"flex items-center gap-1\">\n                    <Button\n                      variant=\"ghost\"\n                      size=\"icon-sm\"\n                      class=\"size-7 text-zinc-300 hover:bg-white/10 hover:text-white\"\n                      :aria-label=\"showDetails ? 'Hide card number' : 'Reveal card number'\"\n                      @click=\"showDetails = !showDetails\"\n                    >\n                      <EyeOff v-if=\"showDetails\" class=\"size-3.5\" />\n                      <Eye v-else class=\"size-3.5\" />\n                    </Button>\n                    <Button\n                      variant=\"ghost\"\n                      size=\"icon-sm\"\n                      class=\"size-7 text-zinc-300 hover:bg-white/10 hover:text-white\"\n                      aria-label=\"Copy card number\"\n                      @click=\"handleCopyNumber\"\n                    >\n                      <Check v-if=\"copied\" class=\"text-success size-3.5\" />\n                      <Copy v-else class=\"size-3.5\" />\n                    </Button>\n                  </div>\n                </div>\n              </div>\n\n              <!-- Bottom Row: Cardholder, Expiry, CVV -->\n              <div class=\"relative z-10 flex items-end justify-between pt-2\">\n                <div class=\"space-y-0.5\">\n                  <p class=\"text-muted-foreground font-mono text-xs tracking-wider uppercase\">Cardholder</p>\n                  <p class=\"max-w-[140px] truncate text-xs font-semibold tracking-wide text-zinc-200 uppercase\">\n                    {{ selectedCard.holder }}\n                  </p>\n                </div>\n\n                <div class=\"space-y-0.5\">\n                  <p class=\"text-muted-foreground font-mono text-xs tracking-wider uppercase\">Expires</p>\n                  <p class=\"font-mono text-xs font-medium text-zinc-200 tabular-nums\">{{ selectedCard.expiry }}</p>\n                </div>\n\n                <div class=\"space-y-0.5 text-right\">\n                  <p class=\"text-muted-foreground font-mono text-xs tracking-wider uppercase\">CVV</p>\n                  <p class=\"font-mono text-xs font-medium text-zinc-200 tabular-nums\">\n                    {{ showDetails ? selectedCard.cvv : '•••' }}\n                  </p>\n                </div>\n              </div>\n            </div>\n          </div>\n\n          <!-- Card Controls & Spending Breakdown -->\n          <div class=\"space-y-6 lg:col-span-6 xl:col-span-7\">\n            <!-- Spending Limit Meter -->\n            <div class=\"border-border bg-muted/30 space-y-3 rounded-lg border p-4\">\n              <div class=\"flex items-center justify-between\">\n                <span class=\"text-sm font-medium\">Monthly Spending Limit</span>\n                <span class=\"text-muted-foreground font-mono text-xs tabular-nums\">\n                  ${{ selectedCard.spent.toLocaleString() }} / ${{ selectedCard.limit.toLocaleString() }}\n                </span>\n              </div>\n\n              <Progress :model-value=\"selectedPercent\" class=\"h-2\" />\n\n              <div class=\"text-muted-foreground flex items-center justify-between text-xs\">\n                <span class=\"text-foreground font-medium tabular-nums\">\n                  ${{ Math.max(0, selectedCard.limit - selectedCard.spent).toLocaleString() }} available\n                </span>\n                <span class=\"font-medium tabular-nums\"> {{ selectedPercent }}% utilized </span>\n              </div>\n            </div>\n\n            <!-- Card Controls Row -->\n            <div class=\"grid gap-3 sm:grid-cols-3\">\n              <!-- Freeze Card Toggle -->\n              <div\n                class=\"border-border bg-card flex items-center justify-between rounded-lg border p-3 sm:flex-col sm:items-start sm:justify-between sm:gap-2\"\n              >\n                <div class=\"space-y-0.5\">\n                  <p class=\"text-foreground text-xs font-medium\">Freeze Card</p>\n                  <p class=\"text-muted-foreground text-xs\">Block charges</p>\n                </div>\n                <Switch\n                  :model-value=\"isSelectedFrozen\"\n                  size=\"sm\"\n                  aria-label=\"Toggle card freeze status\"\n                  @update:model-value=\"toggleFreeze(selectedCard.id)\"\n                />\n              </div>\n\n              <!-- Change Limit Button -->\n              <Button\n                variant=\"outline\"\n                size=\"sm\"\n                class=\"h-auto flex-col items-start gap-1 p-3 text-left\"\n                @click=\"adjustLimit(selectedCard.id)\"\n              >\n                <div class=\"flex w-full items-center justify-between\">\n                  <span class=\"text-foreground text-xs font-medium\">Adjust Limit</span>\n                  <SlidersHorizontal class=\"text-muted-foreground size-3.5\" />\n                </div>\n                <span class=\"text-muted-foreground text-xs font-normal\">Edit monthly cap</span>\n              </Button>\n\n              <!-- Terminate Card Button -->\n              <Button\n                variant=\"outline\"\n                size=\"sm\"\n                class=\"text-destructive hover:text-destructive hover:bg-destructive/10 border-border h-auto flex-col items-start gap-1 p-3 text-left\"\n                @click=\"terminateCard(selectedCard.id)\"\n              >\n                <div class=\"flex w-full items-center justify-between\">\n                  <span class=\"text-xs font-medium\">Terminate</span>\n                  <Trash2 class=\"size-3.5\" />\n                </div>\n                <span class=\"text-muted-foreground text-xs font-normal\">Close permanently</span>\n              </Button>\n            </div>\n\n            <!-- Card Meta Specs -->\n            <div class=\"grid grid-cols-2 gap-3 pt-1 sm:grid-cols-3\">\n              <div class=\"space-y-0.5\">\n                <span class=\"text-muted-foreground text-xs\">Cardholder</span>\n                <div class=\"flex items-center gap-1.5 pt-0.5\">\n                  <Avatar size=\"xs\" class=\"size-4.5\">\n                    <AvatarImage :src=\"selectedCard.avatar\" :alt=\"selectedCard.holder\" />\n                    <AvatarFallback class=\"text-xs\">{{ selectedCard.initials }}</AvatarFallback>\n                  </Avatar>\n                  <span class=\"truncate text-xs font-medium\">{{ selectedCard.holder }}</span>\n                </div>\n              </div>\n\n              <div class=\"space-y-0.5\">\n                <span class=\"text-muted-foreground text-xs\">Card Type</span>\n                <p class=\"text-foreground text-xs font-medium\">{{ selectedCard.type }}</p>\n              </div>\n\n              <div class=\"space-y-0.5\">\n                <span class=\"text-muted-foreground text-xs\">Fraud Protection</span>\n                <div class=\"text-success flex items-center gap-1 text-xs font-medium\">\n                  <ShieldCheck class=\"size-3.5\" />\n                  <span>3D Secure Active</span>\n                </div>\n              </div>\n            </div>\n          </div>\n        </div>\n      </CardContent>\n    </Card>\n\n    <!-- Active Cards Grid / Table -->\n    <Card class=\"border-border bg-card shadow-xs\">\n      <CardHeader class=\"border-b pb-4\">\n        <div class=\"flex items-center justify-between\">\n          <div>\n            <CardTitle class=\"text-base font-semibold\">Active Cards List</CardTitle>\n            <CardDescription class=\"mt-0.5 text-xs\">\n              All company virtual cards currently assigned to team members and services.\n            </CardDescription>\n          </div>\n          <Badge wrap variant=\"outline\" class=\"font-mono text-xs tabular-nums\"> {{ cards.length }} Issued </Badge>\n        </div>\n      </CardHeader>\n\n      <CardContent class=\"p-0\">\n        <div class=\"divide-border divide-y\">\n          <div\n            v-for=\"card in cards\"\n            :key=\"card.id\"\n            :class=\"\n              cn(\n                'group flex flex-col gap-4 p-4 transition-colors sm:flex-row sm:items-center sm:justify-between',\n                selectedId === card.id ? 'bg-muted/40' : 'hover:bg-muted/20',\n              )\n            \"\n          >\n            <!-- Card Identity & Number -->\n            <div class=\"flex min-w-0 items-center gap-3.5 sm:w-1/3\">\n              <div\n                :class=\"\n                  cn(\n                    'border-border flex size-10 shrink-0 items-center justify-center rounded-lg border shadow-xs transition-transform',\n                    card.status === 'Frozen' ? 'bg-muted/60 text-muted-foreground' : 'bg-primary/10 text-primary',\n                  )\n                \"\n              >\n                <CreditCard class=\"size-5\" />\n              </div>\n\n              <div class=\"min-w-0 flex-1 space-y-0.5\">\n                <div class=\"flex items-center gap-2\">\n                  <p class=\"text-foreground truncate text-sm font-medium\">{{ card.name }}</p>\n                </div>\n                <div class=\"text-muted-foreground flex items-center gap-2 text-xs\">\n                  <span class=\"font-mono tabular-nums\">•••• {{ card.last4 }}</span>\n                  <span>·</span>\n                  <span class=\"uppercase\">{{ card.brand }}</span>\n                </div>\n              </div>\n            </div>\n\n            <!-- Cardholder Avatar & Name -->\n            <div class=\"flex items-center gap-2 sm:w-1/5\">\n              <Avatar size=\"sm\">\n                <AvatarImage :src=\"card.avatar\" :alt=\"card.holder\" />\n                <AvatarFallback>{{ card.initials }}</AvatarFallback>\n              </Avatar>\n              <div class=\"min-w-0\">\n                <p class=\"text-foreground truncate text-xs font-medium\">{{ card.holder }}</p>\n                <p class=\"text-muted-foreground truncate text-xs\">{{ card.type }}</p>\n              </div>\n            </div>\n\n            <!-- Spending Limit & Progress -->\n            <div class=\"space-y-1.5 sm:w-1/4\">\n              <div class=\"flex items-center justify-between text-xs\">\n                <span class=\"text-foreground font-mono font-medium tabular-nums\">\n                  ${{ card.spent.toLocaleString() }} / ${{ card.limit.toLocaleString() }}\n                </span>\n                <span class=\"text-muted-foreground font-mono tabular-nums\">\n                  {{ Math.round((card.spent / card.limit) * 100) }}%\n                </span>\n              </div>\n              <Progress :model-value=\"Math.min(100, Math.round((card.spent / card.limit) * 100))\" class=\"h-1.5\" />\n            </div>\n\n            <!-- Status Badge & Actions -->\n            <div class=\"flex items-center justify-between gap-3 sm:justify-end\">\n              <Badge :variant=\"card.status === 'Active' ? 'success' : 'warning'\" class=\"text-xs whitespace-normal\">\n                {{ card.status }}\n              </Badge>\n\n              <div class=\"flex items-center gap-1.5\">\n                <Button\n                  :variant=\"selectedId === card.id ? 'secondary' : 'ghost'\"\n                  size=\"sm\"\n                  class=\"text-xs\"\n                  @click=\"selectedId = card.id\"\n                >\n                  {{ selectedId === card.id ? 'Viewing' : 'View Card' }}\n                </Button>\n\n                <Button\n                  variant=\"ghost\"\n                  size=\"icon-sm\"\n                  :aria-label=\"card.status === 'Active' ? 'Freeze card' : 'Unfreeze card'\"\n                  @click=\"toggleFreeze(card.id)\"\n                >\n                  <Snowflake v-if=\"card.status === 'Active'\" class=\"text-muted-foreground size-4\" />\n                  <Zap v-else class=\"text-warning size-4\" />\n                </Button>\n              </div>\n            </div>\n          </div>\n        </div>\n      </CardContent>\n    </Card>\n  </div>\n</template>\n",
      "type": "registry:block",
      "target": "~/app/components/blocks/VirtualCardManager.vue"
    }
  ],
  "dependencies": [
    "lucide-vue-next"
  ],
  "devDependencies": [],
  "registryDependencies": [
    "https://uipkge.dev/r/vue/avatar.json",
    "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/progress.json",
    "https://uipkge.dev/r/vue/switch.json"
  ],
  "description": "Mercury/Ramp-style corporate virtual card manager: interactive dark credit card visual hero with EMV chip, revealable credentials, live spending limit progress bar, instant freeze toggles, limit adjusters, and an active virtual cards table.",
  "categories": [
    "finance",
    "app",
    "billing"
  ]
}