{
  "$schema": "https://shadcn-vue.com/schema/registry-item.json",
  "name": "currency-converter-widget",
  "title": "Currency Converter Widget",
  "type": "registry:block",
  "files": [
    {
      "path": "packages/registry-vue/blocks/currency-converter-widget/CurrencyConverterWidget.vue",
      "content": "<script setup lang=\"ts\">\nimport { computed, ref, type HTMLAttributes } from 'vue'\nimport {\n  ArrowDownRight,\n  ArrowRight,\n  ArrowUpDown,\n  ArrowUpRight,\n  Building2,\n  Lock,\n  Minus,\n  RefreshCw,\n  ShieldCheck,\n  Coins,\n  Zap,\n} from 'lucide-vue-next'\nimport { cn } from '@/lib/utils'\nimport { Badge } from '@/components/ui/badge'\nimport { Button } from '@/components/ui/button'\nimport { Card, CardContent } from '@/components/ui/card'\nimport { Select, SelectContent, SelectItem, SelectTrigger } from '@/components/ui/select'\nimport { Separator } from '@/components/ui/separator'\n\ninterface Props {\n  initialSendAmount?: number\n  initialFromCurrency?: string\n  initialToCurrency?: string\n  class?: HTMLAttributes['class']\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n  initialSendAmount: 1000,\n  initialFromCurrency: 'USD',\n  initialToCurrency: 'EUR',\n})\n\nconst emit = defineEmits<{\n  (\n    e: 'transfer',\n    payload: {\n      sendAmount: number\n      fromCurrency: string\n      toCurrency: string\n      recipientGets: number\n      fee: number\n      rate: number\n    },\n  ): void\n}>()\n\nexport interface CurrencyOption {\n  code: string\n  name: string\n  symbol: string\n  flag: string\n  rateToBase: number // USD base = 1.0\n  deliverySpeed: string\n  deliveryNetwork: string\n}\n\nexport interface PopularPair {\n  id: string\n  from: string\n  to: string\n  change24h: number\n  trend: 'up' | 'down'\n}\n\nconst CURRENCIES: CurrencyOption[] = [\n  {\n    code: 'USD',\n    name: 'US Dollar',\n    symbol: '$',\n    flag: '🇺🇸',\n    rateToBase: 1.0,\n    deliverySpeed: 'in minutes',\n    deliveryNetwork: 'FedNow / RTP',\n  },\n  {\n    code: 'EUR',\n    name: 'Euro',\n    symbol: '€',\n    flag: '🇪🇺',\n    rateToBase: 0.9245,\n    deliverySpeed: 'in minutes',\n    deliveryNetwork: 'SEPA Instant',\n  },\n  {\n    code: 'GBP',\n    name: 'British Pound',\n    symbol: '£',\n    flag: '🇬🇧',\n    rateToBase: 0.7892,\n    deliverySpeed: 'in seconds',\n    deliveryNetwork: 'Faster Payments',\n  },\n  {\n    code: 'JPY',\n    name: 'Japanese Yen',\n    symbol: '¥',\n    flag: '🇯🇵',\n    rateToBase: 154.6,\n    deliverySpeed: 'within 4 hours',\n    deliveryNetwork: 'Zengin System',\n  },\n  {\n    code: 'CAD',\n    name: 'Canadian Dollar',\n    symbol: 'CA$',\n    flag: '🇨🇦',\n    rateToBase: 1.378,\n    deliverySpeed: 'in minutes',\n    deliveryNetwork: 'Interac Direct',\n  },\n  {\n    code: 'AUD',\n    name: 'Australian Dollar',\n    symbol: 'A$',\n    flag: '🇦🇺',\n    rateToBase: 1.523,\n    deliverySpeed: 'in minutes',\n    deliveryNetwork: 'NPP / PayID',\n  },\n  {\n    code: 'SGD',\n    name: 'Singapore Dollar',\n    symbol: 'S$',\n    flag: '🇸🇬',\n    rateToBase: 1.348,\n    deliverySpeed: 'instant',\n    deliveryNetwork: 'FAST Network',\n  },\n  {\n    code: 'CHF',\n    name: 'Swiss Franc',\n    symbol: 'CHF',\n    flag: '🇨🇭',\n    rateToBase: 0.898,\n    deliverySpeed: 'in minutes',\n    deliveryNetwork: 'SIC Instant',\n  },\n]\n\nconst POPULAR_PAIRS: PopularPair[] = [\n  { id: 'eur-usd', from: 'EUR', to: 'USD', change24h: 0.18, trend: 'up' },\n  { id: 'gbp-usd', from: 'GBP', to: 'USD', change24h: 0.24, trend: 'up' },\n  { id: 'usd-jpy', from: 'USD', to: 'JPY', change24h: -0.32, trend: 'down' },\n  { id: 'usd-cad', from: 'USD', to: 'CAD', change24h: 0.09, trend: 'up' },\n  { id: 'usd-eur', from: 'USD', to: 'EUR', change24h: -0.18, trend: 'down' },\n  { id: 'gbp-eur', from: 'GBP', to: 'EUR', change24h: 0.05, trend: 'up' },\n]\n\nconst sendAmount = ref<number>(props.initialSendAmount)\nconst fromCurrency = ref<string>(props.initialFromCurrency)\nconst toCurrency = ref<string>(props.initialToCurrency)\nconst isRefreshing = ref<boolean>(false)\nconst refreshSuccess = ref<boolean>(false)\nconst paymentMethod = ref<'bank' | 'card'>('bank')\n\nconst fromCurrencyObj = computed(() => CURRENCIES.find((c) => c.code === fromCurrency.value) || CURRENCIES[0])\nconst toCurrencyObj = computed(() => CURRENCIES.find((c) => c.code === toCurrency.value) || CURRENCIES[1])\n\n// Dynamic mid-market rate calculation\nconst exchangeRate = computed(() => {\n  if (!fromCurrencyObj.value || !toCurrencyObj.value) return 1\n  return toCurrencyObj.value.rateToBase / fromCurrencyObj.value.rateToBase\n})\n\nconst inverseExchangeRate = computed(() => {\n  if (exchangeRate.value === 0) return 0\n  return 1 / exchangeRate.value\n})\n\nconst formattedExchangeRate = computed(() => {\n  const r = exchangeRate.value\n  if (r >= 100) return r.toFixed(2)\n  if (r >= 1) return r.toFixed(4)\n  return r.toFixed(5)\n})\n\n// Fee breakdown logic\nconst fixedBaseFee = computed(() => {\n  // Base fixed fee equivalent to ~$1.20 USD\n  const fromRate = fromCurrencyObj.value.rateToBase\n  const base = 1.2 * fromRate\n  return paymentMethod.value === 'card' ? base * 1.6 : base\n})\n\nconst variableRate = computed(() => (paymentMethod.value === 'card' ? 0.0065 : 0.0035))\n\nconst variableFee = computed(() => {\n  const amt = Number(sendAmount.value) || 0\n  return amt * variableRate.value\n})\n\nconst totalFee = computed(() => {\n  return fixedBaseFee.value + variableFee.value\n})\n\nconst amountToConvert = computed(() => {\n  const amt = Number(sendAmount.value) || 0\n  return Math.max(0, amt - totalFee.value)\n})\n\nconst recipientGets = computed(() => {\n  return amountToConvert.value * exchangeRate.value\n})\n\n// Bank comparison calculation\nconst bankWireFee = computed(() => 20 * fromCurrencyObj.value.rateToBase)\nconst bankMarkupSpread = 0.032 // 3.2% average hidden bank margin\nconst bankTotalCost = computed(() => {\n  const amt = Number(sendAmount.value) || 0\n  return bankWireFee.value + amt * bankMarkupSpread\n})\n\nconst estimatedSavings = computed(() => {\n  return Math.max(0, bankTotalCost.value - totalFee.value)\n})\n\nfunction formatAmount(val: number, currencyCode: string): string {\n  const isZeroDecimal = currencyCode === 'JPY'\n  return new Intl.NumberFormat('en-US', {\n    minimumFractionDigits: isZeroDecimal ? 0 : 2,\n    maximumFractionDigits: isZeroDecimal ? 0 : 2,\n  }).format(val)\n}\n\nfunction handleSwap() {\n  const temp = fromCurrency.value\n  fromCurrency.value = toCurrency.value\n  toCurrency.value = temp\n}\n\nfunction handleSelectPair(pair: PopularPair) {\n  fromCurrency.value = pair.from\n  toCurrency.value = pair.to\n}\n\nfunction handleRefresh() {\n  if (isRefreshing.value) return\n  isRefreshing.value = true\n  setTimeout(() => {\n    isRefreshing.value = false\n    refreshSuccess.value = true\n    setTimeout(() => {\n      refreshSuccess.value = false\n    }, 2000)\n  }, 450)\n}\n\nfunction handleTransfer() {\n  emit('transfer', {\n    sendAmount: Number(sendAmount.value) || 0,\n    fromCurrency: fromCurrency.value,\n    toCurrency: toCurrency.value,\n    recipientGets: recipientGets.value,\n    fee: totalFee.value,\n    rate: exchangeRate.value,\n  })\n}\n\nfunction getPairRate(fromCode: string, toCode: string): string {\n  const f = CURRENCIES.find((c) => c.code === fromCode)?.rateToBase || 1\n  const t = CURRENCIES.find((c) => c.code === toCode)?.rateToBase || 1\n  const rate = t / f\n  return rate >= 100 ? rate.toFixed(2) : rate.toFixed(4)\n}\n</script>\n\n<template>\n  <div :class=\"cn('mx-auto w-full max-w-2xl space-y-6', props.class)\" data-slot=\"currency-converter-widget\">\n    <!-- Header Section -->\n    <div class=\"space-y-2\">\n      <div class=\"flex flex-wrap items-center justify-between gap-2\">\n        <h2 class=\"text-foreground text-xl font-bold tracking-tight sm:text-2xl\">\n          Currency Converter & International Transfer\n        </h2>\n        <Badge variant=\"outline\" class=\"gap-1.5 py-1 text-xs font-normal\">\n          <span class=\"bg-success size-2 animate-pulse rounded-full\" />\n          Live Market Rates\n        </Badge>\n      </div>\n      <p class=\"text-muted-foreground text-sm\">\n        Real-time mid-market exchange rates with transparent fees. No hidden markups.\n      </p>\n\n      <!-- Refresh & Current Mid-market rate banner -->\n      <div\n        class=\"border-border bg-muted/40 text-muted-foreground flex flex-wrap items-center justify-between gap-2 rounded-lg border px-3.5 py-2 text-xs\"\n      >\n        <div class=\"flex items-center gap-2\">\n          <span class=\"text-foreground font-medium\">\n            Mid-market rate: 1 {{ fromCurrencyObj.code }} = {{ formattedExchangeRate }} {{ toCurrencyObj.code }}\n          </span>\n          <span>Updated 1m ago</span>\n        </div>\n        <button\n          type=\"button\"\n          aria-label=\"Refresh exchange rates\"\n          class=\"text-foreground hover:text-primary focus-visible:ring-ring inline-flex min-h-6 items-center gap-1 rounded px-1.5 py-0.5 font-medium transition-colors focus-visible:ring-2 focus-visible:outline-none\"\n          @click=\"handleRefresh\"\n        >\n          <RefreshCw\n            :class=\"cn('size-3.5 transition-transform duration-500', isRefreshing ? 'text-primary animate-spin' : '')\"\n          />\n          <span>{{ refreshSuccess ? 'Refreshed!' : 'Refresh' }}</span>\n        </button>\n      </div>\n    </div>\n\n    <!-- Main Converter Card -->\n    <Card class=\"border-border shadow-xs\">\n      <CardContent class=\"space-y-4 p-5 sm:p-6\">\n        <!-- Payment method tab pill -->\n        <div class=\"flex items-center justify-between gap-2\">\n          <div class=\"border-border bg-muted/50 inline-flex rounded-lg border p-1 text-xs\">\n            <button\n              type=\"button\"\n              :class=\"\n                cn(\n                  'min-h-6 rounded-md px-3 py-1 font-medium transition-colors',\n                  paymentMethod === 'bank'\n                    ? 'bg-card text-foreground shadow-xs'\n                    : 'text-muted-foreground hover:text-foreground',\n                )\n              \"\n              @click=\"paymentMethod = 'bank'\"\n            >\n              Bank Transfer (Lowest Fee)\n            </button>\n            <button\n              type=\"button\"\n              :class=\"\n                cn(\n                  'min-h-6 rounded-md px-3 py-1 font-medium transition-colors',\n                  paymentMethod === 'card'\n                    ? 'bg-card text-foreground shadow-xs'\n                    : 'text-muted-foreground hover:text-foreground',\n                )\n              \"\n              @click=\"paymentMethod = 'card'\"\n            >\n              Debit / Credit Card\n            </button>\n          </div>\n\n          <span class=\"text-muted-foreground hidden text-xs sm:inline-flex\"> Guaranteed rate for 24h </span>\n        </div>\n\n        <!-- \"You send\" Input Container -->\n        <div\n          class=\"border-input bg-card focus-within:border-ring focus-within:ring-ring/20 rounded-xl border p-3.5 shadow-2xs transition-colors focus-within:ring-2\"\n        >\n          <div class=\"text-muted-foreground mb-1.5 flex items-center justify-between text-xs\">\n            <label for=\"send-amount-input\" class=\"text-foreground font-medium\">You send</label>\n            <span>Max limit: $100,000 / transfer</span>\n          </div>\n\n          <div class=\"flex flex-wrap items-center gap-3\">\n            <div class=\"flex flex-1 items-baseline gap-1\">\n              <span class=\"text-muted-foreground text-xl font-semibold select-none sm:text-2xl\">\n                {{ fromCurrencyObj.symbol }}\n              </span>\n              <input\n                id=\"send-amount-input\"\n                v-model.number=\"sendAmount\"\n                type=\"number\"\n                min=\"1\"\n                step=\"any\"\n                placeholder=\"1,000.00\"\n                class=\"text-foreground placeholder:text-muted-foreground/40 w-full bg-transparent text-2xl font-bold tracking-tight tabular-nums outline-none sm:text-3xl\"\n              />\n            </div>\n\n            <!-- From Currency Selector -->\n            <div class=\"w-36 shrink-0\">\n              <Select v-model=\"fromCurrency\">\n                <SelectTrigger class=\"bg-muted/40 h-11 w-full text-xs font-medium sm:text-sm\">\n                  <div class=\"flex items-center gap-2 text-left\">\n                    <span class=\"text-base leading-none\">{{ fromCurrencyObj.flag }}</span>\n                    <span class=\"font-semibold\">{{ fromCurrencyObj.code }}</span>\n                  </div>\n                </SelectTrigger>\n                <SelectContent class=\"max-h-64\">\n                  <SelectItem v-for=\"curr in CURRENCIES\" :key=\"curr.code\" :value=\"curr.code\">\n                    <div class=\"flex items-center gap-2\">\n                      <span class=\"text-base\">{{ curr.flag }}</span>\n                      <span class=\"font-semibold\">{{ curr.code }}</span>\n                      <span class=\"text-muted-foreground truncate text-xs\">({{ curr.name }})</span>\n                    </div>\n                  </SelectItem>\n                </SelectContent>\n              </Select>\n            </div>\n          </div>\n        </div>\n\n        <!-- Transfer Breakdown Rail (Vertical Connector) -->\n        <div\n          class=\"before:bg-border relative my-1 space-y-3.5 py-2 pl-6 before:absolute before:top-2 before:bottom-2 before:left-2.5 before:w-px\"\n        >\n          <!-- Step 1: Fee -->\n          <div class=\"relative flex items-center justify-between text-xs\">\n            <div\n              class=\"border-border bg-card text-muted-foreground absolute -left-[19px] flex size-3.5 items-center justify-center rounded-full border\"\n            >\n              <Minus class=\"size-2.5\" />\n            </div>\n            <div class=\"flex items-center gap-1.5\">\n              <span class=\"text-foreground font-semibold tabular-nums\">\n                -{{ fromCurrencyObj.symbol }}{{ formatAmount(totalFee, fromCurrencyObj.code) }}\n                {{ fromCurrencyObj.code }}\n              </span>\n              <span class=\"text-muted-foreground\">Transfer fee</span>\n              <Badge variant=\"secondary\" class=\"text-muted-foreground h-4.5 px-1.5 text-xs font-normal\">\n                {{ paymentMethod === 'card' ? '0.65% + $1.20' : '0.35% + $1.20' }}\n              </Badge>\n            </div>\n            <span class=\"text-muted-foreground hidden sm:inline\">Transparent fixed rate</span>\n          </div>\n\n          <!-- Step 2: Amount to convert -->\n          <div class=\"relative flex items-center justify-between text-xs\">\n            <div\n              class=\"border-border bg-card text-muted-foreground absolute -left-[19px] flex size-3.5 items-center justify-center rounded-full border\"\n            >\n              <span class=\"text-xs leading-none font-bold\">=</span>\n            </div>\n            <div class=\"flex items-center gap-1.5\">\n              <span class=\"text-foreground font-semibold tabular-nums\">\n                {{ fromCurrencyObj.symbol }}{{ formatAmount(amountToConvert, fromCurrencyObj.code) }}\n                {{ fromCurrencyObj.code }}\n              </span>\n              <span class=\"text-muted-foreground\">Amount to convert</span>\n            </div>\n            <span class=\"text-muted-foreground hidden sm:inline\">Net transfer base</span>\n          </div>\n\n          <!-- Step 3: Guaranteed Exchange Rate & Swap Button Line -->\n          <div class=\"relative flex flex-wrap items-center justify-between gap-2 text-xs\">\n            <div\n              class=\"border-primary/50 bg-primary text-primary-foreground absolute -left-[19px] flex size-3.5 items-center justify-center rounded-full border\"\n            >\n              <Lock class=\"size-2\" />\n            </div>\n            <div class=\"flex flex-wrap items-center gap-2\">\n              <span class=\"text-foreground font-semibold tabular-nums\"> × {{ formattedExchangeRate }} </span>\n              <span class=\"text-muted-foreground\">Guaranteed mid-market rate</span>\n              <Badge variant=\"outline\" class=\"border-success/30 bg-success/10 text-success gap-1 py-0.5 text-xs\">\n                <Lock class=\"size-2.5\" />\n                24h Guarantee\n              </Badge>\n            </div>\n\n            <!-- Swap Currencies Button -->\n            <button\n              type=\"button\"\n              aria-label=\"Swap currencies\"\n              class=\"border-border bg-card text-foreground hover:bg-accent hover:border-primary/50 focus-visible:ring-ring inline-flex min-h-6 items-center gap-1.5 rounded-full border px-2.5 py-1 text-xs font-medium shadow-2xs transition-[background-color,border-color,box-shadow,scale] focus-visible:ring-2 focus-visible:outline-none active:scale-95\"\n              @click=\"handleSwap\"\n            >\n              <ArrowUpDown class=\"text-primary size-3\" />\n              <span>Swap</span>\n            </button>\n          </div>\n        </div>\n\n        <!-- \"Recipient gets\" Input / Output Container -->\n        <div\n          class=\"border-input bg-card focus-within:border-ring focus-within:ring-ring/20 rounded-xl border p-3.5 shadow-2xs transition-colors focus-within:ring-2\"\n        >\n          <div class=\"text-muted-foreground mb-1.5 flex items-center justify-between text-xs\">\n            <label class=\"text-foreground font-medium\">Recipient gets</label>\n            <span class=\"text-success flex items-center gap-1 font-medium\">\n              <Zap class=\"size-3\" />\n              {{ toCurrencyObj.deliverySpeed }}\n            </span>\n          </div>\n\n          <div class=\"flex flex-wrap items-center gap-3\">\n            <div class=\"flex min-w-0 flex-1 items-baseline gap-1\">\n              <span class=\"text-muted-foreground text-xl font-semibold select-none sm:text-2xl\">\n                {{ toCurrencyObj.symbol }}\n              </span>\n              <div\n                class=\"text-foreground w-full truncate text-2xl font-bold tracking-tight tabular-nums select-all sm:text-3xl\"\n              >\n                {{ formatAmount(recipientGets, toCurrencyObj.code) }}\n              </div>\n            </div>\n\n            <!-- To Currency Selector -->\n            <div class=\"w-36 shrink-0\">\n              <Select v-model=\"toCurrency\">\n                <SelectTrigger class=\"bg-muted/40 h-11 w-full text-xs font-medium sm:text-sm\">\n                  <div class=\"flex items-center gap-2 text-left\">\n                    <span class=\"text-base leading-none\">{{ toCurrencyObj.flag }}</span>\n                    <span class=\"font-semibold\">{{ toCurrencyObj.code }}</span>\n                  </div>\n                </SelectTrigger>\n                <SelectContent class=\"max-h-64\">\n                  <SelectItem v-for=\"curr in CURRENCIES\" :key=\"curr.code\" :value=\"curr.code\">\n                    <div class=\"flex items-center gap-2\">\n                      <span class=\"text-base\">{{ curr.flag }}</span>\n                      <span class=\"font-semibold\">{{ curr.code }}</span>\n                      <span class=\"text-muted-foreground truncate text-xs\">({{ curr.name }})</span>\n                    </div>\n                  </SelectItem>\n                </SelectContent>\n              </Select>\n            </div>\n          </div>\n        </div>\n\n        <!-- Delivery Speed & Savings Breakdown Banner -->\n        <div class=\"border-border bg-muted/30 space-y-3 rounded-lg border p-4\">\n          <div class=\"flex flex-wrap items-center justify-between gap-2\">\n            <div class=\"flex items-center gap-2 text-xs\">\n              <span class=\"bg-primary/10 text-primary flex size-6 items-center justify-center rounded-full\">\n                <Zap class=\"size-3.5\" />\n              </span>\n              <div>\n                <p class=\"text-foreground font-semibold\">Estimated delivery: {{ toCurrencyObj.deliverySpeed }}</p>\n                <p class=\"text-muted-foreground\">Via {{ toCurrencyObj.deliveryNetwork }}</p>\n              </div>\n            </div>\n\n            <Badge variant=\"outline\" class=\"border-warning/30 bg-warning/10 text-warning gap-1 py-1 text-xs\">\n              <Coins class=\"size-3\" />\n              Save ~{{ fromCurrencyObj.symbol }}{{ formatAmount(estimatedSavings, fromCurrencyObj.code) }}\n              {{ fromCurrencyObj.code }}\n            </Badge>\n          </div>\n\n          <Separator />\n\n          <!-- Comparison vs Standard High-Street Bank -->\n          <div class=\"grid grid-cols-1 gap-3 text-xs sm:grid-cols-2\">\n            <div class=\"bg-card/60 border-border flex items-start gap-2 rounded-md border p-2.5\">\n              <ShieldCheck class=\"text-success mt-0.5 size-4 shrink-0\" />\n              <div>\n                <p class=\"text-foreground font-medium\">UIPKGE Transfer</p>\n                <p class=\"text-muted-foreground text-xs\">\n                  Fee: {{ fromCurrencyObj.symbol }}{{ formatAmount(totalFee, fromCurrencyObj.code) }} · 0% exchange\n                  spread\n                </p>\n              </div>\n            </div>\n\n            <div class=\"bg-card/60 border-border flex items-start gap-2 rounded-md border p-2.5 opacity-75\">\n              <Building2 class=\"text-muted-foreground mt-0.5 size-4 shrink-0\" />\n              <div>\n                <p class=\"text-foreground font-medium\">Standard Bank Wire</p>\n                <p class=\"text-muted-foreground text-xs\">\n                  Fee: ~{{ fromCurrencyObj.symbol }}{{ formatAmount(bankTotalCost, fromCurrencyObj.code) }} · ~3.2%\n                  hidden spread\n                </p>\n              </div>\n            </div>\n          </div>\n        </div>\n\n        <!-- Primary Action Button -->\n        <Button class=\"h-11 w-full gap-2 text-base font-semibold shadow-sm\" @click=\"handleTransfer\">\n          <span\n            >Get Started / Send {{ fromCurrencyObj.symbol\n            }}{{ formatAmount(sendAmount || 0, fromCurrencyObj.code) }}</span\n          >\n          <ArrowRight class=\"size-4\" />\n        </Button>\n\n        <p class=\"text-muted-foreground flex items-center justify-center gap-1.5 text-center text-xs\">\n          <Lock class=\"text-muted-foreground size-3\" />\n          <span>Rates locked for 24 hours. Licensed & regulated financial institution.</span>\n        </p>\n      </CardContent>\n    </Card>\n\n    <!-- Popular Currency Pairs Quick Rate Ticker -->\n    <div class=\"space-y-3\">\n      <div class=\"flex items-center justify-between\">\n        <h3 class=\"text-foreground text-sm font-semibold\">Popular Currency Pairs</h3>\n        <span class=\"text-muted-foreground text-xs\">Click pair to load</span>\n      </div>\n\n      <div class=\"grid grid-cols-2 gap-2.5 sm:grid-cols-3\">\n        <button\n          v-for=\"pair in POPULAR_PAIRS\"\n          :key=\"pair.id\"\n          type=\"button\"\n          :class=\"\n            cn(\n              'hover:bg-accent focus-visible:ring-ring flex flex-col items-start gap-1 rounded-lg border p-3 text-left transition-colors focus-visible:ring-2 focus-visible:outline-none',\n              fromCurrency === pair.from && toCurrency === pair.to\n                ? 'border-primary bg-primary/5 ring-primary/20 ring-1'\n                : 'border-border bg-card',\n            )\n          \"\n          @click=\"handleSelectPair(pair)\"\n        >\n          <div class=\"flex w-full items-center justify-between text-xs\">\n            <span class=\"text-foreground font-semibold\">{{ pair.from }} / {{ pair.to }}</span>\n            <span\n              :class=\"\n                cn('flex items-center text-xs font-medium', pair.trend === 'up' ? 'text-success' : 'text-destructive')\n              \"\n            >\n              <ArrowUpRight v-if=\"pair.trend === 'up'\" class=\"size-3\" />\n              <ArrowDownRight v-else class=\"size-3\" />\n              {{ pair.change24h > 0 ? `+${pair.change24h}%` : `${pair.change24h}%` }}\n            </span>\n          </div>\n\n          <div class=\"text-foreground text-sm font-bold tabular-nums\">\n            {{ getPairRate(pair.from, pair.to) }}\n          </div>\n        </button>\n      </div>\n    </div>\n  </div>\n</template>\n",
      "type": "registry:block",
      "target": "~/app/components/blocks/CurrencyConverterWidget.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/select.json",
    "https://uipkge.dev/r/vue/separator.json"
  ],
  "description": "Wise and Revolut-style real-time multi-currency exchange calculator and transfer fee estimator with live mid-market rates, transparent fee breakdown rail, bank savings comparison, and quick-rate ticker.",
  "categories": [
    "finance",
    "fintech",
    "billing",
    "commerce"
  ]
}