{"version":3,"file":"payment-sdk-DoZQMWhi.mjs","sources":["../src/i18n/translations.ts","../src/ui/card-element/renderer.ts","../src/ui/card-element/validator.ts","../src/ui/card-element/3ds-modal.ts","../src/ui/card-element/error-mapper.ts","../src/ui/card-element/payment-client.ts","../src/ui/card-element/ui-controller.ts","../src/ui/card-element.ts","../src/core/payment-sdk.ts"],"sourcesContent":["/**\n * Translations for SDK UI elements\n */\n\nimport type { Locale } from '../types';\n\nexport const SUPPORTED_LOCALES: Locale[] = ['en', 'de', 'es', 'fr', 'it', 'nl', 'pl', 'pt'];\n\nexport const DEFAULT_LOCALE: Locale = 'en';\n\nexport interface DisclaimerTranslation {\n  text: string;\n}\n\nexport const DISCLAIMER_TRANSLATIONS: Record<Locale, DisclaimerTranslation> = {\n  en: {\n    text: 'Secured and processed by our Merchant of Record, <strong>Inflowpay</strong>, <br>who also handles order-related inquiries and returns',\n  },\n  de: {\n    text: 'Gesichert und verarbeitet von unserem Merchant of Record, <strong>Inflowpay</strong>, <br>der auch auftragsbezogene Anfragen und Rücksendungen bearbeitet',\n  },\n  es: {\n    text: 'Protegido y procesado por nuestro Merchant of Record, <strong>Inflowpay</strong>, <br>que también maneja consultas y devoluciones relacionadas con el pedido',\n  },\n  fr: {\n    text: 'Sécurisé et traité par notre Merchant of Record, <strong>Inflowpay</strong>, <br>qui gère également les demandes et retours liés aux commandes',\n  },\n  it: {\n    text: 'Protetto ed elaborato dal nostro Merchant of Record, <strong>Inflowpay</strong>, <br>che gestisce anche richieste e resi relativi agli ordini',\n  },\n  nl: {\n    text: 'Beveiligd en verwerkt door onze Merchant of Record, <strong>Inflowpay</strong>, <br>die ook ordergerelatereerde vragen en retouren afhandelt',\n  },\n  pl: {\n    text: 'Zabezpieczone i przetwarzane przez Merchant of Record, <strong>Inflowpay</strong>, <br>który również obsługuje zapytania i zwroty związane z zamówieniami',\n  },\n  pt: {\n    text: 'Protegido e processado pelo nosso Merchant of Record, <strong>Inflowpay</strong>, <br>que também trata de consultas e devoluções relacionadas ao pedido',\n  },\n};\n\nexport function getDisclaimerText(locale?: Locale | string): string {\n  const validLocale = isValidLocale(locale) ? locale : DEFAULT_LOCALE;\n  return DISCLAIMER_TRANSLATIONS[validLocale].text;\n}\n\nexport function isValidLocale(locale?: string): locale is Locale {\n  return !!locale && SUPPORTED_LOCALES.includes(locale as Locale);\n}\n\nexport function detectBrowserLocale(): Locale {\n  if (typeof navigator === 'undefined') {\n    return DEFAULT_LOCALE;\n  }\n\n  const browserLang = navigator.language || (navigator as any).userLanguage || '';\n  const primaryLang = browserLang.split('-')[0].toLowerCase();\n\n  if (isValidLocale(primaryLang)) {\n    return primaryLang;\n  }\n\n  return DEFAULT_LOCALE;\n}\n","/**\n * HTML rendering and CSS styling for CardElement\n */\n\nimport type { CardElementOptions, CSSProperties, ThemeStyles, ButtonStyle, Locale } from '../../types';\nimport { getDisclaimerText } from '../../i18n';\n\n// Renderer needs required fields for rendering\ntype RendererOptions = Required<\n  Pick<CardElementOptions, 'buttonText' | 'placeholders'>\n> &\n  Partial<CardElementOptions>;\n\nexport class CardElementRenderer {\n  private shadowRoot: ShadowRoot | null = null;\n\n  constructor(\n    private container: HTMLElement,\n    private options: RendererOptions,\n    private locale: Locale\n  ) {}\n\n  /**\n   * Get or create the shadow root\n   */\n  getShadowRoot(): ShadowRoot {\n    // If we already have a reference, return it\n    if (this.shadowRoot) {\n      return this.shadowRoot;\n    }\n\n    // Check if container already has a shadow root (from previous mount/re-render)\n    if (this.container.shadowRoot) {\n      this.shadowRoot = this.container.shadowRoot;\n      return this.shadowRoot;\n    }\n\n    // Create new shadow root\n    this.shadowRoot = this.container.attachShadow({ mode: 'open' });\n    return this.shadowRoot;\n  }\n\n  /**\n   * Render HTML template into shadow DOM\n   */\n  render(): void {\n    const shadow = this.getShadowRoot();\n    shadow.innerHTML = `\n<div class=\"inflowpay-card-element\">\n\n  <!-- Card Data -->\n  <div class=\"inflowpay-card-inp-wrap\">\n  \n    <input\n      type=\"text\"\n      id=\"inflowpay-card-number\"\n      class=\"inflowpay-card-input inflowpay-card-number\"\n      placeholder=\"${this.options.placeholders.cardNumber}\"\n      maxlength=\"19\"\n      inputmode=\"numeric\"\n      autocomplete=\"cc-number\"\n    />\n\n    <input\n      type=\"text\"\n      id=\"inflowpay-expiry\"\n      class=\"inflowpay-card-input inflowpay-card-expiry\"\n      placeholder=\"${this.options.placeholders.expiry}\"\n      maxlength=\"5\"\n      inputmode=\"numeric\"\n      autocomplete=\"cc-exp\"\n    />\n\n    <input\n      type=\"text\"\n      id=\"inflowpay-cvc\"\n      class=\"inflowpay-card-input inflowpay-card-cvc\"\n      placeholder=\"${this.options.placeholders.cvc}\"\n      maxlength=\"4\"\n      inputmode=\"numeric\"\n      autocomplete=\"cc-csc\"\n    />\n  </div>\n\n  <div class=\"inflowpay-error\" id=\"error-card-number\"></div>\n  <div class=\"inflowpay-error\" id=\"error-expiry\"></div>\n  <div class=\"inflowpay-error\" id=\"error-cvc\"></div>\n\n  <!-- General Error -->\n  <div class=\"inflowpay-general-error\" id=\"general-error\" style=\"display: none;\">\n    <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n      <path d=\"M12 22C17.5228 22 22 17.5228 22 12C22 6.47715 17.5228 2 12 2C6.47715 2 2 6.47715 2 12C2 17.5228 6.47715 22 12 22Z\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n      <path d=\"M12 8V12\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n      <path d=\"M12 16H12.01\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n    </svg>\n    <span class=\"inflowpay-general-error-text\"></span>\n  </div>\n\n  <!-- Success Message -->\n  <div class=\"inflowpay-general-success\" id=\"general-success\" style=\"display: none;\">\n    <svg width=\"16\" height=\"16\" viewBox=\"0 0 14 14\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n      <g clip-path=\"url(#clip0_189_171)\">\n        <path d=\"M6.99984 12.8334C10.2215 12.8334 12.8332 10.2217 12.8332 7.00008C12.8332 3.77842 10.2215 1.16675 6.99984 1.16675C3.77818 1.16675 1.1665 3.77842 1.1665 7.00008C1.1665 10.2217 3.77818 12.8334 6.99984 12.8334Z\" stroke=\"currentColor\" stroke-width=\"1.3\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n        <path d=\"M5.25 6.99992L6.41667 8.16659L8.75 5.83325\" stroke=\"currentColor\" stroke-width=\"1.3\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n      </g>\n      <defs>\n        <clipPath id=\"clip0_189_171\">\n          <rect width=\"14\" height=\"14\" fill=\"white\"/>\n        </clipPath>\n      </defs>\n    </svg>\n    <span class=\"inflowpay-general-success-text\"></span>\n  </div>\n\n  <!-- Submit Button -->\n  <button\n    type=\"button\"\n    id=\"inflowpay-submit-btn\"\n    class=\"inflowpay-button\"\n  >\n    <span class=\"inflowpay-button-text\">${this.options.buttonText}</span>\n    <span class=\"inflowpay-button-loader\" style=\"display: none;\">\n      <div class=\"inflowpay-loader-animation\"></div>\n    </span>\n  </button>\n\n  <!-- Mandatory Disclaimer -->\n  <div class=\"inflowpay-disclaimer\">\n    <svg class=\"inflowpay-disclaimer-icon\" width=\"10\" height=\"10\" viewBox=\"0 0 8 8\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\n      <path d=\"M5.68893 3.29346H1.49704C1.1663 3.29346 0.898193 3.56157 0.898193 3.8923V5.98825C0.898193 6.31898 1.1663 6.58709 1.49704 6.58709H5.68893C6.01966 6.58709 6.28777 6.31898 6.28777 5.98825V3.8923C6.28777 3.56157 6.01966 3.29346 5.68893 3.29346Z\" stroke=\"currentColor\" stroke-width=\"0.7\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n      <path d=\"M2.09595 3.29342V2.09574C2.09595 1.69868 2.25368 1.31789 2.53444 1.03712C2.8152 0.756363 3.196 0.598633 3.59305 0.598633C3.99011 0.598633 4.3709 0.756363 4.65167 1.03712C4.93243 1.31789 5.09016 1.69868 5.09016 2.09574V3.29342\" stroke=\"currentColor\" stroke-width=\"0.7\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n    </svg>\n\n    <p class=\"inflowpay-disclaimer-text\">\n      ${getDisclaimerText(this.locale)}\n    </p>\n  </div>\n\n</div>\n`;\n  }\n\n  /**\n   * Inject default CSS styles into shadow DOM\n   */\n  injectDefaultStyles(): void {\n    const shadow = this.getShadowRoot();\n\n    // Inject Google Fonts (DM Sans) in document.head (for global access)\n    if (!document.getElementById('inflowpay-dm-sans-font')) {\n      const link = document.createElement('link');\n      link.id = 'inflowpay-dm-sans-font';\n      link.rel = 'stylesheet';\n      link.href =\n        'https://fonts.googleapis.com/css2?family=DM+Sans:ital,opsz,wght@0,9..40,100..1000;1,9..40,100..1000&display=swap';\n      document.head.appendChild(link);\n    }\n\n    // Check if styles are already injected in this shadow root\n    if (shadow.querySelector('#inflowpay-card-element-styles')) {\n      return;\n    }\n\n    // Add font link to shadow DOM so fonts are accessible\n    const fontLink = document.createElement('link');\n    fontLink.rel = 'stylesheet';\n    fontLink.href =\n      'https://fonts.googleapis.com/css2?family=DM+Sans:ital,opsz,wght@0,9..40,100..1000;1,9..40,100..1000&display=swap';\n    shadow.appendChild(fontLink);\n\n    const styleElement = document.createElement('style');\n    styleElement.id = 'inflowpay-card-element-styles';\n    styleElement.textContent = `\n  /* InflowPay CardElement Default Styles */\n  \n  * {\n    box-sizing: border-box;\n    margin: 0;\n    padding: 0;\n  }\n  \n  .inflowpay-card-element {\n    font-family: 'DM Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;\n    width: 344px;\n    max-width: 100%;\n    margin: 0 auto;\n  }\n\n  .inflowpay-card-inp-wrap {\n    display: flex;\n    align-items: center;\n    justify-content: center;\n    gap: 6px;\n    background-color: #F5F5F5;\n    padding: 8px;\n    border-radius: 8px;\n  }\n\n  .inflowpay-card-input {\n    font-family: 'DM Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;\n    background-color: transparent;\n    border: 1px solid #CECECE;\n    padding: 6px;\n    border-radius: 6px;\n    outline-width: 0;\n    color: #000000;\n    font-size: 16px;\n    text-align: start;\n  }\n\n  .inflowpay-card-input::placeholder {\n    color: #7A7A7A;\n    text-align: start;\n  }\n\n  .inflowpay-card-input:focus,\n  .inflowpay-card-input:focus-visible,\n  .inflowpay-card-input:active {\n    box-shadow: none !important;\n  }\n\n  .inflowpay-card-number {\n    flex: 1;\n    min-width: 0;\n  }\n\n  .inflowpay-card-expiry {\n    width: 21.5%;\n    flex-shrink: 0;\n  }\n\n  .inflowpay-card-cvc {\n    width: 17.5%;\n    flex-shrink: 0;\n  }\n\n  .inflowpay-error {\n    display: none;\n    font-size: 13px;\n    color: #ef4444;\n    text-align: start;\n    margin-top: 6px;\n    line-height: 1.4;\n  }\n\n  .inflowpay-general-error {\n    padding: 12px;\n    background-color: #FAC6C0;\n    color: #FF443F;\n    font-size: 14px;\n    text-align: start;\n    border-radius: 6px;\n    margin-top: 10px;\n    display: flex;\n    align-items: center;\n    gap: 5px;\n  }\n\n  .inflowpay-general-error svg {\n    flex-shrink: 0;\n  }\n\n  .inflowpay-general-error-text {\n    flex: 1;\n  }\n\n  .inflowpay-general-success {\n    padding: 12px;\n    background-color: #BFFFDD;\n    color: #119959;\n    font-size: 14px;\n    text-align: start;\n    border-radius: 6px;\n    margin-top: 10px;\n    display: flex;\n    align-items: center;\n    gap: 5px;\n  }\n\n  .inflowpay-general-success svg {\n    flex-shrink: 0;\n  }\n\n  .inflowpay-general-success-text {\n    flex: 1;\n  }\n\n  .inflowpay-button {\n    font-family: 'DM Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;\n    width: 100%;\n    padding: 0 20px;\n    height: 42px;\n    font-size: 16px;\n    font-weight: 500;\n    color: #000000;\n    background-color: #ADFFD2;\n    border: none;\n    border-radius: 8px;\n    cursor: pointer;\n    transition: all 0.2s ease;\n    display: flex;\n    align-items: center;\n    justify-content: center;\n    margin-top: 20px;\n  }\n\n  .inflowpay-button:hover:not(:disabled) {\n    transform: translateY(-1px);\n  }\n\n  .inflowpay-button:active:not(:disabled) {\n    transform: translateY(0);\n  }\n\n  .inflowpay-button:disabled {\n    cursor: not-allowed;\n    opacity: 0.7;\n  }\n\n  .inflowpay-button-text {\n    display: inline;\n    line-height: 1;\n  }\n\n  .inflowpay-button-loader {\n    display: none;\n    align-items: center;\n    justify-content: center;\n    flex-shrink: 0;\n  }\n\n  .inflowpay-loader-animation {\n    width: 35px;\n    aspect-ratio: 2;\n    --_g: no-repeat radial-gradient(circle closest-side, #0F8259 90%, #0000);\n    background: var(--_g) 0% 50%, var(--_g) 50% 50%, var(--_g) 100% 50%;\n    background-size: calc(100%/3) 50%;\n    animation: inflowpay-loader-animation 1s infinite linear;\n  }\n\n  @keyframes inflowpay-loader-animation {\n    20% { background-position: 0% 0%, 50% 50%, 100% 50%; }\n    40% { background-position: 0% 100%, 50% 0%, 100% 50%; }\n    60% { background-position: 0% 50%, 50% 100%, 100% 0%; }\n    80% { background-position: 0% 50%, 50% 50%, 100% 100%; }\n  }\n\n  .inflowpay-disclaimer {\n    display: flex;\n    flex-direction: column;\n    align-items: center;\n    justify-content: center;\n    gap: 4px;\n    font-size: 10px;\n    line-height: 1.5;\n    text-align: center;\n    color: #7A7A7A;\n    margin-top: 16px;\n  }\n\n  .inflowpay-disclaimer-icon {\n    flex-shrink: 0;\n  }\n\n  .inflowpay-disclaimer-text strong {\n    font-weight: 600;\n  }\n\n  .inflowpay-disclaimer-text br {\n    display: block;\n  }\n\n  @media (prefers-color-scheme: dark) {\n    .inflowpay-card-inp-wrap { background-color: #2d2d2d; }\n    .inflowpay-card-input { color: #ffffff; border-color: #7A7A7A; }\n    .inflowpay-card-input::placeholder { color: #959499; }\n    .inflowpay-disclaimer { color: #959499; }\n  }\n`;\n\n    // Inject styles into shadow root\n    shadow.appendChild(styleElement);\n  }\n\n  /**\n   * Apply custom styles to the card element\n   */\n  applyCustomStyles(styles: CSSProperties): void {\n    const shadow = this.getShadowRoot();\n    const wrap = shadow.querySelector('.inflowpay-card-inp-wrap');\n    const cardElement = shadow.querySelector('.inflowpay-card-element') as HTMLElement;\n\n    // ========================================================================\n    // 1. Apply global fontFamily\n    // ========================================================================\n    if (styles.fontFamily) {\n      if (cardElement) {\n        cardElement.style.fontFamily = styles.fontFamily;\n      }\n      const button = shadow.querySelector('.inflowpay-button') as HTMLElement;\n      if (button) {\n        button.style.fontFamily = styles.fontFamily;\n      }\n      const inputs = wrap?.querySelectorAll('.inflowpay-card-input');\n      if (styles.fontFamily && inputs) {\n        const fontFamily = styles.fontFamily;\n        inputs.forEach((input) => {\n          (input as HTMLElement).style.fontFamily = fontFamily;\n        });\n      }\n    }\n\n    if (!wrap) return;\n\n    const htmlWrap = wrap as HTMLElement;\n\n    // ========================================================================\n    // 2. Apply input container styles (base styles)\n    // ========================================================================\n    if (styles.inputContainer) {\n      const container = styles.inputContainer;\n      if (container.backgroundColor) {\n        htmlWrap.style.backgroundColor = container.backgroundColor;\n      }\n      if (container.border) {\n        htmlWrap.style.border = container.border;\n      }\n      if (container.borderRadius) {\n        htmlWrap.style.borderRadius = container.borderRadius;\n      }\n    }\n\n    // ========================================================================\n    // 3. Apply input field styles (base styles)\n    // ========================================================================\n    if (styles.input) {\n      const inputs = wrap.querySelectorAll('.inflowpay-card-input');\n      const inputStyles = styles.input;\n\n      inputs.forEach((input) => {\n        const htmlInput = input as HTMLElement;\n\n        if (inputStyles.border) {\n          htmlInput.style.border = inputStyles.border;\n        }\n        if (inputStyles.borderRadius) {\n          htmlInput.style.borderRadius = inputStyles.borderRadius;\n        }\n        if (inputStyles.color) {\n          htmlInput.style.color = inputStyles.color;\n        }\n        if (inputStyles.fontWeight) {\n          htmlInput.style.fontWeight = inputStyles.fontWeight;\n        }\n      });\n\n      // Apply placeholder styles\n      if (inputStyles.placeholder?.color) {\n        const styleId = 'inflowpay-custom-placeholder';\n        let styleEl = shadow.querySelector(`#${styleId}`) as HTMLStyleElement;\n        if (!styleEl) {\n          styleEl = document.createElement('style');\n          styleEl.id = styleId;\n          shadow.appendChild(styleEl);\n        }\n        styleEl.textContent = `\n          .inflowpay-card-input::placeholder {\n            color: ${inputStyles.placeholder.color} !important;\n          }\n        `;\n      }\n    }\n\n    // ========================================================================\n    // 4. Apply theme-specific styles (light/dark mode)\n    // ========================================================================\n    // Apply custom theme styles if provided. Styles are scoped to their respective\n    // themes using CSS media queries to follow system preference.\n    if (styles.light || styles.dark) {\n      const styleId = 'inflowpay-theme-styles';\n      let themeStyleEl = shadow.querySelector(`#${styleId}`) as HTMLStyleElement;\n      if (!themeStyleEl) {\n        themeStyleEl = document.createElement('style');\n        themeStyleEl.id = styleId;\n        shadow.appendChild(themeStyleEl);\n      }\n\n      const cssRules: string[] = [];\n\n      // Apply light mode custom styles (scoped to light mode only)\n      if (styles.light) {\n        const lightRules: string[] = [];\n        this.applyThemeStyles(styles.light, lightRules, true);\n        if (lightRules.length > 0) {\n          cssRules.push(`  @media (prefers-color-scheme: light), (prefers-color-scheme: no-preference) {`);\n          cssRules.push(...lightRules);\n          cssRules.push(`  }`);\n        }\n      }\n\n      // Apply dark mode custom styles (scoped to dark mode only)\n      if (styles.dark) {\n        const darkRules: string[] = [];\n        this.applyThemeStyles(styles.dark, darkRules, true);\n        if (darkRules.length > 0) {\n          cssRules.push(`  @media (prefers-color-scheme: dark) {`);\n          cssRules.push(...darkRules);\n          cssRules.push(`  }`);\n        }\n      }\n\n      if (cssRules.length > 0) {\n        themeStyleEl.textContent = cssRules.join('\\n');\n      }\n    }\n  }\n\n  /**\n   * Helper method to apply theme styles (light or dark)\n   * \n   * @param theme - Theme styles to apply\n   * @param cssRules - Array to append CSS rules to\n   * @param isDark - Whether styles are for dark mode (affects indentation for media queries)\n   */\n  private applyThemeStyles(\n    theme: ThemeStyles,\n    cssRules: string[],\n    isDark: boolean\n  ): void {\n    // Indentation for CSS formatting (4 spaces for rules inside @media queries)\n    const indent = isDark ? '    ' : '  ';\n\n    // Apply input container theme styles\n    if (theme.inputContainer) {\n      const container = theme.inputContainer;\n      if (container.backgroundColor) {\n        cssRules.push(`${indent}.inflowpay-card-inp-wrap { background-color: ${container.backgroundColor} !important; }`);\n      }\n      if (container.border) {\n        cssRules.push(`${indent}.inflowpay-card-inp-wrap { border: ${container.border} !important; }`);\n      }\n      if (container.borderRadius) {\n        cssRules.push(`${indent}.inflowpay-card-inp-wrap { border-radius: ${container.borderRadius} !important; }`);\n      }\n    }\n\n    // Apply input field theme styles\n    if (theme.input) {\n      const input = theme.input;\n      if (input.border) {\n        cssRules.push(`${indent}.inflowpay-card-input { border: ${input.border} !important; }`);\n      }\n      if (input.borderRadius) {\n        cssRules.push(`${indent}.inflowpay-card-input { border-radius: ${input.borderRadius} !important; }`);\n      }\n      if (input.color) {\n        cssRules.push(`${indent}.inflowpay-card-input { color: ${input.color} !important; }`);\n      }\n      if (input.fontWeight) {\n        cssRules.push(`${indent}.inflowpay-card-input { font-weight: ${input.fontWeight} !important; }`);\n      }\n      if (input.placeholder?.color) {\n        cssRules.push(`${indent}.inflowpay-card-input::placeholder { color: ${input.placeholder.color} !important; }`);\n      }\n    }\n  }\n\n  /**\n   * Apply custom button styles\n   */\n  applyButtonStyles(\n    styles: Partial<CSSStyleDeclaration> | ButtonStyle\n  ): void {\n    const shadow = this.getShadowRoot();\n    const button = shadow.querySelector('.inflowpay-button') as HTMLElement;\n    if (!button) return;\n\n    // Check if it's a nested structure (with base, hover, disabled, loaderColor)\n    if (\n      'base' in styles ||\n      'hover' in styles ||\n      'disabled' in styles ||\n      'loaderColor' in styles\n    ) {\n      const buttonStyles = styles as ButtonStyle;\n\n      // Apply base styles directly to button\n      if (buttonStyles.base) {\n        Object.assign(button.style, buttonStyles.base);\n      }\n\n      // Build CSS for hover and disabled states\n      const cssRules: string[] = [];\n\n      if (buttonStyles.hover) {\n        const hoverProps: string[] = [];\n        Object.entries(buttonStyles.hover).forEach(([key, value]) => {\n          if (value) {\n            const cssKey = key.replace(/([A-Z])/g, '-$1').toLowerCase();\n            hoverProps.push(`${cssKey}: ${value} !important`);\n          }\n        });\n        if (hoverProps.length > 0) {\n          cssRules.push(\n            `.inflowpay-button:hover:not(:disabled) { ${hoverProps.join('; ')} }`\n          );\n        }\n      }\n\n      if (buttonStyles.disabled) {\n        const disabledProps: string[] = [];\n        Object.entries(buttonStyles.disabled).forEach(([key, value]) => {\n          if (value) {\n            const cssKey = key.replace(/([A-Z])/g, '-$1').toLowerCase();\n            disabledProps.push(`${cssKey}: ${value} !important`);\n          }\n        });\n        if (disabledProps.length > 0) {\n          cssRules.push(\n            `.inflowpay-button:disabled { ${disabledProps.join('; ')} }`\n          );\n        }\n      }\n\n      // Handle loader color\n      if (buttonStyles.loaderColor) {\n        const loaderColor = buttonStyles.loaderColor;\n        cssRules.push(\n          `.inflowpay-loader-animation { --_g: no-repeat radial-gradient(circle closest-side, ${loaderColor} 90%, #0000) !important; }`\n        );\n      }\n\n      // Inject CSS for hover, disabled, and loader states into shadow root\n      if (cssRules.length > 0) {\n        const styleId = 'inflowpay-custom-button-states';\n        let styleEl = shadow.querySelector(`#${styleId}`) as HTMLStyleElement;\n        if (!styleEl) {\n          styleEl = document.createElement('style');\n          styleEl.id = styleId;\n          shadow.appendChild(styleEl);\n        }\n        styleEl.textContent = cssRules.join('\\n');\n      }\n    } else {\n      // Flat structure - apply directly (backward compatible)\n      Object.assign(button.style, styles as Partial<CSSStyleDeclaration>);\n    }\n  }\n\n  /**\n   * Get input element by ID from shadow DOM\n   */\n  getInput(id: string): HTMLInputElement {\n    const shadow = this.getShadowRoot();\n    return shadow.querySelector(`#${id}`) as HTMLInputElement;\n  }\n\n  /**\n   * Get button element from shadow DOM\n   */\n  getButton(): HTMLButtonElement {\n    const shadow = this.getShadowRoot();\n    return shadow.querySelector('#inflowpay-submit-btn') as HTMLButtonElement;\n  }\n\n  /**\n   * Reset shadow root reference (for cleanup)\n   */\n  resetShadowRoot(): void {\n    this.shadowRoot = null;\n  }\n}\n","/**\n * Card validation logic for CardElement\n */\n\nexport class CardValidator {\n  private skipLuhnValidation: boolean;\n\n  constructor(skipLuhnValidation: boolean = false) {\n    this.skipLuhnValidation = skipLuhnValidation;\n  }\n\n  /**\n   * Validate card number\n   */\n  validateCardNumber(value: string): string | null {\n    const cleaned = value.replace(/\\s/g, '');\n\n    if (!cleaned) {\n      return null; // Empty is okay until user starts typing\n    }\n\n    if (!/^\\d+$/.test(cleaned)) {\n      return 'Please enter a valid card number.';\n    }\n\n    if (cleaned.length < 13) {\n      return 'Card number is too short.';\n    }\n\n    if (cleaned.length > 19) {\n      return 'Card number is too long.';\n    }\n\n    // Basic Luhn check (skip if disabled for testing)\n    if (!this.skipLuhnValidation && !this.luhnCheck(cleaned)) {\n      return 'Please check your card number.';\n    }\n\n    return null;\n  }\n\n  /**\n   * Validate expiry date (MM/YY format)\n   */\n  validateExpiry(value: string): string | null {\n    if (!value) {\n      return null; // Empty is okay\n    }\n\n    const parts = value.split('/');\n    if (parts.length !== 2 || !parts[0] || !parts[1]) {\n      return 'Please enter expiry as MM/YY.';\n    }\n\n    const month = parseInt(parts[0], 10);\n    const year = parseInt('20' + parts[1], 10);\n\n    if (isNaN(month) || month < 1 || month > 12) {\n      return 'Please enter a valid month.';\n    }\n\n    if (isNaN(year)) {\n      return 'Please enter a valid year.';\n    }\n\n    // Check if expired\n    const now = new Date();\n    const currentYear = now.getFullYear();\n    const currentMonth = now.getMonth() + 1;\n\n    if (year < currentYear || (year === currentYear && month < currentMonth)) {\n      return 'This card has expired.';\n    }\n\n    return null;\n  }\n\n  /**\n   * Validate CVC code\n   */\n  validateCvc(value: string): string | null {\n    if (!value) {\n      return null; // Empty is okay\n    }\n\n    if (!/^\\d+$/.test(value)) {\n      return 'Please enter a valid security code.';\n    }\n\n    if (value.length < 3) {\n      return 'Security code is too short.';\n    }\n\n    if (value.length > 4) {\n      return 'Security code is too long.';\n    }\n\n    return null;\n  }\n\n  /**\n   * Luhn algorithm for card number validation\n   * https://en.wikipedia.org/wiki/Luhn_algorithm\n   */\n  private luhnCheck(cardNumber: string): boolean {\n    let sum = 0;\n    let isEven = false;\n\n    for (let i = cardNumber.length - 1; i >= 0; i--) {\n      let digit = parseInt(cardNumber.charAt(i), 10);\n\n      if (isEven) {\n        digit *= 2;\n        if (digit > 9) {\n          digit -= 9;\n        }\n      }\n\n      sum += digit;\n      isEven = !isEven;\n    }\n\n    return sum % 10 === 0;\n  }\n}","/**\n * 3D Secure Modal for in-page authentication\n *\n * Opens an overlay with iframe containing the 3DS challenge page.\n * Listens for completion via postMessage and auto-closes.\n */\n\nexport class ThreeDSModal {\n  private overlay: HTMLElement | null = null;\n  private iframe: HTMLIFrameElement | null = null;\n  private messageListener: ((event: MessageEvent) => void) | null = null;\n  private resolveCompletion: ((success: boolean) => void) | null = null;\n\n  /**\n   * Open the 3DS modal with challenge URL\n   * Returns a promise that resolves when 3DS is complete\n   */\n  async open(challengeUrl: string): Promise<boolean> {\n\n    // SECURITY: Validate and sanitize URL\n    if (!this.isValidChallengeUrl(challengeUrl)) {\n      throw new Error('Invalid 3DS challenge URL');\n    }\n\n    // Prevent multiple instances\n    if (this.overlay) {\n      this.close();\n    }\n\n    // Create overlay using safe DOM manipulation (not innerHTML with user data)\n    this.overlay = document.createElement('div');\n    this.overlay.className = 'inflowpay-3ds-overlay';\n\n    const modal = document.createElement('div');\n    modal.className = 'inflowpay-3ds-modal';\n\n    const header = document.createElement('div');\n    header.className = 'inflowpay-3ds-header';\n    header.innerHTML = '<h3>Secure Payment Authentication</h3><button class=\"inflowpay-3ds-close\" aria-label=\"Close\">×</button>';\n\n    const content = document.createElement('div');\n    content.className = 'inflowpay-3ds-content';\n    content.innerHTML = '<div class=\"inflowpay-3ds-loading\"><div class=\"inflowpay-spinner\"></div><p>Loading authentication...</p></div>';\n\n    // Create iframe safely\n    this.iframe = document.createElement('iframe');\n    this.iframe.className = 'inflowpay-3ds-iframe';\n    this.iframe.src = challengeUrl; // Safe - URL already validated\n    this.iframe.allow = 'payment';\n    // Note: allow-same-origin is needed for 3DS providers to make API calls\n    // This is safe because:\n    // 1. We validate the challengeUrl domain (whitelist)\n    // 2. 3DS providers are trusted payment processors\n    // 3. Without it, 3DS authentication fails with CORS errors\n    this.iframe.sandbox.add('allow-forms', 'allow-scripts', 'allow-same-origin', 'allow-popups');\n\n    content.appendChild(this.iframe);\n    modal.appendChild(header);\n    modal.appendChild(content);\n    this.overlay.appendChild(modal);\n\n    // Add styles\n    this.injectStyles();\n\n    // Add to DOM\n    document.body.appendChild(this.overlay);\n\n    // Get references\n    const closeBtn = this.overlay.querySelector('.inflowpay-3ds-close');\n    const loadingEl = this.overlay.querySelector('.inflowpay-3ds-loading') as HTMLElement;\n\n    // Hide loading when iframe loads\n    this.iframe.addEventListener('load', () => {\n      if (loadingEl) loadingEl.style.display = 'none';\n      if (this.iframe) this.iframe.style.display = 'block';\n    });\n\n    // Close button handler - FIXED: resolve BEFORE close\n    if (closeBtn) {\n      closeBtn.addEventListener('click', () => {\n        if (this.resolveCompletion) this.resolveCompletion(false);\n        this.close();\n      });\n    }\n\n    // Setup postMessage listener\n    return new Promise<boolean>((resolve) => {\n      this.resolveCompletion = resolve;\n      this.setupPostMessageListener();\n    });\n  }\n\n  /**\n   * Close and cleanup the modal\n   */\n  close(): void {\n\n    // Remove message listener\n    if (this.messageListener) {\n      window.removeEventListener('message', this.messageListener);\n      this.messageListener = null;\n    }\n\n    // Remove overlay from DOM\n    if (this.overlay && this.overlay.parentNode) {\n      this.overlay.parentNode.removeChild(this.overlay);\n    }\n\n    this.overlay = null;\n    this.iframe = null;\n    this.resolveCompletion = null;\n  }\n\n  /**\n   * Listen for postMessage from callback page\n   */\n  private setupPostMessageListener(): void {\n    this.messageListener = (event: MessageEvent) => {\n      // SECURITY: Validate origin - only accept messages from same origin or trusted domains\n      const currentOrigin = window.location.origin;\n\n      // Allow messages from:\n      // 1. Same origin (our callback page in iframe with allow-same-origin)\n      // 2. Basis Theory 3DS domains\n      // 3. InflowPay API domains (for hosted callback pages)\n      const trustedOrigins = [\n        currentOrigin,\n        'https://api.basistheory.com',\n        'https://acs.basistheory.com',\n        'https://api.inflowpay.xyz',\n        'https://pre-prod.api.inflowpay.xyz',\n        'http://localhost:3000',\n      ];\n\n      const isTrusted = trustedOrigins.some(origin =>\n        event.origin === origin ||\n        event.origin.endsWith('.basistheory.com') ||\n        event.origin.endsWith('.inflowpay.xyz')\n      );\n\n      if (!isTrusted) {\n        return;\n      }\n\n      // Parse message data\n      const data = event.data;\n\n      // Check for 3DS completion message\n      if (data && (data.type === 'THREE_DS_COMPLETE' || data.type === '3DS_COMPLETE')) {\n        const success = data.status === 'success';\n\n        // Resolve promise BEFORE closing (close() sets resolveCompletion to null)\n        if (this.resolveCompletion) {\n          this.resolveCompletion(success);\n        }\n\n        // Close modal after resolving\n        this.close();\n      }\n\n      // Also check for redirect to callback URL pattern\n      // This handles cases where iframe redirects to our callback URL\n      if (this.iframe && this.iframe.contentWindow) {\n        try {\n          const iframeUrl = this.iframe.contentWindow.location.href;\n\n          // Check if redirected to success/failure callback (both old and new patterns)\n          // Old pattern: /3ds-callback.html?status=success\n          // New pattern: /threeds/success or /threeds/failure\n          if (iframeUrl.includes('3ds-callback') || iframeUrl.includes('/threeds/')) {\n            const isSuccess = iframeUrl.includes('status=success') ||\n                            iframeUrl.includes('/threeds/success');\n\n            // Resolve promise BEFORE closing\n            if (this.resolveCompletion) {\n              this.resolveCompletion(isSuccess);\n            }\n            this.close();\n          }\n        } catch (e) {\n          // Cross-origin error - expected when iframe is on different domain\n          // This is fine, we'll rely on postMessage instead\n        }\n      }\n    };\n\n    window.addEventListener('message', this.messageListener);\n  }\n\n  /**\n   * Inject modal styles into the page\n   */\n  private injectStyles(): void {\n    const styleId = 'inflowpay-3ds-modal-styles';\n\n    // Don't inject if already present\n    if (document.getElementById(styleId)) {\n      return;\n    }\n\n    const style = document.createElement('style');\n    style.id = styleId;\n    style.textContent = `\n      .inflowpay-3ds-overlay {\n        position: fixed;\n        top: 0;\n        left: 0;\n        right: 0;\n        bottom: 0;\n        background: rgba(0, 0, 0, 0.5);\n        display: flex;\n        align-items: center;\n        justify-content: center;\n        z-index: 999999;\n        animation: inflowpay-fadeIn 0.2s ease-out;\n      }\n\n      @keyframes inflowpay-fadeIn {\n        from { opacity: 0; }\n        to { opacity: 1; }\n      }\n\n      .inflowpay-3ds-modal {\n        background: white;\n        border-radius: 12px;\n        width: 90%;\n        max-width: 600px;\n        max-height: 90vh;\n        display: flex;\n        flex-direction: column;\n        box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);\n        animation: inflowpay-slideUp 0.3s ease-out;\n      }\n\n      @keyframes inflowpay-slideUp {\n        from { transform: translateY(20px); opacity: 0; }\n        to { transform: translateY(0); opacity: 1; }\n      }\n\n      .inflowpay-3ds-header {\n        padding: 20px 24px;\n        border-bottom: 1px solid #e5e7eb;\n        display: flex;\n        align-items: center;\n        justify-content: space-between;\n      }\n\n      .inflowpay-3ds-header h3 {\n        margin: 0;\n        font-size: 18px;\n        font-weight: 600;\n        color: #1f2937;\n      }\n\n      .inflowpay-3ds-close {\n        background: none;\n        border: none;\n        font-size: 32px;\n        line-height: 1;\n        color: #6b7280;\n        cursor: pointer;\n        padding: 0;\n        width: 32px;\n        height: 32px;\n        display: flex;\n        align-items: center;\n        justify-content: center;\n        border-radius: 6px;\n        transition: all 0.2s;\n      }\n\n      .inflowpay-3ds-close:hover {\n        background: #f3f4f6;\n        color: #1f2937;\n      }\n\n      .inflowpay-3ds-content {\n        position: relative;\n        flex: 1;\n        overflow: hidden;\n        min-height: 500px;\n        display: flex;\n        flex-direction: column;\n      }\n\n      .inflowpay-3ds-loading {\n        position: absolute;\n        top: 0;\n        left: 0;\n        right: 0;\n        bottom: 0;\n        display: flex;\n        flex-direction: column;\n        align-items: center;\n        justify-content: center;\n        background: white;\n        z-index: 1;\n      }\n\n      .inflowpay-3ds-loading p {\n        margin-top: 16px;\n        color: #6b7280;\n        font-size: 14px;\n      }\n\n      .inflowpay-spinner {\n        width: 40px;\n        height: 40px;\n        border: 3px solid #e5e7eb;\n        border-top-color: #3b82f6;\n        border-radius: 50%;\n        animation: inflowpay-spin 0.8s linear infinite;\n      }\n\n      @keyframes inflowpay-spin {\n        to { transform: rotate(360deg); }\n      }\n\n      .inflowpay-3ds-iframe {\n        display: none;\n        position: absolute;\n        top: 0;\n        left: 0;\n        right: 0;\n        bottom: 0;\n        width: 100%;\n        height: 100%;\n        border: none;\n      }\n\n      /* Mobile responsive */\n      @media (max-width: 640px) {\n        .inflowpay-3ds-modal {\n          width: 100%;\n          max-width: 100%;\n          height: 100%;\n          max-height: 100%;\n          border-radius: 0;\n        }\n\n        .inflowpay-3ds-content {\n          min-height: 0;\n        }\n      }\n    `;\n\n    document.head.appendChild(style);\n  }\n\n  /**\n   * Validate challenge URL to prevent XSS\n   */\n  private isValidChallengeUrl(url: string): boolean {\n    try {\n      const parsedUrl = new URL(url);\n\n      // Only allow HTTPS (except localhost for development)\n      const isSecure = parsedUrl.protocol === 'https:' ||\n                      (parsedUrl.protocol === 'http:' && parsedUrl.hostname === 'localhost');\n\n      if (!isSecure) {\n        return false;\n      }\n\n      // Whitelist trusted domains for 3DS\n      const trustedDomains = [\n        'basistheory.com',\n        'stripe.com',\n        'localhost', // For development\n      ];\n\n      const isTrustedDomain = trustedDomains.some(domain =>\n        parsedUrl.hostname === domain || parsedUrl.hostname.endsWith('.' + domain)\n      );\n\n      if (!isTrustedDomain) {\n        return false;\n      }\n\n      return true;\n    } catch (e) {\n      return false;\n    }\n  }\n}\n","/**\n * Error Mapper - Converts technical errors to user-friendly messages\n *\n * Ensures end users never see raw API errors, technical messages, or stack traces.\n * All technical details are logged in debug mode but sanitized for user display.\n */\n\nimport type { PaymentError } from '../../types';\n\n/**\n * Map error codes to user-friendly messages\n */\nconst ERROR_MESSAGES: Record<string, string> = {\n  // Validation errors\n  VALIDATION_ERROR: 'Please complete all card fields.',\n  invalid_card_number: 'Please check your card number and try again.',\n  INVALID_CARD_NUMBER: 'Please check your card number and try again.',\n  invalid_expiry: 'Please check the expiration date and try again.',\n  INVALID_EXPIRY: 'Please check the expiration date and try again.',\n  invalid_cvc: 'Please check the security code and try again.',\n  INVALID_CVC: 'Please check the security code and try again.',\n\n  // Card errors\n  card_declined: 'Your card was declined. Please try another payment method or contact your bank.',\n  CARD_DECLINED: 'Your card was declined. Please try another payment method or contact your bank.',\n  insufficient_funds: 'Your card has insufficient funds. Please try another payment method.',\n  INSUFFICIENT_FUNDS: 'Your card has insufficient funds. Please try another payment method.',\n  expired_card: 'This card has expired. Please use a different card.',\n  EXPIRED_CARD: 'This card has expired. Please use a different card.',\n  incorrect_cvc: 'The security code is incorrect. Please check and try again.',\n  INCORRECT_CVC: 'The security code is incorrect. Please check and try again.',\n  processing_error: 'Your card could not be processed. Please try another card.',\n  PROCESSING_ERROR: 'Your card could not be processed. Please try another card.',\n\n  // 3DS errors\n  THREE_DS_FAILED: '3D Secure authentication failed. Please try again.',\n  THREE_DS_CANCELED: 'Authentication was canceled. Please try again to complete your payment.',\n  three_ds_not_supported: \"This card doesn't support secure authentication. Please try a different card.\",\n  THREE_DS_NOT_SUPPORTED: \"This card doesn't support secure authentication. Please try a different card.\",\n\n  // Network errors\n  NETWORK_ERROR: 'Connection error. Please check your internet connection and try again.',\n  NETWORK_TIMEOUT: 'Connection timeout. Please try again.',\n  network_error: 'Connection error. Please check your internet connection and try again.',\n  timeout: 'Connection timeout. Please try again.',\n\n  // System errors\n  PAYMENT_FAILED: 'Payment could not be processed. Please try again.',\n  PAYMENT_NOT_FOUND: 'Payment session has expired. Please start a new payment.',\n  PAYMENT_ALREADY_PROCESSED: 'This payment has already been processed successfully.',\n  AUTHENTICATION_ERROR: 'Authentication failed. Please refresh the page and try again.',\n  STATUS_CHECK_FAILED: 'Could not verify payment status. Please contact support.',\n  POLLING_ERROR: 'Could not verify payment status. Please try again.',\n  PAYMENT_PROCESSING: 'Your payment is being processed. Please wait a moment and check your payment status.',\n\n  // Tokenization errors\n  tokenization_failed: 'Card information could not be processed. Please check your card details and try again.',\n  TOKENIZATION_FAILED: 'Card information could not be processed. Please check your card details and try again.',\n\n  // Stripe-specific codes\n  requires_payment_method: 'Your card was declined. Please try another payment method.',\n  test_mode_live_card: 'This card cannot be used in test mode. Please use a test card number.',\n\n  // Generic Stripe error codes\n  generic_decline: 'Your card was declined. Please try another payment method or contact your bank.',\n  lost_card: 'This card has been reported lost. Please use a different card.',\n  stolen_card: 'This card has been reported stolen. Please use a different card.',\n  do_not_honor: 'Your card was declined. Please contact your bank for more information.',\n  do_not_try_again: 'Your card was declined. Please use a different payment method.',\n};\n\n/**\n * Default fallback message for unknown errors\n */\nconst DEFAULT_ERROR_MESSAGE = 'Something went wrong. Please try again or contact support if the problem persists.';\n\n/**\n * Convert API error response to user-friendly PaymentError\n */\nexport function mapApiError(\n  response: any,\n  statusCode: number,\n  debugMode: boolean = false\n): PaymentError {\n  // Log raw error for debugging\n  if (debugMode) {\n    console.log('[ErrorMapper] Raw API error:', {\n      statusCode,\n      response,\n    });\n  }\n\n  // Handle case where error details are nested in a message field as JSON string\n  // Example: { message: \"Status code: 424\\nBody: {...}\" }\n  if (response?.message && typeof response.message === 'string') {\n    // Try to extract JSON from the message field\n    const jsonMatch = response.message.match(/Body:\\s*(\\{[\\s\\S]*\\})/);\n    if (jsonMatch) {\n      try {\n        const parsedBody = JSON.parse(jsonMatch[1]);\n        if (debugMode) {\n          console.log('[ErrorMapper] Extracted nested JSON from message field:', parsedBody);\n        }\n        // Recursively call mapApiError with the extracted body\n        return mapApiError(parsedBody, statusCode, debugMode);\n      } catch (e) {\n        // Failed to parse nested JSON, continue with normal flow\n        if (debugMode) {\n          console.log('[ErrorMapper] Failed to parse nested JSON:', e);\n        }\n      }\n    }\n  }\n\n  // Handle structured error responses (like your 3DS 424 example)\n  if (response?.error) {\n    const apiError = response.error;\n\n    // Extract meaningful user message from structured error\n    let userMessage = DEFAULT_ERROR_MESSAGE;\n    let errorCode = 'UNKNOWN_ERROR';\n\n    // Check for 3DS-specific errors\n    if (apiError.errorSource === '3DS Server' || response.title?.includes('3DS')) {\n      errorCode = 'THREE_DS_NOT_SUPPORTED';\n\n      // Use the details array if available (like your example)\n      if (apiError.details && Array.isArray(apiError.details) && apiError.details.length > 0) {\n        userMessage = apiError.details[0];\n      } else if (apiError.message) {\n        // Map known 3DS messages\n        if (apiError.message.toLowerCase().includes('not supported')) {\n          userMessage = ERROR_MESSAGES.THREE_DS_NOT_SUPPORTED || DEFAULT_ERROR_MESSAGE;\n        } else {\n          userMessage = apiError.message;\n        }\n      }\n    }\n    // Check for other structured error patterns\n    else if (apiError.code) {\n      errorCode = apiError.code;\n      const mappedMessage = ERROR_MESSAGES[errorCode];\n      userMessage = mappedMessage || (apiError.message ? apiError.message : DEFAULT_ERROR_MESSAGE);\n    } else if (apiError.message) {\n      // Try to map the message to a known error\n      const normalizedMessage = apiError.message.toLowerCase();\n\n      if (normalizedMessage.includes('declined')) {\n        errorCode = 'CARD_DECLINED';\n        userMessage = ERROR_MESSAGES.CARD_DECLINED || DEFAULT_ERROR_MESSAGE;\n      } else if (normalizedMessage.includes('insufficient')) {\n        errorCode = 'INSUFFICIENT_FUNDS';\n        userMessage = ERROR_MESSAGES.INSUFFICIENT_FUNDS || DEFAULT_ERROR_MESSAGE;\n      } else if (normalizedMessage.includes('expired')) {\n        errorCode = 'EXPIRED_CARD';\n        userMessage = ERROR_MESSAGES.EXPIRED_CARD || DEFAULT_ERROR_MESSAGE;\n      } else if (normalizedMessage.includes('3ds') || normalizedMessage.includes('3d secure')) {\n        errorCode = 'THREE_DS_FAILED';\n        userMessage = ERROR_MESSAGES.THREE_DS_FAILED || DEFAULT_ERROR_MESSAGE;\n      } else {\n        // Use the API message if it seems user-friendly (no technical jargon)\n        if (!hasTechnicalJargon(apiError.message)) {\n          userMessage = apiError.message;\n        }\n      }\n    }\n\n    // Determine if error is retryable\n    const retryable = isRetryableError(errorCode, statusCode);\n\n    return {\n      code: errorCode,\n      message: sanitizeMessage(userMessage),\n      retryable,\n      statusCode,\n      details: debugMode ? response : undefined,\n    };\n  }\n\n  // Handle simple error messages\n  if (response?.message) {\n    const errorCode = response.code || 'PAYMENT_FAILED';\n    const mappedMessage = ERROR_MESSAGES[errorCode];\n    const userMessage = mappedMessage ||\n      (hasTechnicalJargon(response.message) ? DEFAULT_ERROR_MESSAGE : response.message);\n\n    return {\n      code: errorCode,\n      message: sanitizeMessage(userMessage),\n      retryable: isRetryableError(errorCode, statusCode),\n      statusCode,\n      details: debugMode ? response : undefined,\n    };\n  }\n\n  // Handle HTTP errors without structured response\n  let errorCode = 'PAYMENT_FAILED';\n  let userMessage = DEFAULT_ERROR_MESSAGE;\n\n  if (statusCode === 404) {\n    errorCode = 'PAYMENT_NOT_FOUND';\n    userMessage = ERROR_MESSAGES.PAYMENT_NOT_FOUND || DEFAULT_ERROR_MESSAGE;\n  } else if (statusCode === 401 || statusCode === 403) {\n    errorCode = 'AUTHENTICATION_ERROR';\n    userMessage = ERROR_MESSAGES.AUTHENTICATION_ERROR || DEFAULT_ERROR_MESSAGE;\n  } else if (statusCode === 424) {\n    // 424 Failed Dependency - often used for 3DS errors\n    errorCode = 'THREE_DS_FAILED';\n    userMessage = ERROR_MESSAGES.THREE_DS_FAILED || DEFAULT_ERROR_MESSAGE;\n  } else if (statusCode >= 500) {\n    userMessage = 'Our payment system is temporarily unavailable. Please try again in a few moments.';\n  }\n\n  return {\n    code: errorCode,\n    message: sanitizeMessage(userMessage),\n    retryable: isRetryableError(errorCode, statusCode),\n    statusCode,\n    details: debugMode ? response : undefined,\n  };\n}\n\n/**\n * Map error codes to user-friendly messages\n */\nexport function mapErrorCode(code: string, originalMessage?: string): string {\n  // Check if we have a mapped message\n  if (ERROR_MESSAGES[code]) {\n    return ERROR_MESSAGES[code];\n  }\n\n  // If original message exists and seems user-friendly, use it\n  if (originalMessage && !hasTechnicalJargon(originalMessage)) {\n    return sanitizeMessage(originalMessage);\n  }\n\n  return DEFAULT_ERROR_MESSAGE;\n}\n\n/**\n * Map generic exceptions to PaymentError\n */\nexport function mapException(error: unknown, debugMode: boolean = false): PaymentError {\n  if (debugMode) {\n    console.log('[ErrorMapper] Exception:', error);\n  }\n\n  // Network timeout\n  if (error instanceof Error && error.name === 'AbortError') {\n    return {\n      code: 'NETWORK_TIMEOUT',\n      message: ERROR_MESSAGES.NETWORK_TIMEOUT || DEFAULT_ERROR_MESSAGE,\n      retryable: true,\n    };\n  }\n\n  // Network error\n  if (error instanceof TypeError) {\n    return {\n      code: 'NETWORK_ERROR',\n      message: ERROR_MESSAGES.NETWORK_ERROR || DEFAULT_ERROR_MESSAGE,\n      retryable: true,\n    };\n  }\n\n  // Error with message\n  if (error instanceof Error) {\n    // Check if error message contains technical details\n    if (hasTechnicalJargon(error.message)) {\n      return {\n        code: 'PAYMENT_FAILED',\n        message: DEFAULT_ERROR_MESSAGE,\n        retryable: true,\n        details: debugMode ? { originalError: error.message } : undefined,\n      };\n    }\n\n    return {\n      code: 'PAYMENT_FAILED',\n      message: sanitizeMessage(error.message),\n      retryable: true,\n    };\n  }\n\n  return {\n    code: 'UNKNOWN_ERROR',\n    message: DEFAULT_ERROR_MESSAGE,\n    retryable: true,\n  };\n}\n\n/**\n * Check if error code or status indicates a retryable error\n */\nfunction isRetryableError(errorCode: string, statusCode?: number): boolean {\n  // Network errors are always retryable\n  if (errorCode.includes('NETWORK') || errorCode.includes('TIMEOUT')) {\n    return true;\n  }\n\n  // Validation errors are retryable (user can fix input)\n  if (errorCode.includes('INVALID') || errorCode.includes('VALIDATION')) {\n    return true;\n  }\n\n  // Card errors are often retryable (try different card)\n  const retryableCardErrors = [\n    'CARD_DECLINED',\n    'INSUFFICIENT_FUNDS',\n    'EXPIRED_CARD',\n    'INCORRECT_CVC',\n    'THREE_DS_FAILED',\n    'THREE_DS_CANCELED',\n    'THREE_DS_NOT_SUPPORTED',\n  ];\n\n  if (retryableCardErrors.includes(errorCode)) {\n    return true;\n  }\n\n  // Some HTTP statuses indicate retryable errors\n  if (statusCode && (statusCode === 408 || statusCode === 429 || statusCode >= 500)) {\n    return true;\n  }\n\n  // Default to not retryable for unknown errors\n  return false;\n}\n\n/**\n * Check if message contains technical jargon that shouldn't be shown to users\n */\nfunction hasTechnicalJargon(message: string): boolean {\n  const technicalTerms = [\n    'proxy',\n    'json',\n    'html',\n    'parse',\n    'undefined',\n    'null',\n    'exception',\n    'stack trace',\n    'basis theory',\n    'api',\n    'endpoint',\n    'tokenintent',\n    'fetch',\n    'response.status',\n    'http',\n    'ssl',\n    'tls',\n  ];\n\n  const lowerMessage = message.toLowerCase();\n  return technicalTerms.some(term => lowerMessage.includes(term));\n}\n\n/**\n * Sanitize message to ensure it's user-friendly\n */\nfunction sanitizeMessage(message: string): string {\n  // Remove technical prefixes\n  let sanitized = message\n    .replace(/^Error:\\s*/i, '')\n    .replace(/^[A-Z_]+:\\s*/, '') // Remove ERROR_CODE: prefix\n    .trim();\n\n  // Ensure first letter is capitalized and ends with period\n  if (sanitized.length > 0) {\n    sanitized = sanitized.charAt(0).toUpperCase() + sanitized.slice(1);\n    if (!sanitized.endsWith('.')) {\n      sanitized += '.';\n    }\n  }\n\n  return sanitized;\n}","/**\n * Payment API client for CardElement\n * Handles tokenization, payment submission, and status polling\n *\n * IMPORTANT: Assumes payment is pre-created with billing information.\n * Only sends paymentId + tokenIntentId to confirm endpoint.\n */\n\nimport type { CardData, PaymentResult, PaymentStatus } from '../../types';\nimport type { InternalSDKConfig, PaymentStatusResponse, ServerPaymentResponse } from './types';\nimport { ThreeDSModal } from './3ds-modal';\nimport { mapApiError, mapException, mapErrorCode } from './error-mapper';\n\nexport class PaymentClient {\n  private threeDSModal: ThreeDSModal;\n\n  constructor(\n    private config: InternalSDKConfig,\n    private paymentId: string\n  ) {\n    this.threeDSModal = new ThreeDSModal();\n  }\n\n  /**\n   * Complete payment flow with tokenization and status polling\n   * Payment must already be created with all billing information\n   */\n  async completePayment(cardData: CardData): Promise<PaymentResult> {\n    this.log('[CardElement] Starting payment...', { paymentId: this.paymentId });\n\n    try {\n      // Step 1: Tokenize card\n      this.log('[CardElement] Tokenizing card...');\n      const tokenResponse = await this.tokenizeCard(cardData);\n      this.log('[CardElement] Card tokenized', { tokenId: tokenResponse.tokenIntentId });\n\n      // Step 2: Submit payment (with paymentId + tokenIntentId only)\n      this.log('[CardElement] Submitting payment...');\n      const paymentResponse = await this.submitPayment(tokenResponse.tokenIntentId);\n      this.log('[CardElement] Payment response from /sdk/payment/confirm:', paymentResponse);\n\n      // Step 3: Handle 3DS challenge with modal\n      if (paymentResponse.threeDsSessionUrl) {\n        this.log('[CardElement] 3DS challenge required, opening modal...');\n\n        // Open 3DS modal and wait for completion\n        const threeDSSuccess = await this.threeDSModal.open(paymentResponse.threeDsSessionUrl);\n\n        this.log('[CardElement] 3DS modal closed:', threeDSSuccess ? 'success' : 'failure');\n\n        // If 3DS failed or was canceled, return error\n        if (!threeDSSuccess) {\n          return {\n            status: 'PAYMENT_FAILED' as PaymentStatus,\n            error: {\n              code: 'THREE_DS_FAILED',\n              message: '3D Secure authentication failed or was canceled',\n              retryable: true,\n            },\n          };\n        }\n\n        // 3DS completed successfully - now poll for final payment status\n        this.log('[CardElement] 3DS completed, polling payment status...');\n        try {\n          const finalStatus = await this.pollUntilComplete();\n          this.log('[CardElement] Polling complete, final status:', finalStatus);\n          return finalStatus;\n        } catch (pollError) {\n          this.log('[CardElement] Error during polling:', pollError);\n          return {\n            status: 'PAYMENT_FAILED' as PaymentStatus,\n            error: {\n              code: 'POLLING_ERROR',\n              message: 'Failed to verify payment status after 3DS',\n              retryable: true,\n            },\n          };\n        }\n      }\n\n      // Step 4: If payment is already complete, return\n      if (this.isSuccessfulStatus(paymentResponse.status)) {\n        return {\n          status: paymentResponse.status,\n          alreadyProcessed: paymentResponse.alreadyProcessed\n        };\n      }\n\n      // Step 5: Wait for processing\n      this.log('[CardElement] Waiting for processing...');\n      await new Promise(resolve => setTimeout(resolve, 2500));\n\n      // Step 6: Poll for status\n      const maxPolls = 3;\n      const pollInterval = 2000;\n\n      for (let attempt = 1; attempt <= maxPolls; attempt++) {\n        this.log(`[CardElement] Polling status (${attempt}/${maxPolls})...`);\n        const status = await this.pollPaymentStatus();\n        this.log('[CardElement] Full status response from /sdk/payment/:id:', status);\n        this.log('[CardElement] Status response summary:', {\n          status: status.status,\n          hasError: !!status.error,\n          hasLastDepositError: !!status.lastDepositAttempt?.error,\n          hasChallengeUrl: !!status.challengeUrl\n        });\n\n        if (status.error) {\n          this.log('[CardElement] Error details:', status.error);\n        }\n        if (status.lastDepositAttempt?.error) {\n          this.log('[CardElement] Last deposit attempt error:', status.lastDepositAttempt.error);\n        }\n\n        // Success\n        if (this.isSuccessfulStatus(status.status)) {\n          return { status: status.status };\n        }\n\n        // Failed\n        if (this.isFailedStatus(status.status)) {\n          const errorCode = status.error || status.lastDepositAttempt?.error || 'PAYMENT_FAILED';\n          return {\n            status: status.status,\n            error: {\n              code: errorCode,\n              message: mapErrorCode(errorCode),\n              retryable: this.isRetryableErrorCode(errorCode),\n            },\n          };\n        }\n\n        // Check if there's an error in pending/processing states\n        // This handles cases where payment failed but status hasn't updated yet\n        const errorCode = status.error || status.lastDepositAttempt?.error;\n        if (errorCode && (status.status === 'CHECKOUT_PENDING' || status.status === 'INITIATION')) {\n          this.log('[CardElement] Found error in pending state, returning error:', errorCode);\n          return {\n            status: status.status,\n            error: {\n              code: errorCode,\n              message: mapErrorCode(errorCode),\n              retryable: this.isRetryableErrorCode(errorCode),\n            },\n          };\n        }\n\n        // Still processing - retry\n        if (attempt < maxPolls) {\n          await new Promise(resolve => setTimeout(resolve, pollInterval));\n          continue;\n        }\n\n        // Timeout\n        return {\n          status: status.status,\n          error: {\n            code: 'PAYMENT_PROCESSING',\n            message: 'Payment is still processing. Please check status later.',\n            retryable: false,\n          },\n        };\n      }\n\n      throw new Error('Payment processing did not complete');\n    } catch (error) {\n      this.log('[CardElement] Payment error:', error);\n\n      // Map exception to user-friendly error\n      const mappedError = mapException(error, this.config.debug);\n      return {\n        status: 'PAYMENT_FAILED' as PaymentStatus,\n        error: mappedError,\n      };\n    }\n  }\n\n  /**\n   * Tokenize card via proxy (only card data, no billing info)\n   */\n  private async tokenizeCard(cardData: CardData): Promise<{ tokenIntentId: string }> {\n    const headers: Record<string, string> = {\n      'Content-Type': 'application/json',\n    };\n\n    if (this.config.tokenizationProxyKey) {\n      headers['BT-PROXY-KEY'] = this.config.tokenizationProxyKey;\n    }\n\n    const response = await fetch(this.config.tokenizationProxyUrl, {\n      method: 'POST',\n      headers,\n      body: JSON.stringify({\n        card: {\n          number: cardData.number,\n          expiration_month: cardData.expiration_month,\n          expiration_year: cardData.expiration_year,\n          cvc: cardData.cvc,\n        },\n      }),\n      signal: AbortSignal.timeout(this.config.timeout),\n    });\n\n    if (!response.ok) {\n      const errorText = await response.text();\n      this.log('[CardElement] Tokenization failed:', { status: response.status, body: errorText });\n      let errorData: any = {};\n      try {\n        errorData = JSON.parse(errorText);\n      } catch (e) {\n        // Not JSON, will be handled by error mapper\n      }\n\n      // Map API error to user-friendly message\n      const mappedError = mapApiError(errorData, response.status, this.config.debug);\n      throw new Error(mappedError.message);\n    }\n\n    const responseText = await response.text();\n    const contentType = response.headers.get('content-type') || '';\n    this.log('[CardElement] Tokenization response:', {\n      status: response.status,\n      contentType,\n      body: responseText.substring(0, 500) // Log first 500 chars\n    });\n\n    if (!responseText || responseText.trim() === '') {\n      const mappedError = mapApiError({}, response.status, this.config.debug);\n      throw new Error(mappedError.message);\n    }\n\n    // Check if response is HTML instead of JSON (indicates proxy error)\n    if (contentType.includes('text/html')) {\n      this.log('[CardElement] Received HTML instead of JSON - proxy configuration issue');\n      // Map this to a generic system error (don't expose proxy details)\n      const mappedError = mapApiError({ message: 'Service temporarily unavailable' }, 503, this.config.debug);\n      throw new Error(mappedError.message);\n    }\n\n    let parsedResponse: any;\n    try {\n      parsedResponse = JSON.parse(responseText);\n    } catch (e) {\n      this.log('[CardElement] Failed to parse response as JSON:', responseText);\n      const mappedError = mapApiError({ message: 'Service temporarily unavailable' }, 500, this.config.debug);\n      throw new Error(mappedError.message);\n    }\n\n    // Handle wrapped response format from Basis Theory proxy: { body: { tokenIntentId, ... }, headers: ... }\n    if (parsedResponse.body && typeof parsedResponse.body === 'object') {\n      this.log('[CardElement] Unwrapping proxy response body');\n      parsedResponse = parsedResponse.body;\n    }\n\n    // Handle response format: { tokenIntent: { id: \"...\" }, ... } → { tokenIntentId: \"...\" }\n    if (parsedResponse.tokenIntent && parsedResponse.tokenIntent.id) {\n      this.log('[CardElement] Extracting tokenIntentId from tokenIntent.id');\n      return {\n        tokenIntentId: parsedResponse.tokenIntent.id,\n        ...parsedResponse\n      };\n    }\n\n    // Handle direct format: { tokenIntentId: \"...\" }\n    if (parsedResponse.tokenIntentId) {\n      return parsedResponse;\n    }\n\n    // If we got here, the response format is unexpected\n    this.log('[CardElement] Unexpected tokenization response format:', parsedResponse);\n    const mappedError = mapApiError({ message: 'Service temporarily unavailable' }, 500, this.config.debug);\n    throw new Error(mappedError.message);\n  }\n\n  /**\n   * Submit payment to API - simplified\n   * Only sends paymentId + tokenIntentId (billing info already in payment)\n   */\n  private async submitPayment(tokenIntentId: string): Promise<ServerPaymentResponse> {\n    // Generate callback URLs for 3DS flow\n    // These point to API-hosted pages that communicate completion via postMessage\n    const callbackBase = this.getCallbackBaseUrl();\n\n    // SECURITY: URL-encode paymentId to prevent malformed URLs\n    const encodedPaymentId = encodeURIComponent(this.paymentId);\n\n    // Simplified payload matching new SdkConfirmPaymentDto\n    const payload = {\n      paymentId: this.paymentId,    // Payment pre-created with billing info\n      tokenIntentId,                 // Token from Basis Theory\n      threeDsSuccessUrl: `${callbackBase}/success?paymentId=${encodedPaymentId}`,\n      threeDsFailureUrl: `${callbackBase}/failure?paymentId=${encodedPaymentId}`,\n    };\n\n    this.log('[CardElement] Payment payload:', payload);\n\n    const response = await fetch(\n      `${this.config.apiUrl}/sdk/payment/confirm`,\n      {\n        method: 'POST',\n        headers: {\n          'Content-Type': 'application/json',\n          'X-Inflow-Public-Key': this.config.apiKey,\n        },\n        body: JSON.stringify(payload),\n        signal: AbortSignal.timeout(this.config.timeout),\n      }\n    );\n\n    if (!response.ok) {\n      const errorText = await response.text();\n      let errorData: any = {};\n      try {\n        errorData = JSON.parse(errorText);\n      } catch (e) {\n        // Not JSON, will be handled by error mapper\n      }\n\n      // Special handling: If we get an error, check the actual payment status\n      // This helps detect if payment was already processed successfully\n      if (response.status === 400) {\n        this.log('[CardElement] Got 400 error from /confirm, checking actual payment status...');\n        try {\n          const paymentStatus = await this.pollPaymentStatus();\n          this.log('[CardElement] Actual payment status:', paymentStatus);\n\n          // If payment is already in a successful state, return success with alreadyProcessed flag\n          if (this.isSuccessfulStatus(paymentStatus.status)) {\n            this.log('[CardElement] Payment already successful, returning success result with alreadyProcessed flag');\n            return {\n              paymentId: this.paymentId,\n              status: paymentStatus.status,\n              amount: paymentStatus.amount,\n              amountTaxesIncluded: paymentStatus.amountTaxesIncluded,\n              currency: paymentStatus.currency,\n              depositStatus: paymentStatus.depositStatus,\n              alreadyProcessed: true, // Flag to indicate this was a duplicate submission\n            };\n          }\n        } catch (pollError) {\n          this.log('[CardElement] Failed to poll payment status:', pollError);\n          // Continue with original error handling\n        }\n      }\n\n      // Map API error to user-friendly message (this handles your 3DS 424 case!)\n      const mappedError = mapApiError(errorData, response.status, this.config.debug);\n      throw new Error(mappedError.message);\n    }\n\n    return response.json();\n  }\n\n  /**\n   * Poll payment status until we get a final result (success or failure)\n   * Used after 3DS completion\n   */\n  private async pollUntilComplete(): Promise<PaymentResult> {\n    const maxAttempts = 10;\n    const interval = 2000;\n\n    for (let attempt = 1; attempt <= maxAttempts; attempt++) {\n      this.log(`[CardElement] Polling payment status (${attempt}/${maxAttempts})...`);\n\n      try {\n        const payment = await this.pollPaymentStatus();\n\n        // Log full payment data in debug mode\n        this.log(`[CardElement] Payment status response:`, payment);\n\n        // Check for final success states\n        if (this.isSuccessfulStatus(payment.status) || payment.depositStatus === 'succeeded') {\n          return { status: payment.status };\n        }\n\n        // Check for failure states\n        if (this.isFailedStatus(payment.status) || payment.depositStatus === 'failed') {\n          const errorCode = payment.error || payment.lastDepositAttempt?.error || 'PAYMENT_FAILED';\n          return {\n            status: payment.status,\n            error: {\n              code: errorCode,\n              message: mapErrorCode(errorCode),\n              retryable: this.isRetryableErrorCode(errorCode),\n            },\n          };\n        }\n\n        // Check if there's an error in pending/processing states\n        // This handles cases where payment failed but status hasn't updated yet\n        const errorCode = payment.error || payment.lastDepositAttempt?.error;\n        if (errorCode && (payment.status === 'CHECKOUT_PENDING' || payment.status === 'INITIATION')) {\n          this.log('[CardElement] Found error in pending state:', errorCode);\n          return {\n            status: payment.status,\n            error: {\n              code: errorCode,\n              message: mapErrorCode(errorCode),\n              retryable: this.isRetryableErrorCode(errorCode),\n            },\n          };\n        }\n\n        // Still processing, wait and retry\n        if (attempt < maxAttempts) {\n          await new Promise(resolve => setTimeout(resolve, interval));\n        }\n      } catch (error) {\n        this.log('[CardElement] Error polling status:', error);\n\n        if (attempt === maxAttempts) {\n          // Map error to user-friendly message\n          const mappedError = mapException(error, this.config.debug);\n\n          // Override with specific status code handling if available\n          if ((error as any)?.statusCode) {\n            const statusCode = (error as any).statusCode;\n            const apiError = mapApiError({}, statusCode, this.config.debug);\n            return {\n              status: 'PAYMENT_FAILED' as PaymentStatus,\n              error: apiError,\n            };\n          }\n\n          return {\n            status: 'PAYMENT_FAILED' as PaymentStatus,\n            error: mappedError,\n          };\n        }\n      }\n    }\n\n    // Timed out\n    return {\n      status: 'CHECKOUT_PENDING' as PaymentStatus,\n      error: {\n        code: 'PAYMENT_PROCESSING',\n        message: 'Payment is still processing',\n        retryable: false,\n      },\n    };\n  }\n\n  /**\n   * Poll payment status\n   */\n  private async pollPaymentStatus(): Promise<PaymentStatusResponse> {\n    const response = await fetch(\n      `${this.config.apiUrl}/sdk/payment/${this.paymentId}`,\n      {\n        method: 'GET',\n        headers: {\n          'Content-Type': 'application/json',\n          'X-Inflow-Public-Key': this.config.apiKey,\n        },\n        signal: AbortSignal.timeout(this.config.timeout),\n      }\n    );\n\n    if (!response.ok) {\n      const errorText = await response.text();\n      let errorData: any = {};\n      try {\n        errorData = JSON.parse(errorText);\n      } catch (e) {\n        // Not JSON, will be handled by error mapper\n      }\n\n      // Map API error to user-friendly message\n      const mappedError = mapApiError(errorData, response.status, this.config.debug);\n      const error: any = new Error(mappedError.message);\n      error.statusCode = response.status; // Attach status code for better error handling\n      throw error;\n    }\n\n    return response.json();\n  }\n\n  /**\n   * Check if status is successful\n   */\n  private isSuccessfulStatus(status: PaymentStatus): boolean {\n    return ['CHECKOUT_SUCCESS', 'PAYMENT_RECEIVED', 'PAYMENT_SUCCESS'].includes(status);\n  }\n\n  /**\n   * Check if status is failed\n   */\n  private isFailedStatus(status: PaymentStatus): boolean {\n    return ['PAYMENT_FAILED', 'CHECKOUT_CANCELED', 'CANCELED'].includes(status);\n  }\n\n  /**\n   * Check if error code is retryable\n   */\n  private isRetryableErrorCode(errorCode?: string | null): boolean {\n    if (!errorCode) return false;\n\n    const retryableCodes = [\n      'invalid_card_number',\n      'invalid_expiry',\n      'invalid_cvc',\n      'card_declined',\n      'insufficient_funds',\n      'network_error',\n      'INVALID_CARD_NUMBER',\n      'INVALID_EXPIRY',\n      'INVALID_CVC',\n      'CARD_DECLINED',\n      'INSUFFICIENT_FUNDS',\n      'NETWORK_ERROR',\n      // Stripe-specific codes\n      'requires_payment_method',\n      'test_mode_live_card',\n      'generic_decline',\n      'lost_card',\n      'stolen_card',\n      'do_not_honor',\n      'do_not_try_again',\n    ];\n\n    return retryableCodes.includes(errorCode);\n  }\n\n  /**\n   * Get default API URL based on environment\n   */\n  static getDefaultApiUrl(environment: string): string {\n    if (environment === 'production') {\n      return 'https://api.inflowpay.xyz';\n    } else if (environment === 'development') {\n      return 'https://pre-prod.api.inflowpay.xyz';\n    } else {\n      // sandbox (local development)\n      return 'http://localhost:3000';\n    }\n  }\n\n  /**\n   * Get default tokenization proxy URL based on environment\n   */\n  static getDefaultTokenizationProxyUrl(_environment: string): string {\n    // All environments use Basis Theory proxy for tokenization\n    return 'https://api.basistheory.com/proxy';\n  }\n\n  /**\n   * Get default Basis Theory proxy key based on environment and API key\n   */\n  static getDefaultTokenizationProxyKey(environment: string, apiKey?: string): string | undefined {\n    // Check if this is preprod (needs production BT key even though it uses development environment)\n    const isPreprod = apiKey && (apiKey.includes('_preprod_') || apiKey.startsWith('inflow_preprod_'));\n\n    if (environment === 'production' || isPreprod) {\n      // Basis Theory production proxy key for production and preprod\n      return 'key_prod_us_proxy_LfqTJPkDm8p55QtQf3BftJ';\n    } else if (environment === 'development' || environment === 'sandbox') {\n      // Basis Theory dev proxy key for development and local\n      // return 'key_test_us_proxy_9xV4eL5Pn5c9AELTD7LbJf';\n      return 'key_prod_us_proxy_LfqTJPkDm8p55QtQf3BftJ';\n    } else {\n      return undefined;\n    }\n  }\n\n  /**\n   * Get 3DS callback base URL based on environment\n   * Returns API-hosted callback page URLs to prevent 404 errors\n   */\n  private getCallbackBaseUrl(): string {\n    const apiUrl = this.config.apiUrl;\n\n    // Use the API URL and append /threeds path\n    // This ensures callbacks are hosted on the API server\n    return `${apiUrl}/threeds`;\n  }\n\n  /**\n   * Debug logging\n   */\n  private log(message: string, data?: any): void {\n    if (this.config.debug) {\n      if (data !== undefined) {\n        console.log(message, data);\n      } else {\n        console.log(message);\n      }\n    }\n  }\n}","/**\n * UI state management and DOM manipulation for CardElement\n */\n\nimport type { CardElementRenderer } from './renderer';\n\nexport class UIController {\n  private shadowRoot: ShadowRoot;\n\n  constructor(\n    private renderer: CardElementRenderer\n  ) {\n    // Get shadow root from renderer\n    this.shadowRoot = renderer.getShadowRoot();\n  }\n\n  /**\n   * Show or hide error message for a specific field\n   */\n  showError(field: string, message: string | null): void {\n    const errorEl = this.shadowRoot.querySelector(`#error-${field}`) as HTMLElement;\n    if (errorEl) {\n      errorEl.textContent = message || '';\n      errorEl.style.display = message ? 'block' : 'none';\n    }\n  }\n\n  /**\n   * Show general error message\n   */\n  showGeneralError(message: string): void {\n    // Hide success message if showing error\n    this.hideGeneralSuccess();\n\n    const errorEl = this.shadowRoot.querySelector('#general-error') as HTMLElement;\n    const errorText = this.shadowRoot.querySelector('.inflowpay-general-error-text') as HTMLElement;\n    if (errorEl && errorText) {\n      errorText.textContent = message;\n      errorEl.style.display = 'flex';\n    }\n  }\n\n  /**\n   * Show general success message\n   */\n  showGeneralSuccess(message: string): void {\n    // Hide error message if showing success\n    this.hideGeneralError();\n\n    const successEl = this.shadowRoot.querySelector('#general-success') as HTMLElement;\n    const successText = this.shadowRoot.querySelector('.inflowpay-general-success-text') as HTMLElement;\n    if (successEl && successText) {\n      successText.textContent = message;\n      successEl.style.display = 'flex';\n    }\n  }\n\n  /**\n   * Hide general error message\n   */\n  hideGeneralError(): void {\n    const generalError = this.shadowRoot.querySelector('#general-error') as HTMLElement;\n    if (generalError) {\n      generalError.style.display = 'none';\n    }\n  }\n\n  /**\n   * Hide general success message\n   */\n  hideGeneralSuccess(): void {\n    const generalSuccess = this.shadowRoot.querySelector('#general-success') as HTMLElement;\n    if (generalSuccess) {\n      generalSuccess.style.display = 'none';\n    }\n  }\n\n  /**\n   * Clear all error messages\n   */\n  clearErrors(): void {\n    this.showError('card-number', null);\n    this.showError('expiry', null);\n    this.showError('cvc', null);\n    this.hideGeneralError();\n    this.updateButtonState();\n  }\n\n  /**\n   * Clear all messages (errors and success)\n   */\n  clearMessages(): void {\n    this.clearErrors();\n    this.hideGeneralSuccess();\n  }\n\n  /**\n   * Set button loading state\n   */\n  setButtonLoading(loading: boolean): void {\n    const button = this.shadowRoot.querySelector('#inflowpay-submit-btn') as HTMLButtonElement;\n    const text = this.shadowRoot.querySelector('.inflowpay-button-text') as HTMLElement;\n    const loader = this.shadowRoot.querySelector('.inflowpay-button-loader') as HTMLElement;\n\n    if (button && text && loader) {\n      button.disabled = loading;\n      text.style.display = loading ? 'none' : 'inline';\n      loader.style.display = loading ? 'inline-block' : 'none';\n    }\n  }\n\n  /**\n   * Update button disabled state based on field errors and completion\n   * Disables button if any error div has content/is visible OR if fields are incomplete\n   * Respects loading state - won't re-enable if button is in loading state\n   */\n  updateButtonState(): void {\n    const button = this.shadowRoot.querySelector('#inflowpay-submit-btn') as HTMLButtonElement;\n    if (!button) return;\n\n    // Check if button is in loading state (don't override loading state)\n    const loader = this.shadowRoot.querySelector('.inflowpay-button-loader') as HTMLElement;\n    const isLoading = loader && loader.style.display !== 'none';\n    if (isLoading) return;\n\n    // Check if any error div has content and is visible\n    const cardNumberError = this.shadowRoot.querySelector('#error-card-number') as HTMLElement;\n    const expiryError = this.shadowRoot.querySelector('#error-expiry') as HTMLElement;\n    const cvcError = this.shadowRoot.querySelector('#error-cvc') as HTMLElement;\n\n    const hasErrors =\n      (cardNumberError &&\n        cardNumberError.style.display !== 'none' &&\n        cardNumberError.textContent?.trim()) ||\n      (expiryError &&\n        expiryError.style.display !== 'none' &&\n        expiryError.textContent?.trim()) ||\n      (cvcError &&\n        cvcError.style.display !== 'none' &&\n        cvcError.textContent?.trim());\n\n    // Check if all fields are filled\n    const cardNumberInput = this.renderer.getInput('inflowpay-card-number');\n    const expiryInput = this.renderer.getInput('inflowpay-expiry');\n    const cvcInput = this.renderer.getInput('inflowpay-cvc');\n\n    const cardNumber = cardNumberInput?.value.replace(/\\s/g, '') || '';\n    const expiry = expiryInput?.value || '';\n    const cvc = cvcInput?.value || '';\n\n    const isComplete =\n      cardNumber.length > 0 && expiry.length > 0 && cvc.length > 0;\n\n    // Disable button if there are errors OR if fields are incomplete\n    button.disabled = !!hasErrors || !isComplete;\n  }\n\n  /**\n   * Setup event listeners for inputs and button\n   */\n  setupEventListeners(\n    onCardInput: (value: string) => void,\n    onExpiryInput: (value: string) => void,\n    onCvcInput: (value: string) => void,\n    onSubmit: () => void\n  ): void {\n    const cardNumberInput = this.renderer.getInput('inflowpay-card-number');\n    const expiryInput = this.renderer.getInput('inflowpay-expiry');\n    const cvcInput = this.renderer.getInput('inflowpay-cvc');\n    const button = this.renderer.getButton();\n\n    // Track previous card number length to detect completion transition\n    let previousCardLength = 0;\n\n    /**\n     * Card Number Input Handler\n     * Formats as space-separated groups of 4 digits. Auto-advances to expiry when complete (16 digits).\n     */\n    cardNumberInput.addEventListener('input', (e) => {\n      const target = e.target as HTMLInputElement;\n      const value = target.value.replace(/\\s/g, '');\n      const formatted = value.match(/.{1,4}/g)?.join(' ') || value;\n      target.value = formatted;\n      \n      // Auto-advance to expiry when card number becomes complete\n      if (value.length === 16 && previousCardLength < 16) {\n        const expiryValue = expiryInput.value;\n        const expiryIsEmpty = expiryValue.length === 0;\n        const expiryIsIncomplete = expiryValue.length > 0 && expiryValue.length < 5;\n        \n        if (expiryIsEmpty || expiryIsIncomplete) {\n          setTimeout(() => expiryInput.focus(), 50);\n        }\n      }\n      \n      previousCardLength = value.length;\n      onCardInput(target.value);\n      this.updateButtonState();\n    });\n\n    /**\n     * Card Number Keydown Handler\n     * Enter: Submit if valid. Number keys: Auto-advance to next incomplete field (expiry → CVC).\n     */\n    cardNumberInput.addEventListener('keydown', (e) => {\n      // Enter: Submit payment\n      if (e.key === 'Enter') {\n        e.preventDefault();\n        if (!button.disabled) {\n          onSubmit();\n        }\n        return;\n      }\n      \n      // Auto-advance: When complete (16 digits), advance to next incomplete field\n      if (/[0-9]/.test(e.key)) {\n        const currentValue = cardNumberInput.value.replace(/\\s/g, '');\n        const cursorPos = cardNumberInput.selectionStart ?? 0;\n        const isComplete = currentValue.length === 16;\n        const cursorAtEnd = cursorPos >= cardNumberInput.value.length - 1;\n        \n        if (isComplete && cursorAtEnd) {\n          const expiryValue = expiryInput.value;\n          const cvcValue = cvcInput.value;\n          const expiryIsEmpty = expiryValue.length === 0;\n          const expiryIsIncomplete = expiryValue.length > 0 && expiryValue.length < 5;\n          const cvcIsIncomplete = cvcValue.length > 0 && cvcValue.length < 3;\n          const expiryIsComplete = expiryValue.length === 5;\n          \n          // Advance to expiry if incomplete\n          if (expiryIsEmpty || expiryIsIncomplete) {\n            expiryInput.focus();\n            const expiryLength = expiryValue.length;\n            expiryInput.setSelectionRange(expiryLength, expiryLength);\n          } \n          // Advance to CVC if expiry complete but CVC incomplete\n          else if (expiryIsComplete && cvcIsIncomplete) {\n            cvcInput.focus();\n            const cvcLength = cvcValue.length;\n            cvcInput.setSelectionRange(cvcLength, cvcLength);\n          }\n        }\n      }\n    });\n\n    cardNumberInput.addEventListener('keypress', (e) => {\n      if (!/[0-9]/.test(e.key) && e.key !== ' ') {\n        e.preventDefault();\n      }\n    });\n\n    /**\n     * Expiry Input Handler\n     * Formats as MM/YY. Auto-advances to CVC when complete (5 chars).\n     */\n    expiryInput.addEventListener('input', (e) => {\n      const target = e.target as HTMLInputElement;\n      let value = target.value.replace(/\\D/g, '');\n      if (value.length >= 2) {\n        value = value.slice(0, 2) + '/' + value.slice(2, 4);\n      }\n      target.value = value;\n      \n      // Auto-advance to CVC when expiry complete\n      if (value.length === 5) {\n        const cvcValue = cvcInput.value;\n        const cvcIsEmpty = cvcValue.length === 0;\n        const cvcIsIncomplete = cvcValue.length > 0 && cvcValue.length < 3;\n        \n        if (cvcIsEmpty || cvcIsIncomplete) {\n          setTimeout(() => cvcInput.focus(), 50);\n        }\n      }\n      \n      onExpiryInput(target.value);\n      this.updateButtonState();\n    });\n\n    /**\n     * Expiry Keydown Handler\n     * Enter: Submit if valid. Backspace: Handle \"/\" deletion, reverse-advance if empty.\n     * Number keys: Auto-advance to CVC when expiry complete.\n     */\n    expiryInput.addEventListener('keydown', (e) => {\n      // Enter: Submit payment\n      if (e.key === 'Enter') {\n        e.preventDefault();\n        if (!button.disabled) {\n          onSubmit();\n        }\n        return;\n      }\n      \n      // Backspace: Handle \"/\" deletion or reverse-advance\n      if (e.key === 'Backspace') {\n        const target = e.target as HTMLInputElement;\n        const cursorPos = target.selectionStart ?? 0;\n        const value = target.value;\n        \n        // Delete \"/\" and preceding digit when cursor after \"/\"\n        if (cursorPos === 3 && value.length >= 3 && value[2] === '/') {\n          e.preventDefault();\n          const digits = value.replace(/\\D/g, '');\n          if (digits.length > 0) {\n            const newDigits = digits.slice(0, -1);\n            target.value = newDigits.length >= 2 ? `${newDigits.slice(0, 2)}/${newDigits.slice(2, 4)}` : newDigits;\n            target.setSelectionRange(2, 2);\n            onExpiryInput(target.value);\n            this.updateButtonState();\n          }\n          return;\n        }\n        \n        // Reverse-advance to card number if empty\n        if (cursorPos === 0 && value.length === 0) {\n          e.preventDefault();\n          setTimeout(() => cardNumberInput.focus(), 50);\n          return;\n        }\n      }\n      \n      // Auto-advance to CVC when expiry complete\n      if (/[0-9]/.test(e.key)) {\n        const currentValue = expiryInput.value;\n        const cursorPos = expiryInput.selectionStart ?? 0;\n        const isComplete = currentValue.length === 5;\n        const cursorAtEnd = cursorPos >= currentValue.length - 1;\n        \n        if (isComplete && cursorAtEnd) {\n          const cvcValue = cvcInput.value;\n          const cvcIsEmpty = cvcValue.length === 0;\n          const cvcIsIncomplete = cvcValue.length > 0 && cvcValue.length < 3;\n          \n          if (cvcIsEmpty || cvcIsIncomplete) {\n            cvcInput.focus();\n            const cvcLength = cvcValue.length;\n            cvcInput.setSelectionRange(cvcLength, cvcLength);\n          }\n        }\n      }\n    });\n\n    /**\n     * CVC Input Handler\n     * Updates form state on input.\n     */\n    cvcInput.addEventListener('input', (e) => {\n      const target = e.target as HTMLInputElement;\n      const value = target.value;\n      \n      onCvcInput(value);\n      this.updateButtonState();\n    });\n\n    cvcInput.addEventListener('keypress', (e) => {\n      if (!/[0-9]/.test(e.key)) {\n        e.preventDefault();\n      }\n    });\n\n    /**\n     * CVC Keydown Handler\n     * Enter: Submit if valid. Backspace: Reverse-advance to expiry if empty.\n     */\n    cvcInput.addEventListener('keydown', (e) => {\n      // Enter: Submit payment\n      if (e.key === 'Enter') {\n        e.preventDefault();\n        if (!button.disabled) {\n          onSubmit();\n        }\n        return;\n      }\n      \n      // Reverse-advance to expiry if empty\n      if (e.key === 'Backspace' && (e.target as HTMLInputElement).selectionStart === 0 && (e.target as HTMLInputElement).value.length === 0) {\n        e.preventDefault();\n        setTimeout(() => expiryInput.focus(), 50);\n      }\n    });\n\n    // Button click handler\n    button.addEventListener('click', () => {\n      onSubmit();\n    });\n  }\n}\n","/**\n * CardElement - Self-contained card input widget\n *\n * Provides a secure, customizable card input interface that developers\n * can embed in their checkout UI. Handles card collection, validation,\n * tokenization, and payment completion.\n *\n * IMPORTANT: This widget assumes payment was already created with all billing\n * information via the /server/payment endpoint. It only collects card details.\n */\n\nimport type {\n  CardElementOptions,\n  CardElementState,\n  CardData,\n  PaymentResult,\n  PaymentError,\n  SDKConfig,\n  PaymentStatus,\n} from '../types';\nimport type { InternalSDKConfig } from './card-element/types';\nimport { CardElementRenderer } from './card-element/renderer';\nimport { CardValidator } from './card-element/validator';\nimport { PaymentClient } from './card-element/payment-client';\nimport { UIController } from './card-element/ui-controller';\nimport { detectBrowserLocale } from '../i18n';\n\n// Internal options type with required defaults\ntype InternalCardElementOptions = Required<CardElementOptions>;\n\nexport class CardElement {\n  private container: HTMLElement;\n  private options: InternalCardElementOptions;\n  private config: InternalSDKConfig;\n  private state: CardElementState;\n  private mounted: boolean = false;\n\n  // Module instances\n  private renderer: CardElementRenderer;\n  private validator: CardValidator;\n  private paymentClient: PaymentClient;\n  private uiController: UIController;\n\n  constructor(config: SDKConfig & { environment: 'sandbox' | 'production' | 'development' }, options: CardElementOptions) {\n    const environment = config.environment;\n    const locale = config.locale || detectBrowserLocale();\n\n    // Store config for API calls with defaults\n    this.config = {\n      apiKey: config.apiKey,\n      environment,\n      apiUrl: PaymentClient.getDefaultApiUrl(environment),\n      tokenizationProxyUrl: PaymentClient.getDefaultTokenizationProxyUrl(environment),\n      tokenizationProxyKey: PaymentClient.getDefaultTokenizationProxyKey(environment, config.apiKey),\n      timeout: config.timeout || 30000,\n      debug: config.debug || false,\n      locale,\n    };\n\n    // Resolve container\n    let containerElement: HTMLElement | null;\n    if (typeof options.container === 'string') {\n      containerElement = document.querySelector(options.container);\n      if (!containerElement) {\n        throw new Error(`Container not found: ${options.container}`);\n      }\n    } else {\n      containerElement = options.container;\n    }\n    this.container = containerElement;\n\n    // Set defaults\n    this.options = {\n      container: containerElement,\n      paymentId: options.paymentId,\n      style: options.style || {},\n      buttonText: options.buttonText || 'Complete Payment',\n      buttonStyle: options.buttonStyle || {},\n      placeholders: {\n        cardNumber: options.placeholders?.cardNumber || '4242 4242 4242 4242',\n        expiry: options.placeholders?.expiry || 'MM/YY',\n        cvc: options.placeholders?.cvc || 'CVC',\n      },\n      onChange: options.onChange || (() => {}),\n      onComplete: options.onComplete || (() => {}),\n      onError: options.onError || (() => {}),\n    };\n\n    // Initialize state\n    this.state = {\n      complete: false,\n      empty: true,\n      errors: {},\n    };\n\n    // Initialize modules\n    this.renderer = new CardElementRenderer(this.container, this.options, locale);\n    this.validator = new CardValidator();\n    this.paymentClient = new PaymentClient(\n      this.config,\n      this.options.paymentId\n    );\n    this.uiController = new UIController(this.renderer);\n  }\n\n  /**\n   * Mount the element into the DOM\n   */\n  mount(): void {\n    if (this.mounted) {\n      throw new Error('CardElement is already mounted');\n    }\n\n    // Create shadow root first by calling render(), then inject styles\n    this.renderer.render();\n    this.renderer.injectDefaultStyles();\n    this.setupEventListeners();\n    this.applyStyles();\n\n    // Set initial button state (disabled when fields are empty)\n\t\tthis.uiController.updateButtonState();\n    \n    this.mounted = true;\n  }\n\n\n  /**\n   * Submit payment (tokenizes card and confirms payment)\n   * Payment must already be created with billing information\n   */\n  async submit(): Promise<PaymentResult> {\n    this.uiController.clearMessages();\n    this.uiController.setButtonLoading(true);\n\n    try {\n      // Validate card inputs\n      if (!this.state.complete) {\n        const validationError: PaymentError = {\n          code: 'VALIDATION_ERROR',\n          message: 'Please complete all card fields.',\n          retryable: true,\n        };\n        this.options.onError(validationError);\n        this.uiController.showGeneralError(validationError.message);\n        this.uiController.setButtonLoading(false);\n        return { status: 'PAYMENT_FAILED' as PaymentStatus, error: validationError };\n      }\n\n      // Collect card data\n      const cardData: CardData = {\n        number: this.getCardNumber(),\n        expiration_month: this.getExpiryMonth(),\n        expiration_year: this.getExpiryYear(),\n        cvc: this.getCvc(),\n      };\n\n      // Complete payment using payment client\n      const result = await this.paymentClient.completePayment(cardData);\n\n      // Handle errors in the result (from payment client)\n      if (result.error) {\n        this.options.onError(result.error);\n        this.uiController.showGeneralError(result.error.message);\n        this.uiController.setButtonLoading(false);\n        return result;\n      }\n\n      // Success - show success message and trigger callback\n      const successMessage = result.alreadyProcessed\n        ? 'This payment was already processed successfully.'\n        : 'Payment successful!';\n      this.uiController.showGeneralSuccess(successMessage);\n      this.uiController.setButtonLoading(false);\n      this.options.onComplete(result);\n      return result;\n    } catch (error) {\n      // This catch is for unexpected errors (payment client returns PaymentResult, not throws)\n      const paymentError: PaymentError = {\n        code: 'PAYMENT_FAILED',\n        message: error instanceof Error ? error.message : 'Payment failed. Please try again.',\n        retryable: true,\n      };\n\n      this.options.onError(paymentError);\n      this.uiController.showGeneralError(paymentError.message);\n      this.uiController.setButtonLoading(false);\n\n      // Return error result instead of throwing\n      return { status: 'PAYMENT_FAILED' as PaymentStatus, error: paymentError };\n    } finally {\n      this.uiController.setButtonLoading(false);\n    }\n  }\n\n  /**\n   * Destroy the element and clean up\n   */\n  destroy(): void {\n    if (this.mounted) {\n      // Clear shadow root if it exists\n      const shadowRoot = this.container.shadowRoot;\n      if (shadowRoot) {\n        shadowRoot.innerHTML = '';\n      }\n      // Reset renderer's shadow root reference\n      this.renderer.resetShadowRoot();\n      this.mounted = false;\n    }\n  }\n\n  // ============================================================================\n  // Private: Event Handling\n  // ============================================================================\n\n  private setupEventListeners(): void {\n    this.uiController.setupEventListeners(\n      () => this.validateAndUpdate(),\n      () => this.validateAndUpdate(),\n      () => this.validateAndUpdate(),\n      async () => {\n        await this.submit();\n      }\n    );\n  }\n\n  // ============================================================================\n  // Private: Validation\n  // ============================================================================\n\n  private validateAndUpdate(): void {\n    const cardNumber = this.getCardNumber();\n    const expiry = this.renderer.getInput('inflowpay-expiry').value;\n    const cvc = this.getCvc();\n\n    // Hide general error when user starts typing\n    this.uiController.hideGeneralError();\n\n    // Hide general success when user starts typing\n\t\tthis.uiController.hideGeneralSuccess();\n\n    // Validate each field using validator\n    const cardNumberError = this.validator.validateCardNumber(cardNumber);\n    const expiryError = this.validator.validateExpiry(expiry);\n    const cvcError = this.validator.validateCvc(cvc);\n\n    // Update state\n    this.state.errors = {\n      cardNumber: cardNumberError || undefined,\n      expiry: expiryError || undefined,\n      cvc: cvcError || undefined,\n    };\n\n    this.state.empty = !cardNumber && !expiry && !cvc;\n    this.state.complete = !cardNumberError && !expiryError && !cvcError && !this.state.empty;\n\n    // Show only one error at a time (priority: card number > expiry > cvc)\n    // Hide all errors first\n    this.uiController.showError('card-number', null);\n    this.uiController.showError('expiry', null);\n    this.uiController.showError('cvc', null);\n\n    // Show the first error found\n    if (cardNumberError) {\n      this.uiController.showError('card-number', cardNumberError);\n    } else if (expiryError) {\n      this.uiController.showError('expiry', expiryError);\n    } else if (cvcError) {\n      this.uiController.showError('cvc', cvcError);\n    }\n\n    // Update button state based on errors and completion (after validation and error display)\n\t\tthis.uiController.updateButtonState();\n\n    // Trigger onChange callback\n    this.options.onChange(this.state);\n  }\n\n  // ============================================================================\n  // Private: Styling\n  // ============================================================================\n\n  private applyStyles(): void {\n    // Apply custom input styles\n    if (this.options.style) {\n      this.renderer.applyCustomStyles(this.options.style);\n    }\n\n    // Apply custom button styles\n    if (this.options.buttonStyle) {\n      this.renderer.applyButtonStyles(this.options.buttonStyle);\n    }\n  }\n\n  // ============================================================================\n  // Private: Helpers\n  // ============================================================================\n\n  private getCardNumber(): string {\n    return this.renderer.getInput('inflowpay-card-number').value.replace(/\\s/g, '');\n  }\n\n  private getExpiryMonth(): string {\n    const expiry = this.renderer.getInput('inflowpay-expiry').value;\n    return expiry.split('/')[0] || '';\n  }\n\n  private getExpiryYear(): string {\n    const expiry = this.renderer.getInput('inflowpay-expiry').value;\n    const year = expiry.split('/')[1] || '';\n    return year ? '20' + year : '';\n  }\n\n  private getCvc(): string {\n    return this.renderer.getInput('inflowpay-cvc').value;\n  }\n}\n","/**\n * InflowPay Payment SDK\n *\n * Minimal SDK wrapper for CardElement functionality\n */\n\n\nimport type {\n  SDKConfig,\n  CardElementOptions,\n  PaymentStatusResponse,\n} from '../types';\nimport { detectBrowserLocale } from '../i18n';\nimport { CardElement } from '../ui/card-element';\nimport { PaymentClient } from '../ui/card-element/payment-client';\n\nexport class PaymentSDK {\n  private config: SDKConfig & { environment: 'sandbox' | 'production' | 'development'; timeout: number; debug: boolean };\n\n  /**\n   * Initialize the InflowPay Payment SDK\n   *\n   * @param config - SDK configuration options\n   * @param config.apiKey - InflowPay public API key (required, must start with \"inflow_pub_\")\n   * @param config.timeout - Request timeout in milliseconds (defaults to 30000)\n   * @param config.debug - Enable debug logging (defaults to false)\n   *\n   * @throws {Error} If API key is missing or invalid\n   *\n   * @example\n   * ```typescript\n   * // Production environment (auto-detected from key prefix)\n   * const sdk = new PaymentSDK({\n   *   apiKey: 'inflow_pub_prod_xxx'\n   * });\n   *\n   * // Development environment (auto-detected from key prefix)\n   * const sdk = new PaymentSDK({\n   *   apiKey: 'inflow_pub_dev_xxx'\n   * });\n   *\n   * // Sandbox/local development (auto-detected from key prefix)\n   * const sdk = new PaymentSDK({\n   *   apiKey: 'inflow_pub_local_xxx'\n   * });\n   * ```\n   */\n  constructor(config: SDKConfig) {\n    // Validate API key\n    if (!config.apiKey || typeof config.apiKey !== 'string') {\n      throw new Error('API key is required');\n    }\n\n    // Accept production, development, preprod, and local keys\n    if (!config.apiKey.startsWith('inflow_pub_') &&\n      !config.apiKey.startsWith('inflow_local_') &&\n      !config.apiKey.startsWith('inflow_preprod_')) {\n      throw new Error('Invalid API key format. Keys must start with \"inflow_pub_\", \"inflow_preprod_\", or \"inflow_local_\"');\n    }\n\n    // Auto-detect environment from API key prefix\n    // inflow_pub_local_xxx or inflow_local_xxx -> sandbox (localhost)\n    // inflow_pub_dev_xxx or inflow_pub_preprod_xxx -> development (dev/preprod server)\n    // inflow_pub_prod_xxx -> production\n    let environment: 'sandbox' | 'production' | 'development';\n\n    // Check _local_ first to avoid confusion with _dev_ in \"local_dev_\" strings\n    if (config.apiKey.includes('_local_') || config.apiKey.startsWith('inflow_local_')) {\n      environment = 'sandbox';\n    } else if (config.apiKey.includes('_prod_') && !config.apiKey.includes('_preprod_')) {\n      // Check for _prod_ but exclude _preprod_ (which should be dev)\n      environment = 'production';\n    } else if (config.apiKey.includes('_dev_') || config.apiKey.includes('_preprod_') || config.apiKey.startsWith('inflow_preprod_')) {\n      environment = 'development';\n    } else {\n      // Default to sandbox for safety (no real money)\n      environment = 'sandbox';\n    }\n\n    // Set config with defaults\n    this.config = {\n      apiKey: config.apiKey,\n      environment,\n      locale: config.locale || detectBrowserLocale(),\n      timeout: config.timeout || 30000,\n      debug: config.debug || false,\n    };\n\n    this.log('[PaymentSDK] Initialized', {\n      environment: this.config.environment,\n      apiUrl: PaymentClient.getDefaultApiUrl(environment),\n    });\n  }\n\n  /**\n   * Create a CardElement for embedded payment UI\n   *\n   * @param options - CardElement configuration\n   * @returns CardElement instance\n   *\n   * @example\n   * ```typescript\n   * const cardElement = sdk.createCardElement({\n   *   container: '#card-container',\n   *   paymentId: 'pay_123',\n   *   onComplete: (result) => console.log('Payment complete:', result)\n   * });\n   *\n   * cardElement.mount();\n   * ```\n   */\n  createCardElement(options: CardElementOptions): CardElement {\n    return new CardElement(this.config, options);\n  }\n\n  /**\n   * Get the current status of a payment\n   *\n   * Useful for polling payment status after 3DS authentication or\n   * checking the final state of a payment after redirect.\n   *\n   * @param paymentId - The payment ID to check\n   * @returns Payment status information\n   *\n   * @example\n   * ```typescript\n   * // After user returns from 3DS authentication\n   * const status = await sdk.getPaymentStatus('pay_123');\n   *\n   * if (status.status === 'PAYMENT_SUCCESS') {\n   *   console.log('Payment completed!');\n   * } else if (status.status === 'PAYMENT_FAILED') {\n   *   console.log('Payment failed:', status.error);\n   * }\n   * ```\n   */\n  async getPaymentStatus(paymentId: string): Promise<PaymentStatusResponse> {\n    this.log('[PaymentSDK] Checking payment status:', paymentId);\n\n    // Determine the API URL based on environment\n    const apiUrl = PaymentClient.getDefaultApiUrl(this.config.environment);\n\n    const response = await fetch(\n      `${apiUrl}/sdk/payment/${paymentId}`,\n      {\n        method: 'GET',\n        headers: {\n          'Content-Type': 'application/json',\n          'X-Inflow-Public-Key': this.config.apiKey,\n        },\n        signal: AbortSignal.timeout(this.config.timeout),\n      }\n    );\n\n    if (!response.ok) {\n      const errorData = await response.json().catch(() => ({}));\n      throw new Error(errorData.message || 'Failed to get payment status');\n    }\n\n    const data = await response.json();\n    this.log('[PaymentSDK] Payment status:', data);\n    return data;\n  }\n\n  /**\n   * Internal logging (respects debug flag)\n   */\n  private log(message: string, data?: any): void {\n    if (this.config.debug) {\n      if (data !== undefined) {\n        console.log(message, data);\n      } else {\n        console.log(message);\n      }\n    }\n  }\n}"],"names":["SUPPORTED_LOCALES","DEFAULT_LOCALE","DISCLAIMER_TRANSLATIONS","getDisclaimerText","locale","validLocale","isValidLocale","detectBrowserLocale","primaryLang","CardElementRenderer","container","options","shadow","link","fontLink","styleElement","styles","wrap","cardElement","button","inputs","fontFamily","input","htmlWrap","inputStyles","htmlInput","styleId","styleEl","themeStyleEl","cssRules","lightRules","darkRules","theme","isDark","indent","buttonStyles","hoverProps","key","value","cssKey","disabledProps","loaderColor","id","CardValidator","skipLuhnValidation","cleaned","parts","month","year","now","currentYear","currentMonth","cardNumber","sum","isEven","i","digit","ThreeDSModal","challengeUrl","modal","header","content","closeBtn","loadingEl","resolve","event","origin","data","success","iframeUrl","isSuccess","style","url","parsedUrl","domain","ERROR_MESSAGES","DEFAULT_ERROR_MESSAGE","mapApiError","response","statusCode","debugMode","jsonMatch","parsedBody","e","apiError","userMessage","errorCode","normalizedMessage","hasTechnicalJargon","retryable","isRetryableError","sanitizeMessage","mapErrorCode","code","originalMessage","mapException","error","message","technicalTerms","lowerMessage","term","sanitized","PaymentClient","config","paymentId","cardData","tokenResponse","paymentResponse","threeDSSuccess","finalStatus","pollError","maxPolls","pollInterval","attempt","status","headers","errorText","errorData","mappedError","responseText","contentType","parsedResponse","tokenIntentId","callbackBase","encodedPaymentId","payload","paymentStatus","payment","environment","_environment","apiKey","isPreprod","UIController","renderer","field","errorEl","successEl","successText","generalError","generalSuccess","loading","text","loader","cardNumberError","expiryError","cvcError","hasErrors","cardNumberInput","expiryInput","cvcInput","expiry","cvc","isComplete","onCardInput","onExpiryInput","onCvcInput","onSubmit","previousCardLength","target","formatted","expiryValue","expiryIsEmpty","expiryIsIncomplete","currentValue","cursorPos","cursorAtEnd","cvcValue","cvcIsIncomplete","expiryIsComplete","expiryLength","cvcLength","cvcIsEmpty","digits","newDigits","CardElement","containerElement","validationError","result","successMessage","paymentError","shadowRoot","PaymentSDK","apiUrl"],"mappings":"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"}