{
  "$schema": "https://uipkge.dev/schema/registry-item.json",
  "name": "payment-card",
  "title": "Payment Card",
  "type": "registry:ui",
  "files": [
    {
      "path": "packages/registry-angular/components/payment-card/payment-card.component.ts",
      "content": "import { Component, ElementRef, Input, booleanAttribute, inject, ChangeDetectionStrategy } from '@angular/core'\nimport { cn } from '@/lib/utils'\n\nexport type CardBrand = 'visa' | 'mastercard' | 'amex' | 'discover' | 'unknown'\nexport type PaymentCardSize = 'sm' | 'md' | 'lg'\nexport type PaymentCardVariant = 'default' | 'compact'\n\nconst SIZE_CLASSES: Record<PaymentCardSize, string> = {\n  sm: 'text-xs w-[280px]',\n  md: 'max-w-sm text-sm w-[360px]',\n  lg: 'max-w-md text-base w-[420px]',\n}\n\ninterface BrandVisual {\n  cardClass: string\n  accentGlow: string\n  foilSheen: string\n  guillocheColor: string\n  textColor: string\n  subtextColor: string\n  embossStyle: string\n  chipType: 'gold' | 'silver'\n}\n\nconst BRAND_VISUALS: Record<CardBrand, BrandVisual> = {\n  visa: {\n    cardClass:\n      'bg-[radial-gradient(ellipse_at_top_right,#1e3a8a_0%,#0f2252_45%,#08122c_85%,#040a18_100%)] text-white shadow-[0_22px_45px_-12px_rgba(15,34,82,0.65),0_8px_16px_-8px_rgba(0,0,0,0.5)]',\n    accentGlow: 'from-blue-400/20 via-indigo-500/10 to-transparent',\n    foilSheen: 'from-white/20 via-blue-200/5 to-transparent',\n    guillocheColor: 'rgba(96, 165, 250, 0.12)',\n    textColor: 'text-white',\n    subtextColor: 'text-blue-200/60',\n    embossStyle: 'text-white drop-shadow-[0_1px_1px_rgba(0,0,0,0.8)]',\n    chipType: 'gold',\n  },\n  mastercard: {\n    cardClass:\n      'bg-[radial-gradient(ellipse_at_top_right,#2a0808_0%,#180608_35%,#0f0506_70%,#09090b_100%)] text-white shadow-[0_22px_45px_-12px_rgba(220,38,38,0.35),0_8px_16px_-8px_rgba(0,0,0,0.6)]',\n    accentGlow: 'from-red-500/25 via-amber-500/15 to-transparent',\n    foilSheen: 'from-white/20 via-orange-300/10 to-transparent',\n    guillocheColor: 'rgba(239, 68, 68, 0.1)',\n    textColor: 'text-white',\n    subtextColor: 'text-zinc-400',\n    embossStyle: 'text-zinc-100 drop-shadow-[0_1px_2px_rgba(0,0,0,0.9)]',\n    chipType: 'gold',\n  },\n  amex: {\n    cardClass:\n      'bg-[radial-gradient(ellipse_at_top_right,#1e293b_0%,#0f172a_40%,#090d16_80%,#020617_100%)] text-slate-100 shadow-[0_22px_45px_-12px_rgba(15,23,42,0.7),0_8px_16px_-8px_rgba(0,0,0,0.6)]',\n    accentGlow: 'from-slate-300/20 via-teal-500/10 to-transparent',\n    foilSheen: 'from-white/25 via-cyan-100/10 to-transparent',\n    guillocheColor: 'rgba(148, 163, 184, 0.12)',\n    textColor: 'text-slate-100',\n    subtextColor: 'text-slate-400',\n    embossStyle: 'text-slate-100 drop-shadow-[0_1px_2px_rgba(0,0,0,0.9)]',\n    chipType: 'silver',\n  },\n  discover: {\n    cardClass:\n      'bg-[radial-gradient(ellipse_at_top_right,#431407_0%,#270d04_45%,#1c0903_80%,#0c0401_100%)] text-white shadow-[0_22px_45px_-12px_rgba(194,65,12,0.45),0_8px_16px_-8px_rgba(0,0,0,0.6)]',\n    accentGlow: 'from-orange-400/25 via-amber-600/15 to-transparent',\n    foilSheen: 'from-white/20 via-amber-200/10 to-transparent',\n    guillocheColor: 'rgba(251, 146, 60, 0.12)',\n    textColor: 'text-white',\n    subtextColor: 'text-amber-200/60',\n    embossStyle: 'text-white drop-shadow-[0_1px_2px_rgba(0,0,0,0.9)]',\n    chipType: 'gold',\n  },\n  unknown: {\n    cardClass:\n      'bg-[radial-gradient(ellipse_at_top_right,#27272a_0%,#18181b_40%,#09090b_85%,#000000_100%)] text-white shadow-[0_22px_45px_-12px_rgba(0,0,0,0.7),0_8px_16px_-8px_rgba(0,0,0,0.5)]',\n    accentGlow: 'from-zinc-400/15 via-zinc-600/10 to-transparent',\n    foilSheen: 'from-white/18 via-zinc-300/5 to-transparent',\n    guillocheColor: 'rgba(255, 255, 255, 0.06)',\n    textColor: 'text-white',\n    subtextColor: 'text-zinc-400',\n    embossStyle: 'text-zinc-100 drop-shadow-[0_1px_2px_rgba(0,0,0,0.9)]',\n    chipType: 'silver',\n  },\n}\n\n@Component({\n  changeDetection: ChangeDetectionStrategy.Eager,\n  selector: 'ui-payment-card, [ui-payment-card]',\n  standalone: true,\n  host: {\n    '[attr.data-slot]': '\"payment-card\"',\n    '[attr.data-uipkge]': '\"\"',\n    '[attr.data-brand]': 'detectedBrand',\n    '[attr.data-flipped]': 'isFlipped || undefined',\n    role: 'img',\n    '[attr.aria-label]': 'ariaLabel',\n    '[class]': 'hostClass',\n    '(mousemove)': 'onMove($event)',\n    '(mouseleave)': 'onLeave()',\n  },\n  template: `\n    <div data-uipkge data-slot=\"payment-card-inner\" [class]=\"innerClass\" [style.transform]=\"innerTransform\">\n      <!-- ==================== FRONT FACE ==================== -->\n      <div data-uipkge data-slot=\"payment-card-front\" [class]=\"frontFaceClass\">\n        <!-- Fine Guilloche pattern -->\n        <svg\n          class=\"pointer-events-none absolute inset-0 size-full opacity-60 mix-blend-screen\"\n          xmlns=\"http://www.w3.org/2000/svg\"\n          viewBox=\"0 0 360 227\"\n          fill=\"none\"\n          aria-hidden=\"true\"\n        >\n          <g [attr.stroke]=\"theme.guillocheColor\" stroke-width=\"0.75\" stroke-opacity=\"0.7\">\n            <path d=\"M-40 40 C 60 180, 180 -40, 400 120\" />\n            <path d=\"M-40 55 C 60 195, 180 -25, 400 135\" />\n            <path d=\"M-40 70 C 60 210, 180 -10, 400 150\" />\n            <path d=\"M-40 85 C 60 225, 180 5, 400 165\" />\n            <path d=\"M-40 100 C 60 240, 180 20, 400 180\" />\n            <path d=\"M-40 115 C 60 255, 180 35, 400 195\" />\n            <circle cx=\"280\" cy=\"80\" r=\"90\" stroke-width=\"0.5\" stroke-dasharray=\"2 3\" />\n            <circle cx=\"280\" cy=\"80\" r=\"60\" stroke-width=\"0.5\" stroke-dasharray=\"1 2\" />\n          </g>\n        </svg>\n\n        <!-- Brushed metallic sheen & specular lighting -->\n        <div\n          class=\"pointer-events-none absolute inset-0 bg-gradient-to-tr from-transparent via-white/[0.07] to-transparent opacity-80\"\n        ></div>\n        <div\n          class=\"pointer-events-none absolute -inset-y-8 -left-1/3 w-1/2 rotate-12 bg-gradient-to-r opacity-70\"\n          [class]=\"theme.foilSheen\"\n        ></div>\n        <div\n          class=\"pointer-events-none absolute -top-12 -right-12 h-44 w-44 rounded-full bg-gradient-to-br blur-2xl\"\n          [class]=\"theme.accentGlow\"\n        ></div>\n        <div class=\"pointer-events-none absolute -bottom-10 -left-10 h-36 w-36 rounded-full bg-black/40 blur-2xl\"></div>\n\n        <!-- Outer bevel perimeter ring -->\n        <div\n          class=\"pointer-events-none absolute inset-0 rounded-[16px] shadow-[inset_0_1px_1px_rgba(255,255,255,0.35),inset_0_-1px_1px_rgba(0,0,0,0.5)]\"\n        ></div>\n\n        <!-- Shimmer sweep -->\n        @if (shimmer) {\n          <div\n            class=\"pointer-events-none absolute -inset-x-full inset-y-0 bg-gradient-to-r from-transparent via-white/25 to-transparent\"\n            style=\"animation: payment-card-shimmer 2.5s linear infinite\"\n          ></div>\n        }\n\n        <!-- Content structure -->\n        <div [class]=\"contentClass\">\n          <!-- TOP ROW: Tier / Brand Logo -->\n          <div class=\"flex items-center justify-between\">\n            <div class=\"flex items-center gap-1.5\">\n              @if (variant !== 'compact') {\n                <span class=\"font-mono text-xs font-semibold tracking-[0.25em] text-white/70 uppercase\">\n                  {{ tierLabel }}\n                </span>\n              } @else {\n                <span class=\"font-mono text-xs font-bold tracking-widest text-white/70 uppercase\">CARD</span>\n              }\n            </div>\n\n            <!-- Brand Logo -->\n            <div class=\"flex items-center justify-end\" style=\"perspective: 600px\">\n              @if (detectedBrand === 'visa') {\n                <div class=\"flex items-center\">\n                  <svg\n                    [class]=\"variant === 'compact' ? 'h-3 w-auto' : 'h-6 w-auto'\"\n                    viewBox=\"0 0 78 24\"\n                    fill=\"none\"\n                    xmlns=\"http://www.w3.org/2000/svg\"\n                    aria-label=\"Visa\"\n                  >\n                    <path\n                      d=\"M29.5 23.2H23.9L27.4 1.8H33L29.5 23.2ZM52.4 2.3C51.3 1.9 49.5 1.5 47.3 1.5C41.8 1.5 37.9 4.4 37.8 8.6C37.7 11.7 40.5 13.4 42.6 14.4C44.8 15.5 45.5 16.2 45.5 17.1C45.5 18.6 43.7 19.2 42.1 19.2C39.8 19.2 38.5 18.9 36.8 18.1L36 17.7L35.1 23C36.6 23.7 39.2 24.2 41.8 24.2C47.7 24.2 51.5 21.3 51.6 16.9C51.7 13.4 49.6 11.7 47 10.4C45.2 9.5 44.1 8.9 44.1 8C44.1 7.2 45 6.4 46.8 6.4C48.3 6.4 49.6 6.7 50.8 7.2L51.3 7.5L52.4 2.3ZM67.5 1.8H63.2C61.8 1.8 60.8 2.2 60.2 3.6L51.4 23.2H57.3L58.5 19.9H65.7L66.4 23.2H71.6L67.5 1.8ZM60.1 15.5C60.6 14.2 62.5 8.9 62.5 8.9C62.5 8.9 63 7.6 63.3 6.7L63.8 8.7C63.8 8.7 64.9 14.1 65.2 15.5H60.1ZM18.7 1.8L13.2 16.4L12.6 13.4C11.6 10 8.7 6.3 5.4 4.5L10.3 23.2H16.3L25.1 1.8H18.7ZM8.3 1.8H0.2L0 2.3C6.3 3.9 10.4 7.7 12.1 12.4L10.4 3.7C10.1 2.4 9.3 1.9 8.3 1.8Z\"\n                      fill=\"white\"\n                    />\n                    <path\n                      d=\"M12.1 12.4L10.4 3.7C10.1 2.4 9.3 1.9 8.3 1.8H0.2L0 2.3C6.3 3.9 10.4 7.7 12.1 12.4Z\"\n                      fill=\"#F9A01B\"\n                    />\n                  </svg>\n                </div>\n              } @else if (detectedBrand === 'mastercard') {\n                <div class=\"flex items-center gap-1.5\">\n                  <svg\n                    [class]=\"variant === 'compact' ? 'h-3.5 w-auto' : 'h-7 w-auto'\"\n                    viewBox=\"0 0 48 30\"\n                    fill=\"none\"\n                    xmlns=\"http://www.w3.org/2000/svg\"\n                    aria-label=\"Mastercard\"\n                  >\n                    <circle cx=\"15\" cy=\"15\" r=\"15\" fill=\"#EB001B\" />\n                    <circle cx=\"33\" cy=\"15\" r=\"15\" fill=\"#F79E1B\" fill-opacity=\"0.92\" />\n                    <path\n                      d=\"M24 4.5C27.5 7.1 29.8 11.2 29.8 16C29.8 20.8 27.5 24.9 24 27.5C20.5 24.9 18.2 20.8 18.2 16C18.2 11.2 20.5 7.1 24 4.5Z\"\n                      fill=\"#FF5F00\"\n                    />\n                  </svg>\n                  @if (variant !== 'compact') {\n                    <span\n                      class=\"font-mono text-xs font-bold tracking-tight text-white lowercase\"\n                      style=\"letter-spacing: -0.05em\"\n                    >\n                      mastercard\n                    </span>\n                  }\n                </div>\n              } @else if (detectedBrand === 'amex') {\n                <div class=\"flex items-center\">\n                  <div [class]=\"amexClass\">AMEX</div>\n                </div>\n              } @else if (detectedBrand === 'discover') {\n                <div class=\"flex items-center gap-0.5 text-xs font-bold tracking-wider text-white\">\n                  <span>DISC</span>\n                  <span\n                    class=\"inline-block rounded-full bg-gradient-to-br from-amber-400 to-orange-600 shadow-xs\"\n                    [class]=\"variant === 'compact' ? 'size-2' : 'size-3.5'\"\n                  ></span>\n                  <span>VER</span>\n                </div>\n              } @else {\n                <div class=\"flex items-center gap-1 opacity-80\">\n                  <div class=\"size-2 rounded-full bg-white/60\"></div>\n                  <div class=\"size-2 rounded-full bg-white/30\"></div>\n                  <span class=\"font-mono text-xs font-bold tracking-widest text-white/80 uppercase\"> PREMIUM </span>\n                </div>\n              }\n            </div>\n          </div>\n\n          <!-- MIDDLE ROW: EMV Chip + Contactless Symbol -->\n          <div class=\"flex items-center justify-between\">\n            <div class=\"flex items-center gap-3\">\n              <!-- Ultra-Realistic Metallic EMV Chip -->\n              <div [class]=\"chipClass\">\n                <div class=\"absolute inset-[2px] rounded-[3px] border border-black/25\"></div>\n                <div class=\"absolute inset-x-0 top-1/2 h-px -translate-y-1/2 bg-black/30\"></div>\n                <div class=\"absolute inset-y-0 left-1/3 w-px bg-black/30\"></div>\n                <div class=\"absolute inset-y-0 right-1/3 w-px bg-black/30\"></div>\n                <div\n                  class=\"absolute top-1/4 right-1/3 left-1/3 h-1/2 rounded-[2px] border border-black/25 bg-black/10\"\n                ></div>\n                <div\n                  class=\"pointer-events-none absolute inset-0 bg-gradient-to-tr from-transparent via-white/40 to-transparent\"\n                ></div>\n              </div>\n\n              <!-- Contactless NFC Radio Waves -->\n              @if (variant !== 'compact') {\n                <svg\n                  viewBox=\"0 0 24 24\"\n                  class=\"h-5 w-auto text-white/70 drop-shadow-sm\"\n                  fill=\"none\"\n                  stroke=\"currentColor\"\n                  stroke-width=\"1.75\"\n                  stroke-linecap=\"round\"\n                  aria-hidden=\"true\"\n                >\n                  <path d=\"M6.5 8a6 6 0 0 1 0 8\" />\n                  <path d=\"M10 6a9.5 9.5 0 0 1 0 12\" />\n                  <path d=\"M13.5 4a13 13 0 0 1 0 16\" />\n                </svg>\n              }\n            </div>\n\n            <!-- Holographic Security Stamp -->\n            @if (variant !== 'compact') {\n              <div class=\"pay-card-holo h-7 w-9 rounded-[4px] opacity-75 shadow-xs\"></div>\n            }\n          </div>\n\n          <!-- CARD NUMBER (Authentic Embossed Raised Digits) -->\n          <div [class]=\"numberContainerClass\">\n            <span class=\"sr-only\" data-uipkge data-slot=\"payment-card-number\">{{ displayNumber }}</span>\n            @for (ch of displayChars; track $index) {\n              <!-- Not [class.text-[0.85em]]: Angular can't parse brackets in a class-binding name and\n                   emitted the class \"text-[0\", so placeholder dots rendered full size. -->\n              <span\n                class=\"inline-block origin-bottom tabular-nums transition-transform\"\n                [class]=\"ch === '•' ? 'text-[0.85em] opacity-50' : ''\"\n                aria-hidden=\"true\"\n                >{{ ch === ' ' ? '\\u00a0' : ch }}</span\n              >\n            }\n          </div>\n\n          <!-- BOTTOM ROW: Cardholder Name + Expiry Date -->\n          <div class=\"flex items-end justify-between gap-3\">\n            <div class=\"min-w-0 flex-1\">\n              @if (variant !== 'compact') {\n                <div class=\"text-xs font-semibold tracking-[0.2em] uppercase\" [class]=\"theme.subtextColor\">\n                  CARDHOLDER NAME\n                </div>\n              }\n              <div data-uipkge data-slot=\"payment-card-name\" [class]=\"nameClass\">\n                {{ displayName }}\n              </div>\n            </div>\n\n            <div class=\"shrink-0 text-right\">\n              @if (variant !== 'compact') {\n                <div\n                  class=\"flex items-center justify-end gap-1 text-xs font-semibold tracking-wider uppercase\"\n                  [class]=\"theme.subtextColor\"\n                >\n                  <span class=\"text-[6px] leading-tight\">GOOD<br />THRU</span>\n                  <span>MONTH/YEAR</span>\n                </div>\n              }\n              <div data-uipkge data-slot=\"payment-card-expiry\" [class]=\"expiryClass\">\n                {{ displayExpiry }}\n              </div>\n            </div>\n          </div>\n        </div>\n      </div>\n\n      <!-- ==================== BACK FACE ==================== -->\n      @if (flip) {\n        <div data-uipkge data-slot=\"payment-card-back\" [class]=\"backFaceClass\">\n          <div\n            class=\"pointer-events-none absolute inset-0 rounded-[16px] shadow-[inset_0_1px_1px_rgba(255,255,255,0.35),inset_0_-1px_1px_rgba(0,0,0,0.5)]\"\n          ></div>\n\n          <!-- Magnetic Stripe -->\n          <div [class]=\"magneticStripeClass\"></div>\n\n          <div [class]=\"backContentClass\">\n            <!-- Signature Panel + CVV Code -->\n            <div [class]=\"signatureRowClass\">\n              <div\n                [class]=\"signatureStripClass\"\n                style=\"background-image: repeating-linear-gradient(-45deg, rgba(0, 0, 0, 0.05) 0px, rgba(0, 0, 0, 0.05) 2px, transparent 2px, transparent 6px);\"\n              >\n                @if (variant !== 'compact') {\n                  <div class=\"font-mono text-xs font-semibold tracking-wider text-slate-400 uppercase\">\n                    AUTHORIZED SIGNATURE\n                  </div>\n                }\n              </div>\n\n              <div [class]=\"cvcBoxClass\">\n                @if (variant !== 'compact') {\n                  <span class=\"text-[6px] font-bold tracking-widest text-slate-400 uppercase\">CVV</span>\n                }\n                <span data-uipkge data-slot=\"payment-card-cvc\" class=\"leading-none tracking-widest italic\">{{\n                  displayCvc\n                }}</span>\n              </div>\n            </div>\n\n            <!-- Microtext Disclaimer -->\n            @if (variant !== 'compact') {\n              <div class=\"mt-3 space-y-1.5\">\n                <p class=\"text-[7.5px] leading-snug text-white/50\">\n                  This card is property of the issuing bank and must be returned upon request. Use is subject to the\n                  cardholder agreement.\n                </p>\n                <div\n                  class=\"flex items-center justify-between border-t border-white/10 pt-2 text-xs font-medium text-white/60\"\n                >\n                  <span>24/7 Support: 1-800-555-0199</span>\n                  <span class=\"font-mono font-bold tracking-wider text-white/75\">CIRRUS · PLUS · STAR</span>\n                </div>\n              </div>\n            }\n          </div>\n        </div>\n      }\n    </div>\n    <ng-content />\n  `,\n  styles: `\n    @keyframes payment-card-shimmer {\n      0% {\n        transform: translateX(-100%);\n      }\n      100% {\n        transform: translateX(200%);\n      }\n    }\n  `,\n})\nexport class UiPaymentCardComponent {\n  @Input() number = ''\n  @Input() name = ''\n  @Input() expiry = ''\n  @Input() cvc = ''\n  @Input() brand: CardBrand | 'auto' = 'auto'\n  @Input({ transform: booleanAttribute }) flipped = false\n  @Input() variant: PaymentCardVariant = 'default'\n  @Input({ transform: booleanAttribute }) tilt = false\n  @Input({ transform: booleanAttribute }) shimmer = false\n  @Input({ transform: booleanAttribute }) flip = true\n  @Input() size: PaymentCardSize = 'md'\n  @Input('class') className?: string\n\n  tiltX = 0\n  tiltY = 0\n  isHovering = false\n  private readonly el: ElementRef<HTMLElement> | null = null\n\n  constructor() {\n    try {\n      this.el = inject<ElementRef<HTMLElement>>(ElementRef, { optional: true })\n    } catch {}\n  }\n\n  onMove(e: MouseEvent): void {\n    if (!this.tilt || !this.el) return\n    const rect = this.el.nativeElement.getBoundingClientRect()\n    const x = e.clientX - rect.left\n    const y = e.clientY - rect.top\n    const px = (x / rect.width - 0.5) * 2\n    const py = (y / rect.height - 0.5) * 2\n    this.tiltX = -py * 10\n    this.tiltY = px * 12\n    this.isHovering = true\n  }\n\n  onLeave(): void {\n    if (!this.tilt) return\n    this.tiltX = 0\n    this.tiltY = 0\n    this.isHovering = false\n  }\n\n  get innerTransform(): string {\n    const flipDeg = this.isFlipped ? 180 : 0\n    if (this.tilt && this.isHovering) {\n      return `perspective(1200px) rotateX(${this.tiltX}deg) rotateY(${this.tiltY + flipDeg}deg) scale3d(1.02, 1.02, 1.02)`\n    }\n    return `perspective(1200px) rotateY(${flipDeg}deg)`\n  }\n\n  get detectedBrand(): CardBrand {\n    if (this.brand && this.brand !== 'auto') return this.brand\n    return UiPaymentCardComponent.detectBrand(this.number)\n  }\n\n  static detectBrand(raw: string): CardBrand {\n    const n = (raw ?? '').replace(/\\D/g, '')\n    if (!n) return 'unknown'\n    if (/^4/.test(n)) return 'visa'\n    if (/^(5[1-5]|2[2-7])/.test(n)) return 'mastercard'\n    if (/^3[47]/.test(n)) return 'amex'\n    if (/^(6011|65|64[4-9])/.test(n)) return 'discover'\n    return 'unknown'\n  }\n\n  get displayNumber(): string {\n    return UiPaymentCardComponent.formatMasked(this.number, this.detectedBrand)\n  }\n\n  static formatMasked(raw: string, brand: CardBrand): string {\n    const digits = (raw ?? '').replace(/\\D/g, '').slice(0, brand === 'amex' ? 15 : 16)\n    const groups = brand === 'amex' ? [4, 6, 5] : [4, 4, 4, 4]\n    const total = groups.reduce((a, b) => a + b, 0)\n    const padded = (digits + '••••••••••••••••').slice(0, total)\n    let i = 0\n    return groups\n      .map((g) => {\n        const slice = padded.slice(i, i + g)\n        i += g\n        return slice\n      })\n      .join(' ')\n  }\n\n  get displayChars(): string[] {\n    return this.displayNumber.split('')\n  }\n\n  get displayName(): string {\n    return (this.name.trim() || 'CARDHOLDER NAME').toUpperCase()\n  }\n\n  get displayExpiry(): string {\n    const raw = (this.expiry ?? '').replace(/\\D/g, '').slice(0, 4)\n    if (!raw) return 'MM/YY'\n    if (raw.length <= 2) return `${raw}/YY`\n    return `${raw.slice(0, 2)}/${raw.slice(2, 4)}`\n  }\n\n  get displayCvc(): string {\n    const max = this.detectedBrand === 'amex' ? 4 : 3\n    const digits = (this.cvc ?? '').replace(/\\D/g, '').slice(0, max)\n    return digits || '•••'\n  }\n\n  get isFlipped(): boolean {\n    return this.flipped\n  }\n\n  get theme(): BrandVisual {\n    return BRAND_VISUALS[this.detectedBrand]\n  }\n\n  get tierLabel(): string {\n    if (this.detectedBrand === 'amex') return 'PLATINUM'\n    if (this.detectedBrand === 'mastercard') return 'WORLD ELITE'\n    return 'SIGNATURE'\n  }\n\n  get hostClass(): string {\n    return cn(\n      'group relative inline-block select-none [perspective:1200px]',\n      SIZE_CLASSES[this.size],\n      this.variant === 'compact' && 'w-[120px] max-w-56',\n      this.className,\n    )\n  }\n\n  get innerClass(): string {\n    return cn(\n      'relative aspect-[85.6/53.98] w-full transition-transform [transform-style:preserve-3d]',\n      this.flip ? 'duration-[650ms] ease-[cubic-bezier(0.22,1,0.36,1)]' : 'duration-300',\n      this.isFlipped && '[transform:rotateY(180deg)]',\n    )\n  }\n\n  get faceClass(): string {\n    return cn(\n      'absolute inset-0 flex flex-col justify-between overflow-hidden rounded-xl p-5',\n      this.shimmer && 'payment-card-shimmer',\n      this.tilt && 'payment-card-tilt',\n    )\n  }\n\n  get frontFaceClass(): string {\n    return cn(\n      'pay-card-face absolute inset-0 overflow-hidden rounded-[16px] border border-white/15 [backface-visibility:hidden]',\n      this.theme.cardClass,\n    )\n  }\n\n  get backFaceClass(): string {\n    return cn(\n      'pay-card-face absolute inset-0 [transform:rotateY(180deg)] overflow-hidden rounded-[16px] border border-white/15 [backface-visibility:hidden]',\n      this.theme.cardClass,\n    )\n  }\n\n  get contentClass(): string {\n    return cn('absolute inset-0 flex flex-col justify-between', this.variant === 'compact' ? 'p-2' : 'p-5')\n  }\n\n  get amexClass(): string {\n    return cn(\n      'flex items-center justify-center rounded-sm bg-[#006fcf] font-sans font-bold tracking-tighter text-white shadow-xs',\n      this.variant === 'compact' ? 'px-1 py-0.5 text-xs' : 'px-2 py-1 text-xs',\n    )\n  }\n\n  get chipClass(): string {\n    return cn(\n      'relative overflow-hidden rounded-[5px] border border-amber-950/40 shadow-[0_2px_5px_rgba(0,0,0,0.5),inset_0_1px_0_rgba(255,255,255,0.6)]',\n      this.theme.chipType === 'silver'\n        ? 'bg-gradient-to-br from-slate-200 via-slate-300 to-slate-400'\n        : 'bg-gradient-to-br from-[#ffe082] via-[#ffb300] to-[#ff8f00]',\n      this.variant === 'compact' ? 'h-3.5 w-5' : 'h-8 w-11',\n    )\n  }\n\n  get numberContainerClass(): string {\n    return cn(\n      'flex flex-nowrap items-center font-mono font-bold tracking-[0.18em] tabular-nums',\n      this.theme.embossStyle,\n      this.variant === 'compact' ? 'my-0.5 text-xs' : 'my-1 text-base sm:text-lg',\n    )\n  }\n\n  get nameClass(): string {\n    return cn(\n      'truncate font-semibold tracking-wider uppercase',\n      this.theme.embossStyle,\n      this.variant === 'compact' ? 'text-xs' : 'text-xs',\n    )\n  }\n\n  get expiryClass(): string {\n    return cn(\n      'font-mono font-semibold tracking-wider whitespace-nowrap',\n      this.theme.embossStyle,\n      this.variant === 'compact' ? 'text-xs' : 'text-xs',\n    )\n  }\n\n  get magneticStripeClass(): string {\n    return cn(\n      'w-full bg-gradient-to-b from-neutral-950 via-black to-neutral-900 shadow-[inset_0_1px_0_rgba(255,255,255,0.1),inset_0_-1px_0_rgba(0,0,0,0.8)]',\n      this.variant === 'compact' ? 'mt-2 h-4' : 'mt-4 h-10',\n    )\n  }\n\n  get backContentClass(): string {\n    return cn('relative flex flex-col justify-between', this.variant === 'compact' ? 'p-2' : 'p-4')\n  }\n\n  get signatureRowClass(): string {\n    return cn('flex items-stretch gap-2', this.variant === 'compact' ? 'mt-1' : 'mt-2')\n  }\n\n  get signatureStripClass(): string {\n    return cn(\n      'relative flex-1 overflow-hidden rounded-[3px] border border-slate-300/80 bg-white/95 px-2 py-1',\n      this.variant === 'compact' ? 'h-4' : 'h-8',\n    )\n  }\n\n  get cvcBoxClass(): string {\n    return cn(\n      'flex flex-col items-center justify-center rounded-[3px] border border-slate-300 bg-white font-mono font-bold text-slate-950 shadow-inner',\n      this.variant === 'compact' ? 'px-1 text-xs' : 'px-3 text-xs',\n    )\n  }\n\n  get ariaLabel(): string {\n    const brand = this.detectedBrand === 'unknown' ? 'Card' : this.detectedBrand\n    const last4 = this.displayNumber.replace(/[•\\s]/g, '').slice(-4) || '••••'\n    return `${brand} ending ${last4}, ${this.displayName}, expires ${this.displayExpiry}`\n  }\n}\n",
      "type": "registry:ui",
      "target": "~/src/app/components/ui/payment-card/payment-card.component.ts"
    },
    {
      "path": "packages/registry-angular/components/payment-card/index.ts",
      "content": "export {\n  UiPaymentCardComponent,\n  type CardBrand,\n  type PaymentCardSize,\n  type PaymentCardVariant,\n} from './payment-card.component'\n",
      "type": "registry:ui",
      "target": "~/src/app/components/ui/payment-card/index.ts"
    }
  ],
  "dependencies": [],
  "devDependencies": [],
  "registryDependencies": [],
  "description": "Premium metallic credit-card visual with embossed type, holographic foil, and per-digit typing animation. Auto-detects brand (Visa, Mastercard, Amex, Discover), flips in 3D, and supports opt-in mouse-parallax tilt and shimmer. Pure presentational — pass typed values in via props.",
  "categories": [
    "data-display"
  ]
}