@moneybar.online/moneybar 10.1.2 → 10.1.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.bundle.js +1 -1
- package/dist/index.bundle.js.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.esm.js +1 -1
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/moneybar-config-template.js +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,"__esModule",{value:!0});var n=require("@supabase/supabase-js");exports.MoneyBar=class{mergeConfigs(n){const t="undefined"!=typeof window?window.APP_CONFIG:null;if(!n&&!t)throw new Error("MoneyBar: No configuration provided. Either pass config to constructor or set window.APP_CONFIG");return n?t?{...t,...n}:n:t}constructor(n){this.currentUser=null,this.userFingerprint=null,this.eventListeners=new Map,this.supabaseConnectionFailed=!1,this.paymentConnectionFailed=!1,this.securityKeyFailed=!1,this.isLoadingStatus=!1,this.validatedAppName=null,this.cachedStatus=null,this.statusCacheTime=0,this.STATUS_CACHE_DURATION=6e4,this.DOWNLOAD_COUNT_CACHE_DURATION=3e4,this.initializationPromise=null,this.cachedPremiumStatus=null,this.premiumStatusCacheTime=0,this.lastCheckedEmail=null,this.lastAuthEmail=null,this.cachedSubscriptionDetails=null,this.cachedDownloadCount=null,this.downloadCountCacheTime=0,this.downloadCountPromise=null,this.premiumCheckPromise=null,this.config=this.mergeConfigs(n),this.config.options,this.validateConfig(),this.initializeSupabase(),this.initializePayment(),this.initializeFingerprint(),this.setupAuthListener(),this.checkPaymentStatus()}async handleDownload(){try{if(this.securityKeyFailed)return void this.showError("Invalid Security Key","Your security key is invalid, expired, or not found. Please check your MoneyBar configuration and ensure you have a valid security_key.");if(this.supabaseConnectionFailed)return void this.config.callbacks?.onError?.(new Error("Server connection required for download verification. Please check your configuration."));if(this.config.payment&&this.paymentConnectionFailed)return void this.config.callbacks?.onError?.(new Error("Payment configuration error. Please contact support."));if(this.currentUser){const{isPremium:n}=await this.checkPremiumStatus(this.currentUser.email);if(n)return void this.config.callbacks?.onPremiumDownload()}const n=await this.getDownloadStatus();if(n.currentCount>=n.limit)return void this.config.callbacks?.onLimitReached(n.currentCount,n.limit);await this.incrementDownloadCount(),this.config.callbacks?.onDownloadAllowed(),this.cachedStatus=null;const t=await this.getDownloadStatus();this.emit("countChanged",{count:t.currentCount,limit:t.limit,remaining:t.remaining}),t.currentCount>=t.limit&&setTimeout(()=>{this.config.callbacks?.onLimitReached(t.currentCount,t.limit)},100)}catch(n){this.handleError(n)}}async getDownloadStatus(n=!1){const t=this.cachedStatus?Date.now()-this.statusCacheTime:-1;if(!n&&this.cachedStatus&&t<this.STATUS_CACHE_DURATION)return this.cachedStatus;if(!n&&this.initializationPromise)return await this.initializationPromise;this.initializationPromise=this.fetchFreshStatus(n);try{return await this.initializationPromise}finally{this.initializationPromise=null}}async fetchFreshStatus(n){try{let t=0,e=!1;if(this.currentUser){const a=null!==this.cachedPremiumStatus&&Date.now()-this.premiumStatusCacheTime<this.STATUS_CACHE_DURATION;if(n||!a){e=(await this.checkPremiumStatus(this.currentUser.email)).isPremium,this.cachedPremiumStatus=e,this.premiumStatusCacheTime=Date.now()}else e=this.cachedPremiumStatus;if(e)console.log("🔍 [OPTIMIZATION] User is premium - skipping download count check"),t=0;else if(n||!this.cachedStatus){if(t=await this.getDownloadCount(),this.securityKeyFailed)return{currentCount:0,limit:this.config.freeAttemptLimit,isPremium:!1,isAuthenticated:!1,remaining:0}}else t=this.cachedStatus.currentCount}else if(e=!1,n||!this.cachedStatus){if(t=await this.getDownloadCount(),this.securityKeyFailed)return{currentCount:0,limit:this.config.freeAttemptLimit,isPremium:!1,isAuthenticated:!1,remaining:0}}else t=this.cachedStatus.currentCount;const a={currentCount:t,limit:this.config.freeAttemptLimit,isPremium:e,isAuthenticated:!!this.currentUser,remaining:Math.max(0,this.config.freeAttemptLimit-t)};return this.cachedStatus=a,this.statusCacheTime=Date.now(),a}catch(n){this.handleError(n);const t={currentCount:0,limit:this.config.freeAttemptLimit,isPremium:!1,isAuthenticated:!1,remaining:this.config.freeAttemptLimit};return this.cachedStatus=t,this.statusCacheTime=Date.now(),t}}async getUserContext(n){const t=n||await this.getDownloadStatus(),e={isPremium:t.isPremium,isAuthenticated:t.isAuthenticated,email:this.currentUser?.email,name:this.currentUser?.user_metadata?.full_name||this.currentUser?.user_metadata?.name,currentCount:t.currentCount,remaining:t.remaining,limit:t.limit,user:this.currentUser};if(this.currentUser&&t.isPremium){const{subscriptionDetails:n}=await this.checkPremiumStatus(this.currentUser.email);n&&(e.subscriptionType=n.subscription_type,e.subscriptionId=n.subscription_id,e.subscriptionExpiresAt=n.subscription_expires_at,e.subscriptionDaysRemaining=n.days_remaining,e.isSubscriptionActive=n.is_subscription_active,e.nextBillingDate=n.next_billing_date,e.billingFrequency=n.billing_frequency,e.customerId=n.customer_id)}return e}async signIn(){try{const{error:n}=await this.supabase.auth.signInWithOAuth({provider:"google",options:{redirectTo:`${window.location.origin}${window.location.pathname}`}});if(n)throw n}catch(n){this.handleError(n)}}async signOut(){try{await this.supabase.auth.signOut(),this.currentUser=null,this.emit("authChanged",{user:null,isAuthenticated:!1,isPremium:!1})}catch(n){this.handleError(n)}}async createPayment(){if(!this.currentUser)throw new Error("User must be signed in to create payment");if(!this.config.payment)throw new Error("Payment configuration not provided");const n=this.config.payment?.find(n=>"dodo"===n.provider);if(!n)throw new Error("No dodo payment provider configured");const t={email:this.currentUser.email,product_id:n.productId,mode:n.mode||"test",app_id:this.validatedAppName||"unknown",return_url:`${window.location.origin}${window.location.pathname}?payment=success`};try{let e;if("dodo"!==n.provider)throw new Error(`Payment provider '${n.provider}' is not yet supported`);if(e=await fetch(`${this.config.supabase.url}/functions/v1/create-payment`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${this.config.supabase.anonKey}`},body:JSON.stringify(t)}),this.config.options,!e.ok){const n=await e.text();let t;this.config.options?.debug&&console.error("🔍 DEBUG: createPayment error response:",n);try{t=JSON.parse(n)}catch{t={error:n}}throw(n.includes("404")||n.includes("could not be found"))&&(this.paymentConnectionFailed=!0,this.config.options?.debug&&console.warn("Invalid payment product ID detected, disabling downloads"),this.updateStatusDisplays()),new Error(t.error||"Payment creation failed")}const a=await e.json();return this.config.options,a}catch(n){return this.handleError(n),null}}async openCustomerPortal(n){try{if(!this.config.payment)throw new Error("Payment configuration not provided");const t=this.config.payment?.find(n=>"dodo"===n.provider);if(!t)throw new Error("No dodo payment provider configured");const e={customer_id:n,mode:t.mode||"test"},a=await fetch(`${this.config.supabase.url}/functions/v1/create-customer-portal`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${this.config.supabase.anonKey}`},body:JSON.stringify(e)});if(!a.ok){const n=await a.json().catch(()=>({error:"Unknown error"}));throw new Error(n.error||"Failed to create customer portal session")}const o=await a.json();o.link&&window.open(o.link,"_blank")}catch(n){console.error("Failed to open customer portal:",n),this.handleError(n)}}attachToButton(n,t){const e=document.querySelector(n);if(!e)throw new Error(`Button not found: ${n}`);this.injectBaseStyles(),this.createTitleBar(),this.createPaywallModal(),this.createSuccessModal(),this.createAuthUI(),this.createStatusDisplay(),e.setAttribute("data-leadfast-attached","true"),e.onclick=async n=>{n.preventDefault(),await this.handleButtonClick(t)},this.setupUIUpdates()}attachToButtons(n){this.injectBaseStyles(),this.createTitleBar(),this.createPaywallModal(),this.createSuccessModal(),this.createAuthUI(),n.buttons.forEach(n=>{const t=document.querySelector(n.selector);t?(t.setAttribute("data-leadfast-attached","true"),t.onclick=async t=>{t.preventDefault(),await this.handleButtonClick(n.downloadCallback)},this.setupUIUpdates()):console.warn(`Button not found: ${n.selector}`)}),this.createGlobalStatusDisplay()}async handleButtonClick(n){const t=document.querySelectorAll('[data-leadfast-attached="true"]');if(Array.from(t).some(n=>n.disabled))console.log("⚠️ Button click ignored - operation already in progress");else{t.forEach(n=>{n.disabled=!0,n.style.opacity="0.6"});try{await this.handleButtonClickInternal(n)}finally{t.forEach(n=>{n.disabled=!1,n.style.opacity="1"})}}}async handleButtonClickInternal(n){if(this.supabaseConnectionFailed)return void this.showConnectionError();if(this.config.payment&&this.paymentConnectionFailed)return void this.showPaymentConfigError();const t=this.cachedStatus&&Date.now()-this.statusCacheTime<this.STATUS_CACHE_DURATION?this.cachedStatus:await this.getDownloadStatus();if(t.isPremium){const t=await this.getUserContext();return void(n.length>0?n(t):n())}if(t.currentCount>=t.limit)this.showPaywallInstant(t);else{try{if(n.length>0){const t=n(await this.getUserContext());t&&"object"==typeof t&&"then"in t&&await t}else{const t=n();t&&"object"==typeof t&&"then"in t&&await t}const t=await this.getDownloadStatus(!0);if(t.currentCount>=t.limit)return console.warn(`⚠️ Limit reached during execution (${t.currentCount}/${t.limit}) - canceling increment`),void alert("⚠️ You reached the limit while this action was processing. No attempt was counted.");const e=await this.incrementDownloadCount();if(e>this.config.freeAttemptLimit)return void console.error(`⚠️ Server returned count (${e}) exceeding limit (${this.config.freeAttemptLimit})`);if(!0===this.config.successMessage?.enabled){const n=this.config.successMessage?.title||"Action Completed!",t=this.config.successMessage?.message||"Your action completed successfully!";this.showSuccess(n,t)}}catch(n){return console.error("User function failed:",n),void alert("Action failed. Please check the console for details. No attempt was counted.")}this.cachedStatus=null,this.updateStatusDisplays()}}injectBaseStyles(){if(document.getElementById("lead-fast-styles"))return;this.config.theme?.name&&this.injectDaisyUI();const n=document.createElement("style");n.id="lead-fast-styles";const t=this.config.theme?.primaryColor||"#3182ce";n.textContent=`\n /* User Profile Card - Top Right */\n .lead-fast-profile {\n position: fixed;\n top: 20px;\n left: 50%;\n transform: translateX(-50%);\n z-index: 1000;\n font-family: system-ui, -apple-system, sans-serif;\n width: 90%;\n max-width: 1200px;\n }\n\n .lead-fast-title-bar {\n background: rgba(250, 247, 245, 0.9) !important;\n border: 1px solid rgba(231, 226, 223, 0.6) !important;\n color: #291334 !important;\n border-radius: 16px;\n padding: 12px 24px;\n box-shadow: 0 8px 32px rgb(0 0 0 / 0.1), 0 2px 8px rgb(0 0 0 / 0.05);\n backdrop-filter: blur(20px);\n display: flex;\n align-items: center;\n justify-content: space-between;\n min-height: 60px;\n font-family: system-ui, -apple-system, sans-serif;\n }\n\n /* Theme variations for floating title bar */\n [data-theme="bumblebee"] .lead-fast-title-bar {\n background: rgba(255, 248, 220, 0.9) !important;\n border-color: rgba(254, 215, 170, 0.6) !important;\n color: #1c1917 !important;\n }\n\n [data-theme="garden"] .lead-fast-title-bar {\n background: rgba(240, 253, 244, 0.9) !important;\n border-color: rgba(134, 239, 172, 0.6) !important;\n color: #14532d !important;\n }\n\n [data-theme="emerald"] .lead-fast-title-bar {\n background: rgba(236, 253, 245, 0.9) !important;\n border-color: rgba(167, 243, 208, 0.6) !important;\n color: #065f46 !important;\n }\n\n [data-theme="corporate"] .lead-fast-title-bar {\n background: rgba(248, 250, 252, 0.9) !important;\n border-color: rgba(226, 232, 240, 0.6) !important;\n color: #1e293b !important;\n }\n\n [data-theme="dark"] .lead-fast-title-bar {\n background: rgba(31, 41, 55, 0.9) !important;\n border-color: rgba(55, 65, 81, 0.6) !important;\n color: #f9fafb !important;\n }\n\n [data-theme="cyberpunk"] .lead-fast-title-bar {\n background: rgba(0, 20, 36, 0.9) !important;\n border-color: rgba(7, 89, 133, 0.6) !important;\n color: #0ea5e9 !important;\n box-shadow: 0 8px 32px rgba(14, 165, 233, 0.2), 0 2px 8px rgba(14, 165, 233, 0.1);\n }\n\n [data-theme="valentine"] .lead-fast-title-bar {\n background: rgba(233, 30, 122, 0.15) !important;\n border-color: rgba(233, 30, 122, 0.6) !important;\n color: #831843 !important;\n }\n\n [data-theme="synthwave"] .lead-fast-title-bar {\n background: rgba(32, 20, 64, 0.9) !important;\n border-color: rgba(186, 85, 211, 0.6) !important;\n color: #ff00ff !important;\n box-shadow: 0 8px 32px rgba(255, 0, 255, 0.2), 0 2px 8px rgba(255, 0, 255, 0.1);\n }\n\n [data-theme="dracula"] .lead-fast-title-bar {\n background: rgba(40, 42, 54, 0.9) !important;\n border-color: rgba(98, 114, 164, 0.6) !important;\n color: #f8f8f2 !important;\n }\n\n [data-theme="halloween"] .lead-fast-title-bar {\n background: rgba(26, 26, 26, 0.9) !important;\n border-color: rgba(255, 165, 0, 0.6) !important;\n color: #ff6600 !important;\n }\n\n [data-theme="forest"] .lead-fast-title-bar {\n background: rgba(23, 46, 23, 0.9) !important;\n border-color: rgba(34, 197, 94, 0.6) !important;\n color: #22c55e !important;\n }\n\n [data-theme="luxury"] .lead-fast-title-bar {\n background: rgba(9, 9, 11, 0.9) !important;\n border-color: rgba(212, 175, 55, 0.6) !important;\n color: #d4af37 !important;\n }\n\n [data-theme="night"] .lead-fast-title-bar {\n background: rgba(15, 23, 42, 0.9) !important;\n border-color: rgba(30, 58, 138, 0.6) !important;\n color: #60a5fa !important;\n }\n\n [data-theme="light"] .lead-fast-title-bar {\n background: rgba(255, 255, 255, 0.9) !important;\n border-color: rgba(229, 231, 235, 0.6) !important;\n color: #1f2937 !important;\n }\n\n [data-theme="cupcake"] .lead-fast-title-bar {\n background: rgba(250, 235, 215, 0.9) !important;\n border-color: rgba(219, 185, 156, 0.6) !important;\n color: #8b4513 !important;\n }\n\n [data-theme="retro"] .lead-fast-title-bar {\n background: rgba(212, 165, 116, 0.9) !important;\n border-color: rgba(185, 144, 102, 0.6) !important;\n color: #5d4037 !important;\n }\n\n [data-theme="aqua"] .lead-fast-title-bar {\n background: rgba(240, 253, 250, 0.9) !important;\n border-color: rgba(125, 211, 252, 0.6) !important;\n color: #155e75 !important;\n }\n\n [data-theme="lofi"] .lead-fast-title-bar {\n background: rgba(248, 248, 248, 0.9) !important;\n border-color: rgba(68, 68, 68, 0.6) !important;\n color: #1a1a1a !important;\n }\n\n [data-theme="pastel"] .lead-fast-title-bar {\n background: rgba(254, 251, 255, 0.9) !important;\n border-color: rgba(209, 196, 233, 0.6) !important;\n color: #7c3aed !important;\n }\n\n [data-theme="fantasy"] .lead-fast-title-bar {\n background: rgba(255, 247, 237, 0.9) !important;\n border-color: rgba(249, 168, 212, 0.6) !important;\n color: #be185d !important;\n }\n\n [data-theme="wireframe"] .lead-fast-title-bar {\n background: rgba(223, 223, 223, 0.9) !important;\n border-color: rgba(0, 0, 0, 0.3) !important;\n color: #000000 !important;\n }\n\n [data-theme="black"] .lead-fast-title-bar {\n background: rgba(0, 0, 0, 0.9) !important;\n border-color: rgba(55, 55, 55, 0.6) !important;\n color: #ffffff !important;\n }\n\n [data-theme="cmyk"] .lead-fast-title-bar {\n background: rgba(0, 255, 255, 0.9) !important;\n border-color: rgba(255, 0, 255, 0.6) !important;\n color: #000000 !important;\n }\n\n [data-theme="autumn"] .lead-fast-title-bar {\n background: rgba(139, 69, 19, 0.9) !important;\n border-color: rgba(255, 140, 0, 0.6) !important;\n color: #ff8c00 !important;\n }\n\n [data-theme="business"] .lead-fast-title-bar {\n background: rgba(29, 78, 216, 0.9) !important;\n border-color: rgba(59, 130, 246, 0.6) !important;\n color: #3b82f6 !important;\n }\n\n [data-theme="acid"] .lead-fast-title-bar {\n background: rgba(255, 255, 0, 0.9) !important;\n border-color: rgba(255, 0, 255, 0.6) !important;\n color: #000000 !important;\n }\n\n [data-theme="lemonade"] .lead-fast-title-bar {\n background: rgba(255, 255, 224, 0.9) !important;\n border-color: rgba(34, 197, 94, 0.6) !important;\n color: #15803d !important;\n }\n\n [data-theme="coffee"] .lead-fast-title-bar {\n background: rgba(101, 67, 33, 0.9) !important;\n border-color: rgba(160, 82, 45, 0.6) !important;\n color: #d2b48c !important;\n }\n\n [data-theme="winter"] .lead-fast-title-bar {\n background: rgba(248, 250, 252, 0.9) !important;\n border-color: rgba(59, 130, 246, 0.6) !important;\n color: #1e40af !important;\n }\n\n .lead-fast-title-section {\n display: flex;\n align-items: center;\n gap: 16px;\n }\n\n .lead-fast-logo {\n font-size: 20px;\n font-weight: 700;\n display: flex;\n align-items: center;\n gap: 8px;\n color: inherit;\n text-decoration: none;\n }\n\n .lead-fast-logo img {\n width: 32px;\n height: 32px;\n border-radius: 6px;\n }\n\n .lead-fast-nav {\n display: flex;\n align-items: center;\n gap: 32px;\n margin-left: 24px;\n }\n\n .lead-fast-nav-link {\n color: inherit;\n text-decoration: none;\n font-weight: 500;\n font-size: 14px;\n opacity: 0.8;\n transition: all 0.2s;\n }\n\n .lead-fast-nav-link:hover {\n opacity: 1;\n text-decoration: none;\n }\n\n .lead-fast-user-section {\n display: flex;\n align-items: center;\n gap: 12px;\n }\n\n .lead-fast-avatar {\n width: 36px;\n height: 36px;\n border-radius: 50%;\n background: linear-gradient(135deg, ${t}, #4f46e5);\n display: flex;\n align-items: center;\n justify-content: center;\n color: white;\n font-weight: 600;\n font-size: 14px;\n }\n\n .lead-fast-user-info {\n display: flex;\n flex-direction: column;\n align-items: flex-start;\n gap: 2px;\n }\n\n .lead-fast-user-email {\n color: inherit !important;\n font-size: 13px;\n font-weight: 500;\n line-height: 1;\n }\n\n .lead-fast-user-status {\n display: flex;\n align-items: center;\n gap: 6px;\n }\n\n .lead-fast-badge {\n padding: 2px 6px;\n border-radius: 12px;\n font-size: 10px;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.025em;\n line-height: 1;\n }\n\n .lead-fast-badge.premium {\n background: #10b981 !important;\n color: #ffffff !important;\n }\n\n .lead-fast-badge.free {\n background: #65c3c8 !important;\n color: #291334 !important;\n }\n\n [data-theme="dark"] .lead-fast-badge.premium {\n background: #059669 !important;\n color: #ffffff !important;\n }\n\n [data-theme="dark"] .lead-fast-badge.free {\n background: #374151 !important;\n color: #f9fafb !important;\n }\n\n .lead-fast-info-icon {\n display: inline-block;\n margin-left: 3px;\n font-size: 11px;\n opacity: 0.8;\n cursor: help;\n transition: opacity 0.2s;\n }\n\n .lead-fast-info-icon:hover {\n opacity: 1;\n }\n\n /* Subscription Tooltip */\n .lead-fast-subscription-tooltip {\n position: fixed;\n z-index: 10000;\n background: rgba(0, 0, 0, 0.92);\n border-radius: 8px;\n padding: 0;\n box-shadow: 0 8px 24px rgba(0, 0, 0, 0.3);\n min-width: 260px;\n opacity: 0;\n pointer-events: none;\n transform: translateY(-5px);\n transition: opacity 0.2s, transform 0.2s;\n }\n\n .lead-fast-subscription-tooltip.show {\n opacity: 1;\n pointer-events: auto;\n transform: translateY(0);\n }\n\n .lead-fast-subscription-tooltip .tooltip-content {\n padding: 12px 16px;\n }\n\n .lead-fast-subscription-tooltip .tooltip-header {\n font-size: 13px;\n font-weight: 600;\n color: #fff;\n margin-bottom: 8px;\n }\n\n .lead-fast-subscription-tooltip .tooltip-divider {\n height: 1px;\n background: rgba(255, 255, 255, 0.1);\n margin: 8px 0;\n }\n\n .lead-fast-subscription-tooltip .tooltip-row {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 6px 0;\n font-size: 12px;\n }\n\n .lead-fast-subscription-tooltip .tooltip-label {\n color: rgba(255, 255, 255, 0.7);\n font-weight: 500;\n }\n\n .lead-fast-subscription-tooltip .tooltip-value {\n color: #fff;\n font-weight: 600;\n text-align: right;\n }\n\n .lead-fast-subscription-tooltip .tooltip-link {\n display: block;\n text-align: center;\n margin-top: 12px;\n padding-top: 12px;\n border-top: 1px solid rgba(255, 255, 255, 0.1);\n }\n\n .lead-fast-subscription-tooltip .manage-link {\n color: #60a5fa;\n text-decoration: none;\n font-size: 12px;\n font-weight: 500;\n cursor: pointer;\n transition: color 0.2s;\n }\n\n .lead-fast-subscription-tooltip .manage-link:hover {\n color: #93c5fd;\n text-decoration: underline;\n }\n\n .lead-fast-count {\n font-size: 10px;\n color: inherit !important;\n opacity: 0.7;\n line-height: 1;\n }\n\n .lead-fast-signout {\n background: rgba(0, 0, 0, 0.1) !important;\n border: none;\n color: inherit !important;\n cursor: pointer;\n padding: 6px 12px;\n border-radius: 8px;\n transition: all 0.2s;\n font-size: 11px;\n font-weight: 500;\n margin-left: 8px;\n }\n\n [data-theme="dark"] .lead-fast-signout {\n background: rgba(255, 255, 255, 0.1) !important;\n }\n\n [data-theme="cyberpunk"] .lead-fast-signout {\n background: rgba(14, 165, 233, 0.2) !important;\n }\n\n .lead-fast-signout:hover {\n background: rgba(0, 0, 0, 0.2) !important;\n transform: translateY(-1px);\n }\n\n [data-theme="dark"] .lead-fast-signout:hover {\n background: rgba(255, 255, 255, 0.2) !important;\n }\n\n [data-theme="cyberpunk"] .lead-fast-signout:hover {\n background: rgba(14, 165, 233, 0.3) !important;\n }\n\n .lead-fast-branding {\n position: absolute;\n bottom: -20px;\n left: 24px;\n font-size: 9px;\n color: inherit !important;\n opacity: 0.4;\n font-weight: 500;\n letter-spacing: 0.05em;\n text-transform: lowercase;\n background: rgba(255, 255, 255, 0.8);\n padding: 2px 6px;\n border-radius: 4px;\n backdrop-filter: blur(8px);\n }\n\n [data-theme="dark"] .lead-fast-branding {\n background: rgba(0, 0, 0, 0.6);\n }\n\n [data-theme="cyberpunk"] .lead-fast-branding {\n background: rgba(0, 20, 36, 0.8);\n }\n\n /* Modal Theming */\n .download-limiter-modal {\n display: none;\n position: fixed;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n background: rgba(0,0,0,0.5);\n z-index: 9999;\n align-items: center;\n justify-content: center;\n }\n .download-limiter-modal.show { display: flex; }\n\n .download-limiter-content {\n background: #faf7f5 !important;\n color: #291334 !important;\n padding: 2rem;\n border-radius: 12px;\n max-width: 400px;\n text-align: center;\n box-shadow: 0 20px 25px -5px rgb(0 0 0 / 0.1), 0 8px 10px -6px rgb(0 0 0 / 0.1);\n border: 1px solid #e7e2df !important;\n font-family: system-ui, -apple-system, sans-serif;\n }\n\n [data-theme="dark"] .download-limiter-content {\n background: #1f2937 !important;\n color: #f9fafb !important;\n border-color: #374151 !important;\n }\n\n [data-theme="cyberpunk"] .download-limiter-content {\n background: #001424 !important;\n color: #0ea5e9 !important;\n border-color: #075985 !important;\n }\n\n [data-theme="valentine"] .download-limiter-content {\n background: rgba(233, 30, 122, 0.05) !important;\n color: #831843 !important;\n border-color: #e91e7a !important;\n }\n\n [data-theme="bumblebee"] .download-limiter-content {\n background: rgba(255, 248, 220, 0.95) !important;\n color: #1c1917 !important;\n border-color: rgba(254, 215, 170, 0.8) !important;\n }\n\n [data-theme="garden"] .download-limiter-content {\n background: rgba(240, 253, 244, 0.95) !important;\n color: #14532d !important;\n border-color: rgba(134, 239, 172, 0.8) !important;\n }\n\n [data-theme="emerald"] .download-limiter-content {\n background: rgba(236, 253, 245, 0.95) !important;\n color: #065f46 !important;\n border-color: rgba(167, 243, 208, 0.8) !important;\n }\n\n [data-theme="corporate"] .download-limiter-content {\n background: rgba(248, 250, 252, 0.95) !important;\n color: #1e293b !important;\n border-color: rgba(226, 232, 240, 0.8) !important;\n }\n\n [data-theme="forest"] .download-limiter-content {\n background: rgba(23, 46, 23, 0.95) !important;\n color: #22c55e !important;\n border-color: rgba(34, 197, 94, 0.8) !important;\n }\n\n [data-theme="halloween"] .download-limiter-content {\n background: rgba(26, 26, 26, 0.95) !important;\n color: #ff6500 !important;\n border-color: rgba(255, 165, 0, 0.3) !important;\n }\n\n [data-theme="synthwave"] .download-limiter-content {\n background: rgba(32, 20, 64, 0.95) !important;\n color: #ba55d3 !important;\n border-color: rgba(186, 85, 211, 0.3) !important;\n }\n\n [data-theme="dracula"] .download-limiter-content {\n background: rgba(40, 42, 54, 0.95) !important;\n color: #f8f8f2 !important;\n border-color: rgba(98, 114, 164, 0.3) !important;\n }\n\n [data-theme="luxury"] .download-limiter-content {\n background: rgba(9, 9, 11, 0.95) !important;\n color: #d4af37 !important;\n border-color: rgba(212, 175, 55, 0.3) !important;\n }\n\n [data-theme="night"] .download-limiter-content {\n background: rgba(15, 23, 42, 0.95) !important;\n color: #1e40af !important;\n border-color: rgba(30, 58, 138, 0.3) !important;\n }\n\n [data-theme="light"] .download-limiter-content {\n background: rgba(255, 255, 255, 0.95) !important;\n color: #1f2937 !important;\n border-color: rgba(229, 231, 235, 0.8) !important;\n }\n\n [data-theme="cupcake"] .download-limiter-content {\n background: rgba(250, 235, 215, 0.95) !important;\n color: #8b4513 !important;\n border-color: rgba(219, 185, 156, 0.8) !important;\n }\n\n [data-theme="retro"] .download-limiter-content {\n background: rgba(212, 165, 116, 0.95) !important;\n color: #5d4037 !important;\n border-color: rgba(185, 144, 102, 0.8) !important;\n }\n\n [data-theme="aqua"] .download-limiter-content {\n background: rgba(240, 253, 250, 0.95) !important;\n color: #155e75 !important;\n border-color: rgba(125, 211, 252, 0.8) !important;\n }\n\n [data-theme="lofi"] .download-limiter-content {\n background: rgba(248, 248, 248, 0.95) !important;\n color: #1a1a1a !important;\n border-color: rgba(68, 68, 68, 0.8) !important;\n }\n\n [data-theme="pastel"] .download-limiter-content {\n background: rgba(254, 251, 255, 0.95) !important;\n color: #7c3aed !important;\n border-color: rgba(209, 196, 233, 0.8) !important;\n }\n\n [data-theme="fantasy"] .download-limiter-content {\n background: rgba(255, 247, 237, 0.95) !important;\n color: #be185d !important;\n border-color: rgba(249, 168, 212, 0.8) !important;\n }\n\n [data-theme="wireframe"] .download-limiter-content {\n background: rgba(255, 255, 255, 0.95) !important;\n color: #000000 !important;\n border-color: rgba(0, 0, 0, 0.3) !important;\n }\n\n [data-theme="black"] .download-limiter-content {\n background: rgba(0, 0, 0, 0.95) !important;\n color: #ffffff !important;\n border-color: rgba(55, 55, 55, 0.8) !important;\n }\n\n [data-theme="cmyk"] .download-limiter-content {\n background: rgba(0, 255, 255, 0.95) !important;\n color: #000000 !important;\n border-color: rgba(255, 0, 255, 0.8) !important;\n }\n\n [data-theme="autumn"] .download-limiter-content {\n background: rgba(139, 69, 19, 0.95) !important;\n color: #ff8c00 !important;\n border-color: rgba(255, 140, 0, 0.8) !important;\n }\n\n [data-theme="business"] .download-limiter-content {\n background: rgba(29, 78, 216, 0.95) !important;\n color: #3b82f6 !important;\n border-color: rgba(59, 130, 246, 0.8) !important;\n }\n\n [data-theme="acid"] .download-limiter-content {\n background: rgba(255, 255, 0, 0.95) !important;\n color: #000000 !important;\n border-color: rgba(255, 0, 255, 0.8) !important;\n }\n\n [data-theme="lemonade"] .download-limiter-content {\n background: rgba(255, 255, 224, 0.95) !important;\n color: #15803d !important;\n border-color: rgba(34, 197, 94, 0.8) !important;\n }\n\n [data-theme="coffee"] .download-limiter-content {\n background: rgba(101, 67, 33, 0.95) !important;\n color: #d2b48c !important;\n border-color: rgba(160, 82, 45, 0.8) !important;\n }\n\n [data-theme="winter"] .download-limiter-content {\n background: rgba(248, 250, 252, 0.95) !important;\n color: #1e40af !important;\n border-color: rgba(59, 130, 246, 0.8) !important;\n }\n\n .download-limiter-content h2 {\n color: inherit !important;\n margin: 0 0 1rem 0;\n font-size: 1.5rem;\n font-weight: 600;\n }\n .download-limiter-content p {\n color: inherit !important;\n margin: 0 0 1.5rem 0;\n line-height: 1.6;\n }\n .download-limiter-signin-btn {\n display: inline-flex;\n align-items: center;\n gap: 8px;\n background: #65c3c8 !important;\n color: #291334 !important;\n border: none;\n padding: 12px 20px;\n border-radius: 8px;\n font-size: 14px;\n font-weight: 500;\n cursor: pointer;\n text-decoration: none;\n transition: all 0.2s;\n box-shadow: 0 2px 4px rgba(0,0,0,0.1);\n }\n\n [data-theme="dark"] .download-limiter-signin-btn {\n background: #3b82f6 !important;\n color: #ffffff !important;\n }\n\n [data-theme="cyberpunk"] .download-limiter-signin-btn {\n background: #f59e0b !important;\n color: #000000 !important;\n }\n\n [data-theme="valentine"] .download-limiter-signin-btn {\n background: #e91e7a !important;\n color: #ffffff !important;\n }\n\n [data-theme="bumblebee"] .download-limiter-signin-btn {\n background: #fbbf24 !important;\n color: #1c1917 !important;\n }\n\n [data-theme="garden"] .download-limiter-signin-btn {\n background: #22c55e !important;\n color: #ffffff !important;\n }\n\n [data-theme="emerald"] .download-limiter-signin-btn {\n background: #10b981 !important;\n color: #ffffff !important;\n }\n\n [data-theme="corporate"] .download-limiter-signin-btn {\n background: #3b82f6 !important;\n color: #ffffff !important;\n }\n\n [data-theme="forest"] .download-limiter-signin-btn {\n background: #22c55e !important;\n color: #1a1a1a !important;\n }\n\n [data-theme="halloween"] .download-limiter-signin-btn {\n background: #ff6500 !important;\n color: #1a1a1a !important;\n }\n\n [data-theme="synthwave"] .download-limiter-signin-btn {\n background: #ba55d3 !important;\n color: #201040 !important;\n }\n\n [data-theme="dracula"] .download-limiter-signin-btn {\n background: #8be9fd !important;\n color: #282a36 !important;\n }\n\n [data-theme="luxury"] .download-limiter-signin-btn {\n background: #d4af37 !important;\n color: #09090b !important;\n }\n\n [data-theme="night"] .download-limiter-signin-btn {\n background: #1e40af !important;\n color: #ffffff !important;\n }\n\n [data-theme="light"] .download-limiter-signin-btn {\n background: #3b82f6 !important;\n color: #ffffff !important;\n }\n\n [data-theme="cupcake"] .download-limiter-signin-btn {\n background: #8b4513 !important;\n color: #ffffff !important;\n }\n\n [data-theme="retro"] .download-limiter-signin-btn {\n background: #d4a574 !important;\n color: #ffffff !important;\n }\n\n [data-theme="aqua"] .download-limiter-signin-btn {\n background: #0891b2 !important;\n color: #ffffff !important;\n }\n\n [data-theme="lofi"] .download-limiter-signin-btn {\n background: #1a1a1a !important;\n color: #ffffff !important;\n }\n\n [data-theme="pastel"] .download-limiter-signin-btn {\n background: #7c3aed !important;\n color: #ffffff !important;\n }\n\n [data-theme="fantasy"] .download-limiter-signin-btn {\n background: #be185d !important;\n color: #ffffff !important;\n }\n\n [data-theme="wireframe"] .download-limiter-signin-btn {\n background: #dfdfdf !important;\n color: #000000 !important;\n border: 1px solid #000000 !important;\n }\n\n [data-theme="black"] .download-limiter-signin-btn {\n background: #ffffff !important;\n color: #000000 !important;\n }\n\n [data-theme="cmyk"] .download-limiter-signin-btn {\n background: #ff00ff !important;\n color: #000000 !important;\n }\n\n [data-theme="autumn"] .download-limiter-signin-btn {\n background: #ff8c00 !important;\n color: #ffffff !important;\n }\n\n [data-theme="business"] .download-limiter-signin-btn {\n background: #3b82f6 !important;\n color: #ffffff !important;\n }\n\n [data-theme="acid"] .download-limiter-signin-btn {\n background: #ff00ff !important;\n color: #000000 !important;\n }\n\n [data-theme="lemonade"] .download-limiter-signin-btn {\n background: #22c55e !important;\n color: #ffffff !important;\n }\n\n [data-theme="coffee"] .download-limiter-signin-btn {\n background: #a0522d !important;\n color: #ffffff !important;\n }\n\n [data-theme="winter"] .download-limiter-signin-btn {\n background: #3b82f6 !important;\n color: #ffffff !important;\n }\n\n .download-limiter-signin-btn:hover {\n opacity: 0.9;\n transform: translateY(-1px);\n box-shadow: 0 4px 8px rgba(0,0,0,0.15);\n }\n\n /* Upgrade Button Styles for All Themes */\n [data-theme="dark"] .upgrade-btn {\n background: #3b82f6 !important;\n color: #ffffff !important;\n }\n\n [data-theme="cyberpunk"] .upgrade-btn {\n background: #ff073a !important;\n color: #ffffff !important;\n }\n\n [data-theme="valentine"] .upgrade-btn {\n background: #e91e7a !important;\n color: #ffffff !important;\n }\n\n [data-theme="bumblebee"] .upgrade-btn {\n background: #f59e0b !important;\n color: #ffffff !important;\n }\n\n [data-theme="garden"] .upgrade-btn {\n background: #10b981 !important;\n color: #ffffff !important;\n }\n\n [data-theme="emerald"] .upgrade-btn {\n background: #10b981 !important;\n color: #ffffff !important;\n }\n\n [data-theme="corporate"] .upgrade-btn {\n background: #3b82f6 !important;\n color: #ffffff !important;\n }\n\n [data-theme="forest"] .upgrade-btn {\n background: #10b981 !important;\n color: #ffffff !important;\n }\n\n [data-theme="halloween"] .upgrade-btn {\n background: #ff7b00 !important;\n color: #000000 !important;\n }\n\n [data-theme="synthwave"] .upgrade-btn {\n background: #e879f9 !important;\n color: #ffffff !important;\n }\n\n [data-theme="dracula"] .upgrade-btn {\n background: #bd93f9 !important;\n color: #ffffff !important;\n }\n\n [data-theme="luxury"] .upgrade-btn {\n background: #d4af37 !important;\n color: #000000 !important;\n }\n\n [data-theme="night"] .upgrade-btn {\n background: #38bdf8 !important;\n color: #ffffff !important;\n }\n\n [data-theme="light"] .upgrade-btn {\n background: #3b82f6 !important;\n color: #ffffff !important;\n }\n\n [data-theme="cupcake"] .upgrade-btn {\n background: #f472b6 !important;\n color: #ffffff !important;\n }\n\n [data-theme="retro"] .upgrade-btn {\n background: #d4a574 !important;\n color: #ffffff !important;\n }\n\n [data-theme="aqua"] .upgrade-btn {\n background: #06b6d4 !important;\n color: #ffffff !important;\n }\n\n [data-theme="lofi"] .upgrade-btn {\n background: #a3a3a3 !important;\n color: #000000 !important;\n }\n\n [data-theme="pastel"] .upgrade-btn {\n background: #a78bfa !important;\n color: #ffffff !important;\n }\n\n [data-theme="fantasy"] .upgrade-btn {\n background: #f472b6 !important;\n color: #ffffff !important;\n }\n\n [data-theme="wireframe"] .upgrade-btn {\n background: #dfdfdf !important;\n color: #000000 !important;\n border: 1px solid #000000 !important;\n }\n\n [data-theme="black"] .upgrade-btn {\n background: #ffffff !important;\n color: #000000 !important;\n }\n\n [data-theme="cmyk"] .upgrade-btn {\n background: #0891b2 !important;\n color: #ffffff !important;\n }\n\n [data-theme="autumn"] .upgrade-btn {\n background: #d97706 !important;\n color: #ffffff !important;\n }\n\n [data-theme="business"] .upgrade-btn {\n background: #3b82f6 !important;\n color: #ffffff !important;\n }\n\n [data-theme="acid"] .upgrade-btn {\n background: #84cc16 !important;\n color: #000000 !important;\n }\n\n [data-theme="lemonade"] .upgrade-btn {\n background: #22c55e !important;\n color: #ffffff !important;\n }\n\n [data-theme="coffee"] .upgrade-btn {\n background: #a0522d !important;\n color: #ffffff !important;\n }\n\n [data-theme="winter"] .upgrade-btn {\n background: #3b82f6 !important;\n color: #ffffff !important;\n }\n\n /* Cancel Button Styles for All Themes */\n [data-theme="dark"] .cancel-btn {\n background: #4b5563 !important;\n color: #ffffff !important;\n }\n\n [data-theme="cyberpunk"] .cancel-btn {\n background: #7e22ce !important;\n color: #ffffff !important;\n }\n\n [data-theme="valentine"] .cancel-btn {\n background: #c11560 !important;\n color: #ffffff !important;\n }\n\n [data-theme="bumblebee"] .cancel-btn {\n background: #d97706 !important;\n color: #ffffff !important;\n }\n\n [data-theme="garden"] .cancel-btn {\n background: #059669 !important;\n color: #ffffff !important;\n }\n\n [data-theme="emerald"] .cancel-btn {\n background: #059669 !important;\n color: #ffffff !important;\n }\n\n [data-theme="corporate"] .cancel-btn {\n background: #6b7280 !important;\n color: #ffffff !important;\n }\n\n [data-theme="forest"] .cancel-btn {\n background: #059669 !important;\n color: #ffffff !important;\n }\n\n [data-theme="halloween"] .cancel-btn {\n background: #7c3aed !important;\n color: #ffffff !important;\n }\n\n [data-theme="synthwave"] .cancel-btn {\n background: #7e22ce !important;\n color: #ffffff !important;\n }\n\n [data-theme="dracula"] .cancel-btn {\n background: #6272a4 !important;\n color: #ffffff !important;\n }\n\n [data-theme="luxury"] .cancel-btn {\n background: #8b5cf6 !important;\n color: #ffffff !important;\n }\n\n [data-theme="night"] .cancel-btn {\n background: #0284c7 !important;\n color: #ffffff !important;\n }\n\n [data-theme="light"] .cancel-btn {\n background: #6b7280 !important;\n color: #ffffff !important;\n }\n\n [data-theme="cupcake"] .cancel-btn {\n background: #ec4899 !important;\n color: #ffffff !important;\n }\n\n [data-theme="retro"] .cancel-btn {\n background: #b8925c !important;\n color: #ffffff !important;\n }\n\n [data-theme="aqua"] .cancel-btn {\n background: #0891b2 !important;\n color: #ffffff !important;\n }\n\n [data-theme="lofi"] .cancel-btn {\n background: #6b7280 !important;\n color: #ffffff !important;\n }\n\n [data-theme="pastel"] .cancel-btn {\n background: #8b5cf6 !important;\n color: #ffffff !important;\n }\n\n [data-theme="fantasy"] .cancel-btn {\n background: #ec4899 !important;\n color: #ffffff !important;\n }\n\n [data-theme="wireframe"] .cancel-btn {\n background: #f5f5f5 !important;\n color: #000000 !important;\n border: 1px solid #000000 !important;\n }\n\n [data-theme="black"] .cancel-btn {\n background: #6b7280 !important;\n color: #ffffff !important;\n }\n\n [data-theme="cmyk"] .cancel-btn {\n background: #0369a1 !important;\n color: #ffffff !important;\n }\n\n [data-theme="autumn"] .cancel-btn {\n background: #c2410c !important;\n color: #ffffff !important;\n }\n\n [data-theme="business"] .cancel-btn {\n background: #6b7280 !important;\n color: #ffffff !important;\n }\n\n [data-theme="acid"] .cancel-btn {\n background: #65a30d !important;\n color: #ffffff !important;\n }\n\n [data-theme="lemonade"] .cancel-btn {\n background: #16a34a !important;\n color: #ffffff !important;\n }\n\n [data-theme="coffee"] .cancel-btn {\n background: #8b4513 !important;\n color: #ffffff !important;\n }\n\n [data-theme="winter"] .cancel-btn {\n background: #1e40af !important;\n color: #ffffff !important;\n }\n\n /* Success Button Styles for All Themes */\n [data-theme="dark"] .success-btn {\n background: #10b981 !important;\n color: #ffffff !important;\n }\n\n [data-theme="cyberpunk"] .success-btn {\n background: #00ff41 !important;\n color: #000000 !important;\n }\n\n [data-theme="valentine"] .success-btn {\n background: #e91e7a !important;\n color: #ffffff !important;\n }\n\n [data-theme="bumblebee"] .success-btn {\n background: #f59e0b !important;\n color: #ffffff !important;\n }\n\n [data-theme="garden"] .success-btn {\n background: #10b981 !important;\n color: #ffffff !important;\n }\n\n [data-theme="emerald"] .success-btn {\n background: #10b981 !important;\n color: #ffffff !important;\n }\n\n [data-theme="corporate"] .success-btn {\n background: #10b981 !important;\n color: #ffffff !important;\n }\n\n [data-theme="forest"] .success-btn {\n background: #10b981 !important;\n color: #ffffff !important;\n }\n\n [data-theme="halloween"] .success-btn {\n background: #ff7b00 !important;\n color: #000000 !important;\n }\n\n [data-theme="synthwave"] .success-btn {\n background: #00ff41 !important;\n color: #000000 !important;\n }\n\n [data-theme="dracula"] .success-btn {\n background: #50fa7b !important;\n color: #000000 !important;\n }\n\n [data-theme="luxury"] .success-btn {\n background: #d4af37 !important;\n color: #000000 !important;\n }\n\n [data-theme="night"] .success-btn {\n background: #22d3ee !important;\n color: #ffffff !important;\n }\n\n [data-theme="light"] .success-btn {\n background: #10b981 !important;\n color: #ffffff !important;\n }\n\n [data-theme="cupcake"] .success-btn {\n background: #f472b6 !important;\n color: #ffffff !important;\n }\n\n [data-theme="retro"] .success-btn {\n background: #d4a574 !important;\n color: #ffffff !important;\n }\n\n [data-theme="aqua"] .success-btn {\n background: #06b6d4 !important;\n color: #ffffff !important;\n }\n\n [data-theme="lofi"] .success-btn {\n background: #10b981 !important;\n color: #ffffff !important;\n }\n\n [data-theme="pastel"] .success-btn {\n background: #34d399 !important;\n color: #ffffff !important;\n }\n\n [data-theme="fantasy"] .success-btn {\n background: #f472b6 !important;\n color: #ffffff !important;\n }\n\n [data-theme="wireframe"] .success-btn {\n background: #dfdfdf !important;\n color: #000000 !important;\n border: 1px solid #000000 !important;\n }\n\n [data-theme="black"] .success-btn {\n background: #10b981 !important;\n color: #ffffff !important;\n }\n\n [data-theme="cmyk"] .success-btn {\n background: #06b6d4 !important;\n color: #ffffff !important;\n }\n\n [data-theme="autumn"] .success-btn {\n background: #d97706 !important;\n color: #ffffff !important;\n }\n\n [data-theme="business"] .success-btn {\n background: #10b981 !important;\n color: #ffffff !important;\n }\n\n [data-theme="acid"] .success-btn {\n background: #84cc16 !important;\n color: #000000 !important;\n }\n\n [data-theme="lemonade"] .success-btn {\n background: #22c55e !important;\n color: #ffffff !important;\n }\n\n [data-theme="coffee"] .success-btn {\n background: #a0522d !important;\n color: #ffffff !important;\n }\n\n [data-theme="winter"] .success-btn {\n background: #3b82f6 !important;\n color: #ffffff !important;\n }\n .download-limiter-signout-btn {\n background: #dc3545;\n color: white;\n border: none;\n padding: 6px 12px;\n border-radius: 4px;\n font-size: 12px;\n cursor: pointer;\n margin-left: 8px;\n }\n .download-limiter-premium-badge {\n background: linear-gradient(45deg, #f39c12, #e74c3c);\n color: white;\n padding: 2px 6px;\n border-radius: 3px;\n font-size: 10px;\n margin-left: 8px;\n font-weight: bold;\n }\n .download-limiter-btn-premium {\n opacity: 0.7;\n }\n .download-limiter-success-modal {\n display: none;\n position: fixed;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n background: rgba(0,0,0,0.5);\n z-index: 10000;\n align-items: center;\n justify-content: center;\n }\n .download-limiter-success-modal.show { display: flex; }\n .download-limiter-success-content {\n background: white;\n padding: 2rem;\n border-radius: 8px;\n max-width: 400px;\n text-align: center;\n box-shadow: 0 4px 20px rgba(0,0,0,0.15);\n border-left: 4px solid #38a169;\n }\n\n /* Single upgrade flow styles */\n .single-upgrade-container {\n margin: 20px 0;\n text-align: center;\n }\n\n .single-upgrade-content .upgrade-btn {\n background: linear-gradient(135deg, #059669, #0d9488) !important;\n color: white !important;\n border: none !important;\n padding: 16px 32px !important;\n border-radius: 12px !important;\n font-size: 18px !important;\n font-weight: 600 !important;\n cursor: pointer !important;\n transition: all 0.3s ease !important;\n box-shadow: 0 4px 12px rgba(5, 150, 105, 0.3) !important;\n margin-bottom: 16px !important;\n min-width: 200px !important;\n }\n\n .single-upgrade-content .upgrade-btn:hover {\n background: linear-gradient(135deg, #047857, #0f766e) !important;\n transform: translateY(-2px) !important;\n box-shadow: 0 6px 20px rgba(5, 150, 105, 0.4) !important;\n }\n\n .single-upgrade-content .upgrade-description {\n font-size: 14px !important;\n color: #6b7280 !important;\n margin: 12px 0 0 0 !important;\n line-height: 1.5 !important;\n max-width: 300px !important;\n margin-left: auto !important;\n margin-right: auto !important;\n }\n\n /* Anonymous user usage count styles */\n .lead-fast-anonymous-status {\n display: flex;\n align-items: center;\n gap: 12px;\n }\n\n .lead-fast-anonymous-status .lead-fast-count {\n background: rgba(59, 130, 246, 0.1);\n color: #1d4ed8;\n padding: 6px 12px;\n border-radius: 8px;\n font-size: 14px;\n font-weight: 500;\n border: 1px solid rgba(59, 130, 246, 0.2);\n }\n\n /* Loading state styles */\n .lead-fast-loading-status {\n display: flex;\n align-items: center;\n gap: 10px;\n }\n\n .lead-fast-spinner {\n width: 20px;\n height: 20px;\n color: #3b82f6;\n }\n\n .lead-fast-loading-text {\n font-size: 14px;\n color: #6b7280;\n font-weight: 500;\n }\n\n /* Success button theming */\n .download-limiter-btn.success-btn {\n background: #059669 !important;\n color: white !important;\n border: none !important;\n padding: 12px 24px !important;\n border-radius: 8px !important;\n cursor: pointer !important;\n margin-top: 20px !important;\n font-size: 16px !important;\n font-weight: 500 !important;\n transition: all 0.2s ease !important;\n }\n\n .download-limiter-btn.success-btn:hover {\n background: #047857 !important;\n transform: translateY(-1px) !important;\n }\n\n /* Theme-specific success button colors */\n [data-theme="cyberpunk"] .download-limiter-btn.success-btn {\n background: #0ea5e9 !important;\n box-shadow: 0 4px 12px rgba(14, 165, 233, 0.3) !important;\n }\n\n [data-theme="cyberpunk"] .download-limiter-btn.success-btn:hover {\n background: #0284c7 !important;\n }\n\n [data-theme="valentine"] .download-limiter-btn.success-btn {\n background: #be185d !important;\n }\n\n [data-theme="valentine"] .download-limiter-btn.success-btn:hover {\n background: #9d174d !important;\n }\n\n [data-theme="bumblebee"] .download-limiter-btn.success-btn {\n background: #f59e0b !important;\n }\n\n [data-theme="bumblebee"] .download-limiter-btn.success-btn:hover {\n background: #d97706 !important;\n }\n\n [data-theme="garden"] .download-limiter-btn.success-btn {\n background: #16a34a !important;\n }\n\n [data-theme="garden"] .download-limiter-btn.success-btn:hover {\n background: #15803d !important;\n }\n\n /* Google Sign-in button theming */\n .download-limiter-btn.google-signin-btn {\n background: #4285f4 !important;\n color: white !important;\n border: none !important;\n padding: 12px 24px !important;\n border-radius: 8px !important;\n cursor: pointer !important;\n margin-right: 10px !important;\n display: inline-flex !important;\n align-items: center !important;\n gap: 8px !important;\n font-size: 14px !important;\n font-weight: 500 !important;\n transition: all 0.2s ease !important;\n }\n\n .download-limiter-btn.google-signin-btn:hover {\n background: #3367d6 !important;\n transform: translateY(-1px) !important;\n }\n\n /* Upgrade button theming */\n .download-limiter-btn.upgrade-btn {\n background: #059669 !important;\n color: white !important;\n border: none !important;\n padding: 12px 24px !important;\n border-radius: 8px !important;\n cursor: pointer !important;\n margin-right: 10px !important;\n font-size: 16px !important;\n font-weight: 500 !important;\n transition: all 0.2s ease !important;\n }\n\n .download-limiter-btn.upgrade-btn:hover {\n background: #047857 !important;\n transform: translateY(-1px) !important;\n }\n\n /* Theme-specific button colors */\n [data-theme="cyberpunk"] .download-limiter-btn.upgrade-btn {\n background: #0ea5e9 !important;\n box-shadow: 0 4px 12px rgba(14, 165, 233, 0.3) !important;\n }\n\n [data-theme="valentine"] .download-limiter-btn.upgrade-btn {\n background: #be185d !important;\n }\n\n [data-theme="bumblebee"] .download-limiter-btn.upgrade-btn {\n background: #f59e0b !important;\n }\n\n [data-theme="garden"] .download-limiter-btn.upgrade-btn {\n background: #16a34a !important;\n }\n\n /* Cancel button container and styling - positioned at very bottom */\n .download-limiter-cancel-container {\n margin-top: 30px !important;\n padding-top: 20px !important;\n border-top: 1px solid rgba(0, 0, 0, 0.1) !important;\n text-align: center !important;\n position: relative !important;\n bottom: 0 !important;\n }\n\n .download-limiter-btn.cancel-btn {\n background: transparent !important;\n color: #6b7280 !important;\n border: none !important;\n padding: 8px 16px !important;\n border-radius: 6px !important;\n cursor: pointer !important;\n font-size: 13px !important;\n font-weight: 400 !important;\n transition: all 0.2s ease !important;\n text-decoration: underline !important;\n margin: 0 auto !important;\n display: block !important;\n }\n\n .download-limiter-btn.cancel-btn:hover {\n color: #374151 !important;\n background: rgba(107, 114, 128, 0.1) !important;\n text-decoration: none !important;\n }\n\n /* Theme-specific cancel button border */\n [data-theme="dark"] .download-limiter-cancel-container {\n border-top-color: rgba(255, 255, 255, 0.1) !important;\n }\n\n [data-theme="dark"] .download-limiter-btn.cancel-btn {\n color: #9ca3af !important;\n }\n\n [data-theme="dark"] .download-limiter-btn.cancel-btn:hover {\n color: #d1d5db !important;\n background: rgba(156, 163, 175, 0.1) !important;\n }\n\n [data-theme="cyberpunk"] .download-limiter-cancel-container {\n border-top-color: rgba(14, 165, 233, 0.2) !important;\n }\n\n [data-theme="cyberpunk"] .download-limiter-btn.cancel-btn {\n color: #0ea5e9 !important;\n }\n\n [data-theme="cyberpunk"] .download-limiter-btn.cancel-btn:hover {\n color: #38bdf8 !important;\n background: rgba(14, 165, 233, 0.1) !important;\n }\n `,document.head.appendChild(n)}injectDaisyUI(){if(document.querySelector('link[href*="daisyui"]')){if(this.config.theme?.name){const n=this.config.theme.name.toLowerCase();document.documentElement.setAttribute("data-theme",n)}}else if(this.config.theme?.name){const n=this.config.theme.name.toLowerCase();document.documentElement.setAttribute("data-theme",n),this.updateStatusDisplays()}}createPaywallModal(){if(document.getElementById("download-limiter-paywall"))return;const n=document.createElement("div");n.id="download-limiter-paywall",n.className="download-limiter-modal",n.innerHTML='\n <div class="download-limiter-content">\n <h3 id="download-limiter-paywall-title">Usage Limit Reached</h3>\n <p id="download-limiter-paywall-subtitle">You\'ve used all your free attempts. Upgrade to premium for unlimited usage!</p>\n\n \x3c!-- Auth Section (shows when not signed in) --\x3e\n <div id="download-limiter-auth-section" style="margin: 20px 0;">\n <p>Sign in to continue or upgrade to premium</p>\n <button id="download-limiter-signin-btn" class="download-limiter-btn google-signin-btn">\n <svg width="18" height="18" viewBox="0 0 18 18" fill="none">\n <path d="M16.51 8H8.98v3h4.3c-.18 1-.74 1.48-1.6 2.04v2.01h2.6a8.8 8.8 0 0 0 2.38-5.88c0-.57-.05-.66-.15-1.18z" fill="white"/>\n <path d="M8.98 17c2.16 0 3.97-.72 5.3-1.94l-2.6-2.04a4.8 4.8 0 0 1-2.7.75 4.8 4.8 0 0 1-4.52-3.4H1.83v2.07A8 8 0 0 0 8.98 17z" fill="white"/>\n <path d="M4.46 10.37a4.8 4.8 0 0 1-.25-1.37c0-.48.09-.94.25-1.37V5.56H1.83a8 8 0 0 0 0 6.88l2.63-2.07z" fill="white"/>\n <path d="M8.98 3.77c1.32 0 2.5.45 3.44 1.35l2.58-2.58C13.94.64 11.66 0 8.98 0A8 8 0 0 0 1.83 5.56l2.63 2.07c.61-1.8 2.26-3.86 4.52-3.86z" fill="white"/>\n </svg>\n Sign in with Google\n </button>\n </div>\n\n \x3c!-- Payment Section (shows when signed in) --\x3e\n <div id="download-limiter-payment-section" style="margin: 20px 0; display: none;">\n <button id="download-limiter-upgrade-btn" class="download-limiter-btn upgrade-btn">\n Upgrade to Premium\n </button>\n </div>\n\n <div class="download-limiter-cancel-container">\n <button id="download-limiter-close-btn" class="download-limiter-btn cancel-btn">\n Cancel\n </button>\n </div>\n </div>\n ',document.body.appendChild(n),n.querySelector("#download-limiter-signin-btn").addEventListener("click",async()=>{await this.signIn()}),n.querySelector("#download-limiter-upgrade-btn").addEventListener("click",async()=>{const n=await this.createPayment();n?.checkout_url&&(window.location.href=n.checkout_url)}),n.querySelector("#download-limiter-close-btn").addEventListener("click",()=>{this.config.options,this.config.feedback||this.config.email?(this.config.options,this.showFeedbackForm()):(this.config.options,n.classList.remove("show"))})}createSuccessModal(){if(document.getElementById("download-limiter-success"))return;const n=document.createElement("div");n.id="download-limiter-success",n.className="download-limiter-modal",n.innerHTML='\n <div class="download-limiter-content"> \x3c!-- Use same content class as paywall for theming --\x3e\n <h3 id="download-limiter-success-title">Action Started!</h3>\n <p id="download-limiter-success-message">Your action completed successfully!</p>\n <button id="download-limiter-success-close" class="download-limiter-btn success-btn">\n OK\n </button>\n </div>\n ',document.body.appendChild(n),n.querySelector("#download-limiter-success-close").addEventListener("click",()=>{n.classList.remove("show")}),n.addEventListener("click",t=>{t.target===n&&n.classList.remove("show")})}showFeedbackForm(){const n=document.getElementById("download-limiter-paywall");n&&n.classList.remove("show"),this.createFeedbackModal();const t=document.getElementById("download-limiter-feedback");t&&t.classList.add("show")}createFeedbackModal(){if(document.getElementById("download-limiter-feedback"))return void this.config.options;const n=this.config.feedback||(this.config.email?{form:{title:"Quick Feedback",description:"Why didn't you upgrade?",option1:"Not useful for my needs",option2:"Didn't find what I was looking for",option3:"Just trying it out"},email:this.config.email}:null);if(this.config.options,!n)return void this.config.options;const t=document.createElement("div");t.id="download-limiter-feedback",t.className="download-limiter-modal",t.innerHTML=`\n <div class="download-limiter-content">\n <h3>${n.form.title}</h3>\n <p style="margin-bottom: 20px;">${n.form.description}</p>\n\n <form id="feedback-form" style="text-align: left;">\n <div style="margin-bottom: 15px;">\n <label style="display: block; margin-bottom: 8px;">\n <input type="radio" name="reason" value="option1" style="margin-right: 8px;">\n ${n.form.option1}\n </label>\n <label style="display: block; margin-bottom: 8px;">\n <input type="radio" name="reason" value="option2" style="margin-right: 8px;">\n ${n.form.option2}\n </label>\n <label style="display: block; margin-bottom: 8px;">\n <input type="radio" name="reason" value="option3" style="margin-right: 8px;">\n ${n.form.option3}\n </label>\n </div>\n\n <div style="margin-bottom: 15px;">\n <label for="feedback-details" style="display: block; margin-bottom: 5px;">Tell us more:</label>\n <textarea\n id="feedback-details"\n name="details"\n rows="3"\n style="width: 100%; padding: 8px; border: 1px solid #ddd; border-radius: 4px;"\n placeholder="Your feedback helps us improve..." maxlength="200"></textarea>\n </div>\n\n <div style="margin-bottom: 20px;">\n <label for="feedback-email" style="display: block; margin-bottom: 5px;">\n Email (optional):\n </label>\n <input\n type="email"\n id="feedback-email"\n name="email"\n style="width: 100%; padding: 8px; border: 1px solid #ddd; border-radius: 4px;"\n placeholder="your@email.com">\n <small style="color: #666; display: block; margin-top: 4px;">\n Only if you want us to reach out about what you mentioned above. We don't follow up unless you want us to\n </small>\n </div>\n\n \n <div style="text-align: center;">\n <button type="submit" class="download-limiter-btn success-btn" style="margin-right: 10px;">\n Submit Feedback\n </button>\n <button type="button" id="feedback-skip-btn" class="download-limiter-btn cancel-btn">\n Skip\n </button>\n </div>\n </form>\n </div>\n `,document.body.appendChild(t),this.config.options;const e=t.querySelector("#feedback-form");e.addEventListener("submit",n=>{n.preventDefault(),this.submitFeedback(e)}),t.querySelector("#feedback-skip-btn").addEventListener("click",()=>{t.classList.remove("show")}),t.addEventListener("click",n=>{n.target===t&&t.classList.remove("show")})}async submitFeedback(n){const t=new FormData(n),e=t.get("reason"),a=t.get("details"),o=t.get("email");if(!e)return void alert("Please select a reason");const i={reason:e,details:a,email:o||void 0,timestamp:(new Date).toISOString(),userAgent:navigator.userAgent,appId:this.validatedAppName||"unknown"};try{await this.sendFeedbackEmail(i);const n=document.getElementById("download-limiter-feedback");n&&n.classList.remove("show"),alert("Thank you for your feedback!")}catch(n){console.error("Failed to send feedback:",n),alert("Failed to send feedback. Please try again.")}}async sendFeedbackEmail(n){let t;if(this.config.feedback?.email?t=Array.isArray(this.config.feedback.email)?this.config.feedback.email[0]:this.config.feedback.email:this.config.email&&(t={provider:"resend",apiKey:this.config.email.resendApiKey,fromEmail:this.config.email.fromEmail}),!t)throw new Error("Email configuration not available");const e=`\nNew Feedback from ${this.validatedAppName||"unknown"}\n\nReason: ${n.reason}\nDetails: ${n.details}\nUser Email: ${n.email||"Not provided"}\nTimestamp: ${n.timestamp}\nUser Agent: ${n.userAgent}\n `.trim();let a;if("resend"!==t.provider&&t.provider)throw new Error(`Unsupported email provider: ${t.provider}`);if(a=await fetch("https://api.resend.com/emails",{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${t.apiKey||t.resendApiKey}`},body:JSON.stringify({from:t.fromEmail,to:[t.fromEmail],subject:`Feedback from ${this.validatedAppName||"unknown"}`,text:e})}),!a.ok)throw new Error(`Email API error: ${a.status}`)}createAuthUI(){if(document.getElementById("lead-fast-profile"))return;const n=document.createElement("div");n.id="lead-fast-profile",n.className="lead-fast-profile",document.body.appendChild(n)}createStatusDisplay(){if(document.getElementById("download-limiter-status"))return;const n=document.createElement("div");n.id="download-limiter-status",n.className="download-limiter-status",document.body.appendChild(n)}createGlobalStatusDisplay(){this.createStatusDisplay()}showPaywallInstant(n){this.createPaywallModal();const t=document.getElementById("download-limiter-paywall");if(t){const e=t.querySelector("#download-limiter-paywall-title");e&&(e.textContent=`You've used ${n.limit} free attempts`);const a=t.querySelector("#download-limiter-auth-section"),o=t.querySelector("#download-limiter-payment-section");if(this.currentUser)a.style.display="none",o.style.display="block";else{const n=t.querySelector("#download-limiter-paywall-subtitle");n&&(n.textContent="Sign in to continue. If you're already premium, you'll get unlimited access. New users can upgrade after signing in."),a.style.display="none",o.style.display="none",this.showSingleUpgradeFlow(t)}t.classList.add("show")}}async showPaywall(){const n=await this.getDownloadStatus();this.showPaywallInstant(n)}showSingleUpgradeFlow(n){let t=n.querySelector(".single-upgrade-container");if(!t){t=document.createElement("div"),t.className="single-upgrade-container",t.innerHTML='\n <div class="single-upgrade-content">\n <button class="download-limiter-btn upgrade-btn" id="single-upgrade-btn">\n Continue with Google\n </button>\n \x3c!--<p class="upgrade-description">\n Sign in to restore access. Premium members get unlimited usage immediately.\n </p>--\x3e\n </div>\n ';const e=n.querySelector(".download-limiter-cancel-container");e?n.querySelector(".download-limiter-content")?.insertBefore(t,e):n.querySelector(".download-limiter-content")?.appendChild(t)}t.style.display="block";const e=n.querySelector("#single-upgrade-btn");if(e){e.replaceWith(e.cloneNode(!0));const t=n.querySelector("#single-upgrade-btn");t?.addEventListener("click",async()=>{try{const{error:n}=await this.supabase.auth.signInWithOAuth({provider:"google",options:{redirectTo:`${window.location.origin}${window.location.pathname}?upgrade=true`}});n&&(console.error("Sign in error:",n),this.showError("Sign In Failed","Failed to sign in with Google. Please try again."))}catch(n){console.error("Upgrade flow error:",n),this.showError("Upgrade Failed","Failed to start upgrade process. Please try again.")}})}}showSuccess(n,t){const e=document.getElementById("download-limiter-success");if(e){const a=e.querySelector("#download-limiter-success-title"),o=e.querySelector("#download-limiter-success-message");a&&(a.textContent=n),o&&(o.textContent=t),e.classList.add("show")}}showError(n,t){const e=document.createElement("div");e.style.cssText="\n position: fixed;\n top: 20px;\n right: 20px;\n background: #fee2e2;\n border: 1px solid #fecaca;\n color: #dc2626;\n padding: 12px 16px;\n border-radius: 8px;\n font-size: 14px;\n font-weight: 500;\n line-height: 1.4;\n max-width: 300px;\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);\n z-index: 10000;\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\n ",e.innerHTML=`\n <div style="font-weight: 600; margin-bottom: 4px;">${n}</div>\n <div style="font-size: 13px; opacity: 0.9;">${t}</div>\n `,document.body.appendChild(e),setTimeout(()=>{e.parentNode&&e.parentNode.removeChild(e)},5e3),e.addEventListener("click",()=>{e.parentNode&&e.parentNode.removeChild(e)})}showInfo(n,t){const e=document.createElement("div");e.style.cssText="\n position: fixed;\n top: 20px;\n right: 20px;\n background: #dbeafe;\n border: 1px solid #bfdbfe;\n color: #1e40af;\n padding: 12px 16px;\n border-radius: 8px;\n font-size: 14px;\n font-weight: 500;\n line-height: 1.4;\n max-width: 350px;\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);\n z-index: 10000;\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\n ",e.innerHTML=`\n <div style="font-weight: 600; margin-bottom: 4px;">⏳ ${n}</div>\n <div style="font-size: 13px; opacity: 0.9;">${t}</div>\n `,document.body.appendChild(e),setTimeout(()=>{e.parentNode&&e.parentNode.removeChild(e)},8e3),e.addEventListener("click",()=>{e.parentNode&&e.parentNode.removeChild(e)})}showConnectionError(){this.showError("Connection Error","Server connection required for download verification. Please check your configuration and try again.")}showPaymentConfigError(){this.showError("Payment Configuration Error","Payment system is not properly configured. Please contact support.")}disableDownloadButtons(n){const t=document.querySelectorAll("[data-leadfast-attached]"),e={connection:"Download disabled: Server connection required",payment:"Download disabled: Payment configuration error",security_key:"Download disabled: Invalid or missing security key"},a={connection:"⚠️ Connection Error - Downloads Disabled",payment:"⚠️ Payment Config Error - Downloads Disabled",security_key:"🔐 Invalid Security Key - Please Update Configuration"};t.forEach(t=>{const a=t;a.disabled=!0,a.style.opacity="0.5",a.style.cursor="not-allowed",a.title=e[n]});const o=document.querySelector(".lead-fast-user-section");o&&(o.innerHTML=`\n <div style="\n color: #ef4444;\n padding: 6px 8px;\n font-size: 12px;\n font-weight: 500;\n line-height: 1.2;\n border-radius: 4px;\n background: rgba(239, 68, 68, 0.05);\n border: 1px solid rgba(239, 68, 68, 0.2);\n max-width: 200px;\n text-align: center;\n ">\n ${a[n]}\n </div>\n `)}async updateStatusDisplays(){if(this.securityKeyFailed)return void this.disableDownloadButtons("security_key");if(this.supabaseConnectionFailed)return void this.disableDownloadButtons("connection");if(this.config.payment&&this.paymentConnectionFailed)return void this.disableDownloadButtons("payment");this.hasCachedPremiumStatus()||(this.isLoadingStatus=!0,this.updateUserSection(null));const n=await this.getDownloadStatus();this.isLoadingStatus=!1,this.securityKeyFailed?this.disableDownloadButtons("security_key"):this.supabaseConnectionFailed?this.disableDownloadButtons("connection"):this.updateUserSection(n)}createTitleBar(){let n=document.getElementById("lead-fast-profile");n||(n=document.createElement("div"),n.id="lead-fast-profile",n.className="lead-fast-profile",document.body.appendChild(n));const t=this.config.titleBar||{},e=t.title||"My App",a=t.titleImage,o=t.links||[];n.innerHTML=`\n <div class="lead-fast-title-bar">\n <div class="lead-fast-title-section">\n <a href="#" class="lead-fast-logo">\n ${a?`<img src="${a}" alt="${e}">`:""}\n <span>${e}</span>\n </a>\n <nav class="lead-fast-nav">\n ${o.map(n=>`\n <a href="${n.url}" class="lead-fast-nav-link" ${n.target?`target="${n.target}"`:""}>\n ${n.text}\n </a>\n `).join("")}\n </nav>\n </div>\n\n <div class="lead-fast-user-section" id="lead-fast-user-section">\n \x3c!-- User section will be populated when logged in --\x3e\n </div>\n\n \x3c!-- <a href="https://www.moneyfast.bar" target="_blank" class="lead-fast-branding" style="text-decoration: none; color: inherit;">moneyfast.bar</a>--\x3e\n </div>\n `}attachSubscriptionTooltip(n,t){let e=null,a=null;const o=()=>{if(a&&(clearTimeout(a),a=null),!e){e=document.createElement("div"),e.className="lead-fast-subscription-tooltip";const n=new Date(t.subscriptionExpiresAt),a=`${["January","February","March","April","May","June","July","August","September","October","November","December"][n.getMonth()]} ${n.getDate()}, ${n.getFullYear()}`,r=t.subscriptionDaysRemaining,s=t.isSubscriptionActive,c=s?"✓":"⚠️",d=s?"Active":"Cancelled",l=s?"Renews:":"Active until:",m=t.customerId?`<div class="tooltip-link">\n <a href="#" class="manage-link" data-customer-id="${t.customerId}">\n Manage Payments →\n <div style="font-size: 11px; color: #666; margin-top: 4px;">\n Manage subscription, orders, invoices, payment method, profile\n </div>\n </a>\n </div>`:"";e.innerHTML=`\n <div class="tooltip-content">\n <div class="tooltip-header">${t.email}</div>\n <div class="tooltip-divider"></div>\n <div class="tooltip-row">\n <span class="tooltip-label">${c} ${d} Subscription</span>\n </div>\n <div class="tooltip-row">\n <span class="tooltip-label">${l}</span>\n <span class="tooltip-value">${a}</span>\n </div>\n <div class="tooltip-row">\n <span class="tooltip-label">Time left:</span>\n <span class="tooltip-value">${r} days</span>\n </div>\n <div class="tooltip-row">\n <span class="tooltip-label">Plan:</span>\n <span class="tooltip-value">${t.subscriptionType||"Monthly"}</span>\n </div>\n ${m}\n </div>\n `,document.body.appendChild(e),e.addEventListener("mouseenter",o),e.addEventListener("mouseleave",i);const p=e.querySelector(".manage-link");p&&p.addEventListener("click",async n=>{n.preventDefault();const t=n.target.getAttribute("data-customer-id");t&&await this.openCustomerPortal(t)})}const r=n.getBoundingClientRect();e.style.top=`${r.bottom+8}px`,e.style.left=r.left-100+"px",e.classList.add("show")},i=()=>{a=setTimeout(()=>{e&&e.classList.remove("show")},200)};n.addEventListener("mouseenter",o),n.addEventListener("mouseleave",i)}async updateUserSection(n){const t=document.getElementById("lead-fast-user-section");if(t)if(null===n||this.isLoadingStatus)t.innerHTML='\n <div class="lead-fast-loading-status">\n <svg class="lead-fast-spinner" viewBox="0 0 24 24">\n <circle cx="12" cy="12" r="10" stroke="currentColor" stroke-width="3" fill="none" stroke-dasharray="31.4 31.4" stroke-linecap="round">\n <animateTransform attributeName="transform" type="rotate" from="0 12 12" to="360 12 12" dur="1s" repeatCount="indefinite"/>\n </circle>\n </svg>\n <span class="lead-fast-loading-text">Loading...</span>\n </div>\n ';else if(this.currentUser){const e=this.currentUser.email.charAt(0).toUpperCase(),a=this.currentUser.email,o=n.isPremium?"premium":"free";let i=n.isPremium?"Premium":"Free";const r=n.isPremium?"Unlimited":`${n.currentCount}/${n.limit}`;let s=!1,c=null;if(n.isPremium){const t=await this.getUserContext(n);if(t.subscriptionType&&"one-time"!==t.subscriptionType&&t.subscriptionExpiresAt){const n=new Date(t.subscriptionExpiresAt);i=`Premium • ${`${["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"][n.getMonth()]} ${n.getDate()}`}`,s=!0,c=t}}let d=i;s&&(d=`${i} <span class="lead-fast-info-icon" title="Click for subscription details">ⓘ</span>`),t.innerHTML=`\n <div class="lead-fast-avatar">${e}</div>\n <div class="lead-fast-user-info">\n <div class="lead-fast-user-email">${a}</div>\n <div class="lead-fast-user-status">\n <span class="lead-fast-badge ${o}">${d}</span>\n <span class="lead-fast-count">${r}</span>\n </div>\n </div>\n <button class="lead-fast-signout">signout</button>\n `;const l=document.querySelector(".lead-fast-title-bar");l&&getComputedStyle(l);const m=t.querySelector(".lead-fast-signout");if(m&&m.addEventListener("click",()=>{this.signOut()}),s&&c){const n=t.querySelector(".lead-fast-info-icon");n&&this.attachSubscriptionTooltip(n,c)}}else{const e=`${this.config.actionLabel}: ${n.currentCount}/${n.limit}`;t.innerHTML=`\n <div class="lead-fast-anonymous-status">\n <span class="lead-fast-count">${e}</span>\n </div>\n `}}setupUIUpdates(){this.on("authChanged",async n=>{const t=n.user?.email||null,e=this.lastAuthEmail!==t;this.lastAuthEmail=t,this.cachedStatus=null,this.cachedPremiumStatus=null,this.cachedDownloadCount=null,e&&this.clearPremiumStatusFromLocalStorage(),this.updateStatusDisplays();const a=document.getElementById("download-limiter-paywall");a&&a.classList.contains("show")&&(this.updatePaywallDisplay(),this.currentUser&&this.config.payment&&(n.isPremium?a.classList.remove("show"):setTimeout(async()=>{const n=await this.createPayment();n?.checkout_url&&(window.location.href=n.checkout_url)},500)))}),this.on("countChanged",()=>{this.updateStatusDisplays()}),this.updateStatusDisplays()}updatePaywallDisplay(){const n=document.getElementById("download-limiter-paywall");if(!n)return;const t=n.querySelector("#download-limiter-auth-section"),e=n.querySelector("#download-limiter-payment-section");this.currentUser?(t.style.display="none",e.style.display="block"):(t.style.display="block",e.style.display="none")}on(n,t){this.eventListeners.has(n)||this.eventListeners.set(n,[]),this.eventListeners.get(n).push(t)}off(n,t){const e=this.eventListeners.get(n);if(e){const n=e.indexOf(t);n>-1&&e.splice(n,1)}}emit(n,t){const e=this.eventListeners.get(n);e&&e.forEach(e=>{try{e(t)}catch(t){console.error(`Error in ${n} listener:`,t)}})}validateConfig(){if(!this.config.security_key)throw new Error("security_key is required");if(!this.config.actionLabel)throw new Error('actionLabel is required (e.g., "PDF Generations", "Image Exports")');if(!this.config.supabase?.url)throw new Error("supabase.url is required");if(!this.config.supabase?.anonKey)throw new Error("supabase.anonKey is required");if("number"!=typeof this.config.freeAttemptLimit||this.config.freeAttemptLimit<0)throw new Error("freeAttemptLimit must be a non-negative number")}async initializeSupabase(){try{this.supabase=n.createClient(this.config.supabase.url,this.config.supabase.anonKey),this.supabaseConnectionFailed=!1}catch(n){console.error("Failed to initialize Supabase:",n),this.supabaseConnectionFailed=!0}}async initializePayment(){if(!this.config.payment)return;const n=this.config.payment?.find(n=>"dodo"===n.provider);if(!n)return this.paymentConnectionFailed=!0,void(this.config.options?.debug&&console.warn("No dodo payment provider configured"));const t=n.productId;if(!t||!t.startsWith("pdt_")||t.length<10)return this.paymentConnectionFailed=!0,void(this.config.options?.debug&&console.warn("Invalid payment product ID format:",t));this.paymentConnectionFailed=!1}async initializeFingerprint(){try{this.userFingerprint=await this.generateFingerprint()}catch(n){this.userFingerprint=crypto.randomUUID?crypto.randomUUID():String(Date.now()),this.config.options?.debug&&console.warn("Fingerprint generation failed, using fallback:",n)}}async generateFingerprint(){const n=`${navigator.userAgent||""}||${Intl.DateTimeFormat().resolvedOptions().timeZone||""}||${`${screen.width}x${screen.height}`}||${navigator.language||""}`,t=(new TextEncoder).encode(n),e=await crypto.subtle.digest("SHA-256",t);return Array.from(new Uint8Array(e)).map(n=>n.toString(16).padStart(2,"0")).join("")}async setupAuthListener(){this.supabase.auth.onAuthStateChange(async(n,t)=>{const e=this.currentUser;this.currentUser=t?.user||null;let a=!1;if(this.currentUser){const t=!e||e.email!==this.currentUser.email,o=!this.cachedPremiumStatus||Date.now()-this.premiumStatusCacheTime>this.STATUS_CACHE_DURATION;if("INITIAL_SESSION"===n){const n=this.loadPremiumStatusFromLocalStorage(this.currentUser.email);n&&(a=n.isPremium,console.log(`🔍 [INITIAL_SESSION] Using localStorage premium status: ${a}`))}else if(t||o){a=(await this.checkPremiumStatus(this.currentUser.email)).isPremium,this.cachedPremiumStatus=a,this.premiumStatusCacheTime=Date.now()}else a=this.cachedPremiumStatus,console.log(`🔍 [CACHE] Using cached premium status from auth listener: ${a}`)}else this.cachedPremiumStatus=null,this.premiumStatusCacheTime=0;const o="true"===new URLSearchParams(window.location.search).get("upgrade");if("SIGNED_IN"===n&&!e&&this.currentUser&&this.config.payment&&o)if(a){window.history.replaceState({},document.title,window.location.pathname);const n=document.getElementById("download-limiter-paywall");n&&n.classList.remove("show")}else{const n=await this.createPayment();n?.checkout_url&&(window.history.replaceState({},document.title,window.location.pathname),window.location.href=n.checkout_url)}this.cachedStatus=null,this.statusCacheTime=0,this.emit("authChanged",{user:this.currentUser,isAuthenticated:!!this.currentUser,isPremium:a,email:this.currentUser?.email});const i=!!e&&(this.cachedPremiumStatus??!1);a!==i&&this.emit("premiumStatusChanged",{isPremium:a,previousStatus:i,email:this.currentUser?.email}),"INITIAL_SESSION"===n||("SIGNED_OUT"===n?this.updateUserSection(null):await this.updateStatusDisplays())});const{data:{user:n}}=await this.supabase.auth.getUser();this.currentUser=n}async getDownloadCount(){if(!this.userFingerprint)return 0;if(null!==this.cachedDownloadCount&&Date.now()-this.downloadCountCacheTime<this.DOWNLOAD_COUNT_CACHE_DURATION)return console.log(`🔍 [CACHE] Using cached download count: ${this.cachedDownloadCount} (age: ${Math.round((Date.now()-this.downloadCountCacheTime)/1e3)}s)`),this.cachedDownloadCount;if(this.downloadCountPromise)return console.log("🔍 [CACHE] Waiting for existing download count fetch"),await this.downloadCountPromise;this.downloadCountPromise=this.fetchDownloadCount();try{const n=await this.downloadCountPromise;return this.cachedDownloadCount=n,this.downloadCountCacheTime=Date.now(),console.log(`🔍 [CACHE] Cached download count: ${n}`),n}finally{this.downloadCountPromise=null}}async fetchDownloadCount(){try{const n=await fetch(`${this.config.supabase.url}/functions/v1/check-download-limit`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${this.config.supabase.anonKey}`},body:JSON.stringify({fingerprint:this.userFingerprint,security_key:this.config.security_key,action:"check"})});if(n.ok){const t=await n.json();return this.supabaseConnectionFailed=!1,t.app_id&&!this.validatedAppName?this.validatedAppName=t.app_id:this.validatedAppName,t.current_count||0}if(401===n.status||403===n.status)try{const t=await n.json(),e=t.error||t.message||"Authentication failed";e.toLowerCase().includes("security key")?(console.error(`❌ Security Key Validation Failed [check-download-limit]: ${e}`),console.error("💡 Backend Function: check-download-limit"),console.error("💡 Please check your security_key in the MoneyBar configuration"),this.securityKeyFailed=!0,this.supabaseConnectionFailed=!0):(console.warn(`Supabase authentication failed [check-download-limit]: ${n.status} - ${e}`),this.supabaseConnectionFailed=!0)}catch(t){console.warn(`Supabase authentication failed: ${n.status} - Unable to parse error`),this.supabaseConnectionFailed=!0}}catch(n){this.supabaseConnectionFailed=!0,this.config.options?.debug&&console.warn("Failed to get server usage count, connection failed:",n)}return 0}async incrementDownloadCount(){if(!this.userFingerprint)return 0;const n={fingerprint:this.userFingerprint,security_key:this.config.security_key,action:"increment"};try{const t=await fetch(`${this.config.supabase.url}/functions/v1/check-download-limit`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${this.config.supabase.anonKey}`},body:JSON.stringify(n)});if(this.config.options?.debug&&!t.ok){const n=await t.text();console.error("🔍 DEBUG: Error response:",n)}if(t.ok){const n=await t.json();return this.supabaseConnectionFailed=!1,n.app_id&&!this.validatedAppName?this.validatedAppName=n.app_id:this.validatedAppName,this.cachedDownloadCount=null,this.downloadCountCacheTime=0,console.log("🔍 [CACHE] Invalidated download count cache after increment"),n.new_count||0}if(401===t.status||403===t.status)try{const n=await t.json(),e=n.error||n.message||"Authentication failed";e.toLowerCase().includes("security key")?(console.error(`❌ Security Key Validation Failed [check-download-limit]: ${e}`),console.error("💡 Backend Function: check-download-limit"),console.error("💡 Please check your security_key in the MoneyBar configuration"),this.securityKeyFailed=!0,this.supabaseConnectionFailed=!0):(console.warn(`Supabase authentication failed [check-download-limit]: ${t.status} - ${e}`),this.supabaseConnectionFailed=!0)}catch(n){console.warn(`Supabase authentication failed: ${t.status} - Unable to parse error`),this.supabaseConnectionFailed=!0}}catch(n){this.supabaseConnectionFailed=!0,this.config.options?.debug&&console.warn("Failed to increment server count, connection failed:",n)}return 0}async checkPremiumStatus(n){if(this.premiumCheckPromise)return console.log("🔍 [CACHE] Waiting for existing premium check"),await this.premiumCheckPromise;const t=this.loadPremiumStatusFromLocalStorage(n);if(t)return console.log(`🔍 [LOCALSTORAGE] Using localStorage premium status: ${t.isPremium} (age: ${Math.round((Date.now()-t.timestamp)/1e3/60)}m)`),this.cachedPremiumStatus=t.isPremium,this.cachedSubscriptionDetails=t.subscriptionDetails,this.premiumStatusCacheTime=t.timestamp,this.lastCheckedEmail=n,{isPremium:t.isPremium,subscriptionDetails:t.subscriptionDetails};if(null!==this.cachedPremiumStatus&&Date.now()-this.premiumStatusCacheTime<this.STATUS_CACHE_DURATION&&this.lastCheckedEmail===n)return console.log(`🔍 [CACHE] Using cached premium status: ${this.cachedPremiumStatus}`),{isPremium:this.cachedPremiumStatus,subscriptionDetails:this.cachedSubscriptionDetails};this.premiumCheckPromise=this.fetchPremiumStatus(n);try{const t=await this.premiumCheckPromise;return this.savePremiumStatusToLocalStorage(n,t.isPremium,t.subscriptionDetails),t}finally{this.premiumCheckPromise=null}}savePremiumStatusToLocalStorage(n,t,e){try{const a={email:n,isPremium:t,subscriptionDetails:e,timestamp:Date.now(),appId:this.validatedAppName||"unknown"},o=`moneybar_premium_${this.validatedAppName||"unknown"}`;localStorage.setItem(o,JSON.stringify(a)),console.log("🔍 [LOCALSTORAGE] Saved premium status to localStorage (24h cache)")}catch(n){console.warn("Failed to save premium status to localStorage:",n)}}loadPremiumStatusFromLocalStorage(n){try{const t=`moneybar_premium_${this.validatedAppName||"unknown"}`,e=localStorage.getItem(t);if(!e)return null;const a=JSON.parse(e),o=Date.now()-a.timestamp,i=864e5;return a.email===n&&o<i?{isPremium:a.isPremium,subscriptionDetails:a.subscriptionDetails,timestamp:a.timestamp}:(localStorage.removeItem(t),null)}catch(n){return null}}clearPremiumStatusFromLocalStorage(){try{const n=`moneybar_premium_${this.validatedAppName||"unknown"}`;localStorage.removeItem(n),console.log("🔍 [LOCALSTORAGE] Cleared premium status from localStorage")}catch(n){}}hasCachedPremiumStatus(){if(!this.currentUser?.email)return!1;const n=this.loadPremiumStatusFromLocalStorage(this.currentUser.email);if(n&&n.isPremium)return console.log("🔍 [CACHE-CHECK] Premium user with valid cache - skip loading"),!0;return!(!(null!==this.cachedPremiumStatus&&Date.now()-this.premiumStatusCacheTime<this.STATUS_CACHE_DURATION&&this.lastCheckedEmail===this.currentUser.email)||!0!==this.cachedPremiumStatus)&&(console.log("🔍 [CACHE-CHECK] Premium user with valid memory cache - skip loading"),!0)}async fetchPremiumStatus(n){if(!this.validatedAppName&&this.userFingerprint)try{const n=await fetch(`${this.config.supabase.url}/functions/v1/check-download-limit`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${this.config.supabase.anonKey}`},body:JSON.stringify({fingerprint:this.userFingerprint,security_key:this.config.security_key,action:"check"})});if(n.ok){const t=await n.json();t.app_id&&(this.validatedAppName=t.app_id)}}catch(n){}try{const t=this.config.payment?.[0]?.mode||"live",e={email:n,app_id:this.validatedAppName||"unknown",mode:t},a=await fetch(`${this.config.supabase.url}/functions/v1/check-payment-status`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${this.config.supabase.anonKey}`},body:JSON.stringify(e)});if(a.ok){const t=await a.json();t.message&&"processing"===t.payment_status&&this.showInfo("Payment Verification",t.message);const e={isPremium:!0===t.is_premium,subscriptionDetails:t.subscription_details||null};return this.cachedPremiumStatus=e.isPremium,this.cachedSubscriptionDetails=e.subscriptionDetails,this.premiumStatusCacheTime=Date.now(),this.lastCheckedEmail=n,e}}catch(n){this.config.options?.debug&&console.warn("Failed to check premium status:",n)}return{isPremium:!1,subscriptionDetails:null}}getLocalDownloadCount(){const n=`download_count_${this.validatedAppName||"unknown"}`,t=parseInt(localStorage.getItem(n)||"0",10);return isNaN(t)?0:t}incrementLocalDownloadCount(){const n=`download_count_${this.validatedAppName||"unknown"}`,t=this.getLocalDownloadCount()+1;return localStorage.setItem(n,String(t)),t}handleError(n){this.config.options?.debug&&console.error("Lead Fast Error:",n),this.config.callbacks?.onError?this.config.callbacks.onError(n):console.error("Lead Fast:",n.message),this.emit("error",n)}async checkPaymentStatus(){"success"===new URLSearchParams(window.location.search).get("payment")&&setTimeout(async()=>{if(this.currentUser){const{isPremium:n,subscriptionDetails:t}=await this.checkPremiumStatus(this.currentUser.email);n?(this.showSuccess("Payment Successful!","Welcome to premium! You now have unlimited usage."),this.emit("paymentSucceeded",{email:this.currentUser.email,subscriptionType:t?.subscription_type}),t?.subscription_id&&this.emit("subscriptionCreated",{email:this.currentUser.email,subscriptionId:t.subscription_id,subscriptionType:t.subscription_type,expiresAt:t.subscription_expires_at})):(this.showSuccess("Processing Payment","Payment is being processed. Please refresh in a few moments."),this.emit("paymentPending",{email:this.currentUser.email}))}else this.showSuccess("Processing Payment","Please wait while we verify your payment...");const n=window.location.href.split("?")[0];window.history.replaceState({},document.title,n)},2e3)}};
|
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:!0});var n=require("@supabase/supabase-js");exports.MoneyBar=class{mergeConfigs(n){const t="undefined"!=typeof window?window.APP_CONFIG:null;if(!n&&!t)throw new Error("MoneyBar: No configuration provided. Either pass config to constructor or set window.APP_CONFIG");return n?t?{...t,...n}:n:t}constructor(n){this.currentUser=null,this.userFingerprint=null,this.eventListeners=new Map,this.supabaseConnectionFailed=!1,this.paymentConnectionFailed=!1,this.securityKeyFailed=!1,this.isLoadingStatus=!1,this.validatedAppName=null,this.cachedStatus=null,this.statusCacheTime=0,this.STATUS_CACHE_DURATION=6e4,this.DOWNLOAD_COUNT_CACHE_DURATION=3e4,this.initializationPromise=null,this.cachedPremiumStatus=null,this.premiumStatusCacheTime=0,this.lastCheckedEmail=null,this.lastAuthEmail=null,this.cachedSubscriptionDetails=null,this.cachedDownloadCount=null,this.downloadCountCacheTime=0,this.downloadCountPromise=null,this.premiumCheckPromise=null,this.config=this.mergeConfigs(n),this.config.options;const t=sessionStorage.getItem("moneybar_oauth_debug_before");if(t)try{const n=JSON.parse(t);console.log("🟢 [MoneyBar OAuth Debug] BEFORE AUTH (from storage):",n),sessionStorage.removeItem("moneybar_oauth_debug_before")}catch(n){}(window.location.hash.includes("access_token")||window.location.hash.includes("error"))&&console.log("🔵 [MoneyBar OAuth Debug] AFTER AUTH - Returned to URL:",{fullUrl:window.location.href,origin:window.location.origin,pathname:window.location.pathname,hash:window.location.hash.substring(0,100)+"...",expectedRedirectTo:`${window.location.origin}${window.location.pathname}`,queryParams:window.location.search}),this.validateConfig(),this.initializeSupabase(),this.initializePayment(),this.initializeFingerprint(),this.setupAuthListener(),this.checkPaymentStatus()}async handleDownload(){try{if(this.securityKeyFailed)return void this.showError("Invalid Security Key","Your security key is invalid, expired, or not found. Please check your MoneyBar configuration and ensure you have a valid security_key.");if(this.supabaseConnectionFailed)return void this.config.callbacks?.onError?.(new Error("Server connection required for download verification. Please check your configuration."));if(this.config.payment&&this.paymentConnectionFailed)return void this.config.callbacks?.onError?.(new Error("Payment configuration error. Please contact support."));if(this.currentUser){const{isPremium:n}=await this.checkPremiumStatus(this.currentUser.email);if(n)return void this.config.callbacks?.onPremiumDownload()}const n=await this.getDownloadStatus();if(n.currentCount>=n.limit)return void this.config.callbacks?.onLimitReached(n.currentCount,n.limit);await this.incrementDownloadCount(),this.config.callbacks?.onDownloadAllowed(),this.cachedStatus=null;const t=await this.getDownloadStatus();this.emit("countChanged",{count:t.currentCount,limit:t.limit,remaining:t.remaining}),t.currentCount>=t.limit&&setTimeout(()=>{this.config.callbacks?.onLimitReached(t.currentCount,t.limit)},100)}catch(n){this.handleError(n)}}async getDownloadStatus(n=!1){const t=this.cachedStatus?Date.now()-this.statusCacheTime:-1;if(!n&&this.cachedStatus&&t<this.STATUS_CACHE_DURATION)return this.cachedStatus;if(!n&&this.initializationPromise)return await this.initializationPromise;this.initializationPromise=this.fetchFreshStatus(n);try{return await this.initializationPromise}finally{this.initializationPromise=null}}async fetchFreshStatus(n){try{let t=0,e=!1;if(this.currentUser){const a=null!==this.cachedPremiumStatus&&Date.now()-this.premiumStatusCacheTime<this.STATUS_CACHE_DURATION;if(n||!a){e=(await this.checkPremiumStatus(this.currentUser.email)).isPremium,this.cachedPremiumStatus=e,this.premiumStatusCacheTime=Date.now()}else e=this.cachedPremiumStatus;if(e)console.log("🔍 [OPTIMIZATION] User is premium - skipping download count check"),t=0;else if(n||!this.cachedStatus){if(t=await this.getDownloadCount(),this.securityKeyFailed)return{currentCount:0,limit:this.config.freeAttemptLimit,isPremium:!1,isAuthenticated:!1,remaining:0}}else t=this.cachedStatus.currentCount}else if(e=!1,n||!this.cachedStatus){if(t=await this.getDownloadCount(),this.securityKeyFailed)return{currentCount:0,limit:this.config.freeAttemptLimit,isPremium:!1,isAuthenticated:!1,remaining:0}}else t=this.cachedStatus.currentCount;const a={currentCount:t,limit:this.config.freeAttemptLimit,isPremium:e,isAuthenticated:!!this.currentUser,remaining:Math.max(0,this.config.freeAttemptLimit-t)};return this.cachedStatus=a,this.statusCacheTime=Date.now(),a}catch(n){this.handleError(n);const t={currentCount:0,limit:this.config.freeAttemptLimit,isPremium:!1,isAuthenticated:!1,remaining:this.config.freeAttemptLimit};return this.cachedStatus=t,this.statusCacheTime=Date.now(),t}}async getUserContext(n){const t=n||await this.getDownloadStatus(),e={isPremium:t.isPremium,isAuthenticated:t.isAuthenticated,email:this.currentUser?.email,name:this.currentUser?.user_metadata?.full_name||this.currentUser?.user_metadata?.name,currentCount:t.currentCount,remaining:t.remaining,limit:t.limit,user:this.currentUser};if(this.currentUser&&t.isPremium){const{subscriptionDetails:n}=await this.checkPremiumStatus(this.currentUser.email);n&&(e.subscriptionType=n.subscription_type,e.subscriptionId=n.subscription_id,e.subscriptionExpiresAt=n.subscription_expires_at,e.subscriptionDaysRemaining=n.days_remaining,e.isSubscriptionActive=n.is_subscription_active,e.nextBillingDate=n.next_billing_date,e.billingFrequency=n.billing_frequency,e.customerId=n.customer_id)}return e}async signIn(){try{const n=`${window.location.origin}${window.location.pathname}`,t={currentUrl:window.location.href,origin:window.location.origin,pathname:window.location.pathname,redirectTo:n,provider:"google",timestamp:(new Date).toISOString()};console.log("🟢 [MoneyBar OAuth Debug] BEFORE AUTH - Initiating OAuth with:",t),sessionStorage.setItem("moneybar_oauth_debug_before",JSON.stringify(t));const{error:e}=await this.supabase.auth.signInWithOAuth({provider:"google",options:{redirectTo:n}});if(e)throw e}catch(n){this.handleError(n)}}async signOut(){try{await this.supabase.auth.signOut(),this.currentUser=null,this.emit("authChanged",{user:null,isAuthenticated:!1,isPremium:!1})}catch(n){this.handleError(n)}}async createPayment(){if(!this.currentUser)throw new Error("User must be signed in to create payment");if(!this.config.payment)throw new Error("Payment configuration not provided");const n=this.config.payment?.find(n=>"dodo"===n.provider);if(!n)throw new Error("No dodo payment provider configured");const t={email:this.currentUser.email,product_id:n.productId,mode:n.mode||"test",app_id:this.validatedAppName||"unknown",return_url:`${window.location.origin}${window.location.pathname}?payment=success`};try{let e;if("dodo"!==n.provider)throw new Error(`Payment provider '${n.provider}' is not yet supported`);if(e=await fetch(`${this.config.supabase.url}/functions/v1/create-payment`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${this.config.supabase.anonKey}`},body:JSON.stringify(t)}),this.config.options,!e.ok){const n=await e.text();let t;this.config.options?.debug&&console.error("🔍 DEBUG: createPayment error response:",n);try{t=JSON.parse(n)}catch{t={error:n}}throw(n.includes("404")||n.includes("could not be found"))&&(this.paymentConnectionFailed=!0,this.config.options?.debug&&console.warn("Invalid payment product ID detected, disabling downloads"),this.updateStatusDisplays()),new Error(t.error||"Payment creation failed")}const a=await e.json();return this.config.options,a}catch(n){return this.handleError(n),null}}async openCustomerPortal(n){try{if(!this.config.payment)throw new Error("Payment configuration not provided");const t=this.config.payment?.find(n=>"dodo"===n.provider);if(!t)throw new Error("No dodo payment provider configured");const e={customer_id:n,mode:t.mode||"test"},a=await fetch(`${this.config.supabase.url}/functions/v1/create-customer-portal`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${this.config.supabase.anonKey}`},body:JSON.stringify(e)});if(!a.ok){const n=await a.json().catch(()=>({error:"Unknown error"}));throw new Error(n.error||"Failed to create customer portal session")}const o=await a.json();o.link&&window.open(o.link,"_blank")}catch(n){console.error("Failed to open customer portal:",n),this.handleError(n)}}attachToButton(n,t){const e=document.querySelector(n);if(!e)throw new Error(`Button not found: ${n}`);this.injectBaseStyles(),this.createTitleBar(),this.createPaywallModal(),this.createSuccessModal(),this.createAuthUI(),this.createStatusDisplay(),e.setAttribute("data-leadfast-attached","true"),e.onclick=async n=>{n.preventDefault(),await this.handleButtonClick(t)},this.setupUIUpdates()}attachToButtons(n){this.injectBaseStyles(),this.createTitleBar(),this.createPaywallModal(),this.createSuccessModal(),this.createAuthUI(),n.buttons.forEach(n=>{const t=document.querySelector(n.selector);t?(t.setAttribute("data-leadfast-attached","true"),t.onclick=async t=>{t.preventDefault(),await this.handleButtonClick(n.downloadCallback)},this.setupUIUpdates()):console.warn(`Button not found: ${n.selector}`)}),this.createGlobalStatusDisplay()}async handleButtonClick(n){const t=document.querySelectorAll('[data-leadfast-attached="true"]');if(Array.from(t).some(n=>n.disabled))console.log("⚠️ Button click ignored - operation already in progress");else{t.forEach(n=>{n.disabled=!0,n.style.opacity="0.6"});try{await this.handleButtonClickInternal(n)}finally{t.forEach(n=>{n.disabled=!1,n.style.opacity="1"})}}}async handleButtonClickInternal(n){if(this.supabaseConnectionFailed)return void this.showConnectionError();if(this.config.payment&&this.paymentConnectionFailed)return void this.showPaymentConfigError();const t=this.cachedStatus&&Date.now()-this.statusCacheTime<this.STATUS_CACHE_DURATION?this.cachedStatus:await this.getDownloadStatus();if(t.isPremium){const t=await this.getUserContext();return void(n.length>0?n(t):n())}if(t.currentCount>=t.limit)this.showPaywallInstant(t);else{try{if(n.length>0){const t=n(await this.getUserContext());t&&"object"==typeof t&&"then"in t&&await t}else{const t=n();t&&"object"==typeof t&&"then"in t&&await t}const t=await this.getDownloadStatus(!0);if(t.currentCount>=t.limit)return console.warn(`⚠️ Limit reached during execution (${t.currentCount}/${t.limit}) - canceling increment`),void alert("⚠️ You reached the limit while this action was processing. No attempt was counted.");const e=await this.incrementDownloadCount();if(e>this.config.freeAttemptLimit)return void console.error(`⚠️ Server returned count (${e}) exceeding limit (${this.config.freeAttemptLimit})`);if(!0===this.config.successMessage?.enabled){const n=this.config.successMessage?.title||"Action Completed!",t=this.config.successMessage?.message||"Your action completed successfully!";this.showSuccess(n,t)}}catch(n){return console.error("User function failed:",n),void alert("Action failed. Please check the console for details. No attempt was counted.")}this.cachedStatus=null,this.updateStatusDisplays()}}injectBaseStyles(){if(document.getElementById("lead-fast-styles"))return;this.config.theme?.name&&this.injectDaisyUI();const n=document.createElement("style");n.id="lead-fast-styles";const t=this.config.theme?.primaryColor||"#3182ce";n.textContent=`\n /* User Profile Card - Top Right */\n .lead-fast-profile {\n position: fixed;\n top: 20px;\n left: 50%;\n transform: translateX(-50%);\n z-index: 1000;\n font-family: system-ui, -apple-system, sans-serif;\n width: 90%;\n max-width: 1200px;\n }\n\n .lead-fast-title-bar {\n background: rgba(250, 247, 245, 0.9) !important;\n border: 1px solid rgba(231, 226, 223, 0.6) !important;\n color: #291334 !important;\n border-radius: 16px;\n padding: 12px 24px;\n box-shadow: 0 8px 32px rgb(0 0 0 / 0.1), 0 2px 8px rgb(0 0 0 / 0.05);\n backdrop-filter: blur(20px);\n display: flex;\n align-items: center;\n justify-content: space-between;\n min-height: 60px;\n font-family: system-ui, -apple-system, sans-serif;\n }\n\n /* Theme variations for floating title bar */\n [data-theme="bumblebee"] .lead-fast-title-bar {\n background: rgba(255, 248, 220, 0.9) !important;\n border-color: rgba(254, 215, 170, 0.6) !important;\n color: #1c1917 !important;\n }\n\n [data-theme="garden"] .lead-fast-title-bar {\n background: rgba(240, 253, 244, 0.9) !important;\n border-color: rgba(134, 239, 172, 0.6) !important;\n color: #14532d !important;\n }\n\n [data-theme="emerald"] .lead-fast-title-bar {\n background: rgba(236, 253, 245, 0.9) !important;\n border-color: rgba(167, 243, 208, 0.6) !important;\n color: #065f46 !important;\n }\n\n [data-theme="corporate"] .lead-fast-title-bar {\n background: rgba(248, 250, 252, 0.9) !important;\n border-color: rgba(226, 232, 240, 0.6) !important;\n color: #1e293b !important;\n }\n\n [data-theme="dark"] .lead-fast-title-bar {\n background: rgba(31, 41, 55, 0.9) !important;\n border-color: rgba(55, 65, 81, 0.6) !important;\n color: #f9fafb !important;\n }\n\n [data-theme="cyberpunk"] .lead-fast-title-bar {\n background: rgba(0, 20, 36, 0.9) !important;\n border-color: rgba(7, 89, 133, 0.6) !important;\n color: #0ea5e9 !important;\n box-shadow: 0 8px 32px rgba(14, 165, 233, 0.2), 0 2px 8px rgba(14, 165, 233, 0.1);\n }\n\n [data-theme="valentine"] .lead-fast-title-bar {\n background: rgba(233, 30, 122, 0.15) !important;\n border-color: rgba(233, 30, 122, 0.6) !important;\n color: #831843 !important;\n }\n\n [data-theme="synthwave"] .lead-fast-title-bar {\n background: rgba(32, 20, 64, 0.9) !important;\n border-color: rgba(186, 85, 211, 0.6) !important;\n color: #ff00ff !important;\n box-shadow: 0 8px 32px rgba(255, 0, 255, 0.2), 0 2px 8px rgba(255, 0, 255, 0.1);\n }\n\n [data-theme="dracula"] .lead-fast-title-bar {\n background: rgba(40, 42, 54, 0.9) !important;\n border-color: rgba(98, 114, 164, 0.6) !important;\n color: #f8f8f2 !important;\n }\n\n [data-theme="halloween"] .lead-fast-title-bar {\n background: rgba(26, 26, 26, 0.9) !important;\n border-color: rgba(255, 165, 0, 0.6) !important;\n color: #ff6600 !important;\n }\n\n [data-theme="forest"] .lead-fast-title-bar {\n background: rgba(23, 46, 23, 0.9) !important;\n border-color: rgba(34, 197, 94, 0.6) !important;\n color: #22c55e !important;\n }\n\n [data-theme="luxury"] .lead-fast-title-bar {\n background: rgba(9, 9, 11, 0.9) !important;\n border-color: rgba(212, 175, 55, 0.6) !important;\n color: #d4af37 !important;\n }\n\n [data-theme="night"] .lead-fast-title-bar {\n background: rgba(15, 23, 42, 0.9) !important;\n border-color: rgba(30, 58, 138, 0.6) !important;\n color: #60a5fa !important;\n }\n\n [data-theme="light"] .lead-fast-title-bar {\n background: rgba(255, 255, 255, 0.9) !important;\n border-color: rgba(229, 231, 235, 0.6) !important;\n color: #1f2937 !important;\n }\n\n [data-theme="cupcake"] .lead-fast-title-bar {\n background: rgba(250, 235, 215, 0.9) !important;\n border-color: rgba(219, 185, 156, 0.6) !important;\n color: #8b4513 !important;\n }\n\n [data-theme="retro"] .lead-fast-title-bar {\n background: rgba(212, 165, 116, 0.9) !important;\n border-color: rgba(185, 144, 102, 0.6) !important;\n color: #5d4037 !important;\n }\n\n [data-theme="aqua"] .lead-fast-title-bar {\n background: rgba(240, 253, 250, 0.9) !important;\n border-color: rgba(125, 211, 252, 0.6) !important;\n color: #155e75 !important;\n }\n\n [data-theme="lofi"] .lead-fast-title-bar {\n background: rgba(248, 248, 248, 0.9) !important;\n border-color: rgba(68, 68, 68, 0.6) !important;\n color: #1a1a1a !important;\n }\n\n [data-theme="pastel"] .lead-fast-title-bar {\n background: rgba(254, 251, 255, 0.9) !important;\n border-color: rgba(209, 196, 233, 0.6) !important;\n color: #7c3aed !important;\n }\n\n [data-theme="fantasy"] .lead-fast-title-bar {\n background: rgba(255, 247, 237, 0.9) !important;\n border-color: rgba(249, 168, 212, 0.6) !important;\n color: #be185d !important;\n }\n\n [data-theme="wireframe"] .lead-fast-title-bar {\n background: rgba(223, 223, 223, 0.9) !important;\n border-color: rgba(0, 0, 0, 0.3) !important;\n color: #000000 !important;\n }\n\n [data-theme="black"] .lead-fast-title-bar {\n background: rgba(0, 0, 0, 0.9) !important;\n border-color: rgba(55, 55, 55, 0.6) !important;\n color: #ffffff !important;\n }\n\n [data-theme="cmyk"] .lead-fast-title-bar {\n background: rgba(0, 255, 255, 0.9) !important;\n border-color: rgba(255, 0, 255, 0.6) !important;\n color: #000000 !important;\n }\n\n [data-theme="autumn"] .lead-fast-title-bar {\n background: rgba(139, 69, 19, 0.9) !important;\n border-color: rgba(255, 140, 0, 0.6) !important;\n color: #ff8c00 !important;\n }\n\n [data-theme="business"] .lead-fast-title-bar {\n background: rgba(29, 78, 216, 0.9) !important;\n border-color: rgba(59, 130, 246, 0.6) !important;\n color: #3b82f6 !important;\n }\n\n [data-theme="acid"] .lead-fast-title-bar {\n background: rgba(255, 255, 0, 0.9) !important;\n border-color: rgba(255, 0, 255, 0.6) !important;\n color: #000000 !important;\n }\n\n [data-theme="lemonade"] .lead-fast-title-bar {\n background: rgba(255, 255, 224, 0.9) !important;\n border-color: rgba(34, 197, 94, 0.6) !important;\n color: #15803d !important;\n }\n\n [data-theme="coffee"] .lead-fast-title-bar {\n background: rgba(101, 67, 33, 0.9) !important;\n border-color: rgba(160, 82, 45, 0.6) !important;\n color: #d2b48c !important;\n }\n\n [data-theme="winter"] .lead-fast-title-bar {\n background: rgba(248, 250, 252, 0.9) !important;\n border-color: rgba(59, 130, 246, 0.6) !important;\n color: #1e40af !important;\n }\n\n .lead-fast-title-section {\n display: flex;\n align-items: center;\n gap: 16px;\n }\n\n .lead-fast-logo {\n font-size: 20px;\n font-weight: 700;\n display: flex;\n align-items: center;\n gap: 8px;\n color: inherit;\n text-decoration: none;\n }\n\n .lead-fast-logo img {\n width: 32px;\n height: 32px;\n border-radius: 6px;\n }\n\n .lead-fast-nav {\n display: flex;\n align-items: center;\n gap: 32px;\n margin-left: 24px;\n }\n\n .lead-fast-nav-link {\n color: inherit;\n text-decoration: none;\n font-weight: 500;\n font-size: 14px;\n opacity: 0.8;\n transition: all 0.2s;\n }\n\n .lead-fast-nav-link:hover {\n opacity: 1;\n text-decoration: none;\n }\n\n .lead-fast-user-section {\n display: flex;\n align-items: center;\n gap: 12px;\n }\n\n .lead-fast-avatar {\n width: 36px;\n height: 36px;\n border-radius: 50%;\n background: linear-gradient(135deg, ${t}, #4f46e5);\n display: flex;\n align-items: center;\n justify-content: center;\n color: white;\n font-weight: 600;\n font-size: 14px;\n }\n\n .lead-fast-user-info {\n display: flex;\n flex-direction: column;\n align-items: flex-start;\n gap: 2px;\n }\n\n .lead-fast-user-email {\n color: inherit !important;\n font-size: 13px;\n font-weight: 500;\n line-height: 1;\n }\n\n .lead-fast-user-status {\n display: flex;\n align-items: center;\n gap: 6px;\n }\n\n .lead-fast-badge {\n padding: 2px 6px;\n border-radius: 12px;\n font-size: 10px;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.025em;\n line-height: 1;\n }\n\n .lead-fast-badge.premium {\n background: #10b981 !important;\n color: #ffffff !important;\n }\n\n .lead-fast-badge.free {\n background: #65c3c8 !important;\n color: #291334 !important;\n }\n\n [data-theme="dark"] .lead-fast-badge.premium {\n background: #059669 !important;\n color: #ffffff !important;\n }\n\n [data-theme="dark"] .lead-fast-badge.free {\n background: #374151 !important;\n color: #f9fafb !important;\n }\n\n .lead-fast-info-icon {\n display: inline-block;\n margin-left: 3px;\n font-size: 11px;\n opacity: 0.8;\n cursor: help;\n transition: opacity 0.2s;\n }\n\n .lead-fast-info-icon:hover {\n opacity: 1;\n }\n\n /* Subscription Tooltip */\n .lead-fast-subscription-tooltip {\n position: fixed;\n z-index: 10000;\n background: rgba(0, 0, 0, 0.92);\n border-radius: 8px;\n padding: 0;\n box-shadow: 0 8px 24px rgba(0, 0, 0, 0.3);\n min-width: 260px;\n opacity: 0;\n pointer-events: none;\n transform: translateY(-5px);\n transition: opacity 0.2s, transform 0.2s;\n }\n\n .lead-fast-subscription-tooltip.show {\n opacity: 1;\n pointer-events: auto;\n transform: translateY(0);\n }\n\n .lead-fast-subscription-tooltip .tooltip-content {\n padding: 12px 16px;\n }\n\n .lead-fast-subscription-tooltip .tooltip-header {\n font-size: 13px;\n font-weight: 600;\n color: #fff;\n margin-bottom: 8px;\n }\n\n .lead-fast-subscription-tooltip .tooltip-divider {\n height: 1px;\n background: rgba(255, 255, 255, 0.1);\n margin: 8px 0;\n }\n\n .lead-fast-subscription-tooltip .tooltip-row {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 6px 0;\n font-size: 12px;\n }\n\n .lead-fast-subscription-tooltip .tooltip-label {\n color: rgba(255, 255, 255, 0.7);\n font-weight: 500;\n }\n\n .lead-fast-subscription-tooltip .tooltip-value {\n color: #fff;\n font-weight: 600;\n text-align: right;\n }\n\n .lead-fast-subscription-tooltip .tooltip-link {\n display: block;\n text-align: center;\n margin-top: 12px;\n padding-top: 12px;\n border-top: 1px solid rgba(255, 255, 255, 0.1);\n }\n\n .lead-fast-subscription-tooltip .manage-link {\n color: #60a5fa;\n text-decoration: none;\n font-size: 12px;\n font-weight: 500;\n cursor: pointer;\n transition: color 0.2s;\n }\n\n .lead-fast-subscription-tooltip .manage-link:hover {\n color: #93c5fd;\n text-decoration: underline;\n }\n\n .lead-fast-count {\n font-size: 10px;\n color: inherit !important;\n opacity: 0.7;\n line-height: 1;\n }\n\n .lead-fast-signout {\n background: rgba(0, 0, 0, 0.1) !important;\n border: none;\n color: inherit !important;\n cursor: pointer;\n padding: 6px 12px;\n border-radius: 8px;\n transition: all 0.2s;\n font-size: 11px;\n font-weight: 500;\n margin-left: 8px;\n }\n\n [data-theme="dark"] .lead-fast-signout {\n background: rgba(255, 255, 255, 0.1) !important;\n }\n\n [data-theme="cyberpunk"] .lead-fast-signout {\n background: rgba(14, 165, 233, 0.2) !important;\n }\n\n .lead-fast-signout:hover {\n background: rgba(0, 0, 0, 0.2) !important;\n transform: translateY(-1px);\n }\n\n [data-theme="dark"] .lead-fast-signout:hover {\n background: rgba(255, 255, 255, 0.2) !important;\n }\n\n [data-theme="cyberpunk"] .lead-fast-signout:hover {\n background: rgba(14, 165, 233, 0.3) !important;\n }\n\n .lead-fast-branding {\n position: absolute;\n bottom: -20px;\n left: 24px;\n font-size: 9px;\n color: inherit !important;\n opacity: 0.4;\n font-weight: 500;\n letter-spacing: 0.05em;\n text-transform: lowercase;\n background: rgba(255, 255, 255, 0.8);\n padding: 2px 6px;\n border-radius: 4px;\n backdrop-filter: blur(8px);\n }\n\n [data-theme="dark"] .lead-fast-branding {\n background: rgba(0, 0, 0, 0.6);\n }\n\n [data-theme="cyberpunk"] .lead-fast-branding {\n background: rgba(0, 20, 36, 0.8);\n }\n\n /* Modal Theming */\n .download-limiter-modal {\n display: none;\n position: fixed;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n background: rgba(0,0,0,0.5);\n z-index: 9999;\n align-items: center;\n justify-content: center;\n }\n .download-limiter-modal.show { display: flex; }\n\n .download-limiter-content {\n background: #faf7f5 !important;\n color: #291334 !important;\n padding: 2rem;\n border-radius: 12px;\n max-width: 400px;\n text-align: center;\n box-shadow: 0 20px 25px -5px rgb(0 0 0 / 0.1), 0 8px 10px -6px rgb(0 0 0 / 0.1);\n border: 1px solid #e7e2df !important;\n font-family: system-ui, -apple-system, sans-serif;\n }\n\n [data-theme="dark"] .download-limiter-content {\n background: #1f2937 !important;\n color: #f9fafb !important;\n border-color: #374151 !important;\n }\n\n [data-theme="cyberpunk"] .download-limiter-content {\n background: #001424 !important;\n color: #0ea5e9 !important;\n border-color: #075985 !important;\n }\n\n [data-theme="valentine"] .download-limiter-content {\n background: rgba(233, 30, 122, 0.05) !important;\n color: #831843 !important;\n border-color: #e91e7a !important;\n }\n\n [data-theme="bumblebee"] .download-limiter-content {\n background: rgba(255, 248, 220, 0.95) !important;\n color: #1c1917 !important;\n border-color: rgba(254, 215, 170, 0.8) !important;\n }\n\n [data-theme="garden"] .download-limiter-content {\n background: rgba(240, 253, 244, 0.95) !important;\n color: #14532d !important;\n border-color: rgba(134, 239, 172, 0.8) !important;\n }\n\n [data-theme="emerald"] .download-limiter-content {\n background: rgba(236, 253, 245, 0.95) !important;\n color: #065f46 !important;\n border-color: rgba(167, 243, 208, 0.8) !important;\n }\n\n [data-theme="corporate"] .download-limiter-content {\n background: rgba(248, 250, 252, 0.95) !important;\n color: #1e293b !important;\n border-color: rgba(226, 232, 240, 0.8) !important;\n }\n\n [data-theme="forest"] .download-limiter-content {\n background: rgba(23, 46, 23, 0.95) !important;\n color: #22c55e !important;\n border-color: rgba(34, 197, 94, 0.8) !important;\n }\n\n [data-theme="halloween"] .download-limiter-content {\n background: rgba(26, 26, 26, 0.95) !important;\n color: #ff6500 !important;\n border-color: rgba(255, 165, 0, 0.3) !important;\n }\n\n [data-theme="synthwave"] .download-limiter-content {\n background: rgba(32, 20, 64, 0.95) !important;\n color: #ba55d3 !important;\n border-color: rgba(186, 85, 211, 0.3) !important;\n }\n\n [data-theme="dracula"] .download-limiter-content {\n background: rgba(40, 42, 54, 0.95) !important;\n color: #f8f8f2 !important;\n border-color: rgba(98, 114, 164, 0.3) !important;\n }\n\n [data-theme="luxury"] .download-limiter-content {\n background: rgba(9, 9, 11, 0.95) !important;\n color: #d4af37 !important;\n border-color: rgba(212, 175, 55, 0.3) !important;\n }\n\n [data-theme="night"] .download-limiter-content {\n background: rgba(15, 23, 42, 0.95) !important;\n color: #1e40af !important;\n border-color: rgba(30, 58, 138, 0.3) !important;\n }\n\n [data-theme="light"] .download-limiter-content {\n background: rgba(255, 255, 255, 0.95) !important;\n color: #1f2937 !important;\n border-color: rgba(229, 231, 235, 0.8) !important;\n }\n\n [data-theme="cupcake"] .download-limiter-content {\n background: rgba(250, 235, 215, 0.95) !important;\n color: #8b4513 !important;\n border-color: rgba(219, 185, 156, 0.8) !important;\n }\n\n [data-theme="retro"] .download-limiter-content {\n background: rgba(212, 165, 116, 0.95) !important;\n color: #5d4037 !important;\n border-color: rgba(185, 144, 102, 0.8) !important;\n }\n\n [data-theme="aqua"] .download-limiter-content {\n background: rgba(240, 253, 250, 0.95) !important;\n color: #155e75 !important;\n border-color: rgba(125, 211, 252, 0.8) !important;\n }\n\n [data-theme="lofi"] .download-limiter-content {\n background: rgba(248, 248, 248, 0.95) !important;\n color: #1a1a1a !important;\n border-color: rgba(68, 68, 68, 0.8) !important;\n }\n\n [data-theme="pastel"] .download-limiter-content {\n background: rgba(254, 251, 255, 0.95) !important;\n color: #7c3aed !important;\n border-color: rgba(209, 196, 233, 0.8) !important;\n }\n\n [data-theme="fantasy"] .download-limiter-content {\n background: rgba(255, 247, 237, 0.95) !important;\n color: #be185d !important;\n border-color: rgba(249, 168, 212, 0.8) !important;\n }\n\n [data-theme="wireframe"] .download-limiter-content {\n background: rgba(255, 255, 255, 0.95) !important;\n color: #000000 !important;\n border-color: rgba(0, 0, 0, 0.3) !important;\n }\n\n [data-theme="black"] .download-limiter-content {\n background: rgba(0, 0, 0, 0.95) !important;\n color: #ffffff !important;\n border-color: rgba(55, 55, 55, 0.8) !important;\n }\n\n [data-theme="cmyk"] .download-limiter-content {\n background: rgba(0, 255, 255, 0.95) !important;\n color: #000000 !important;\n border-color: rgba(255, 0, 255, 0.8) !important;\n }\n\n [data-theme="autumn"] .download-limiter-content {\n background: rgba(139, 69, 19, 0.95) !important;\n color: #ff8c00 !important;\n border-color: rgba(255, 140, 0, 0.8) !important;\n }\n\n [data-theme="business"] .download-limiter-content {\n background: rgba(29, 78, 216, 0.95) !important;\n color: #3b82f6 !important;\n border-color: rgba(59, 130, 246, 0.8) !important;\n }\n\n [data-theme="acid"] .download-limiter-content {\n background: rgba(255, 255, 0, 0.95) !important;\n color: #000000 !important;\n border-color: rgba(255, 0, 255, 0.8) !important;\n }\n\n [data-theme="lemonade"] .download-limiter-content {\n background: rgba(255, 255, 224, 0.95) !important;\n color: #15803d !important;\n border-color: rgba(34, 197, 94, 0.8) !important;\n }\n\n [data-theme="coffee"] .download-limiter-content {\n background: rgba(101, 67, 33, 0.95) !important;\n color: #d2b48c !important;\n border-color: rgba(160, 82, 45, 0.8) !important;\n }\n\n [data-theme="winter"] .download-limiter-content {\n background: rgba(248, 250, 252, 0.95) !important;\n color: #1e40af !important;\n border-color: rgba(59, 130, 246, 0.8) !important;\n }\n\n .download-limiter-content h2 {\n color: inherit !important;\n margin: 0 0 1rem 0;\n font-size: 1.5rem;\n font-weight: 600;\n }\n .download-limiter-content p {\n color: inherit !important;\n margin: 0 0 1.5rem 0;\n line-height: 1.6;\n }\n .download-limiter-signin-btn {\n display: inline-flex;\n align-items: center;\n gap: 8px;\n background: #65c3c8 !important;\n color: #291334 !important;\n border: none;\n padding: 12px 20px;\n border-radius: 8px;\n font-size: 14px;\n font-weight: 500;\n cursor: pointer;\n text-decoration: none;\n transition: all 0.2s;\n box-shadow: 0 2px 4px rgba(0,0,0,0.1);\n }\n\n [data-theme="dark"] .download-limiter-signin-btn {\n background: #3b82f6 !important;\n color: #ffffff !important;\n }\n\n [data-theme="cyberpunk"] .download-limiter-signin-btn {\n background: #f59e0b !important;\n color: #000000 !important;\n }\n\n [data-theme="valentine"] .download-limiter-signin-btn {\n background: #e91e7a !important;\n color: #ffffff !important;\n }\n\n [data-theme="bumblebee"] .download-limiter-signin-btn {\n background: #fbbf24 !important;\n color: #1c1917 !important;\n }\n\n [data-theme="garden"] .download-limiter-signin-btn {\n background: #22c55e !important;\n color: #ffffff !important;\n }\n\n [data-theme="emerald"] .download-limiter-signin-btn {\n background: #10b981 !important;\n color: #ffffff !important;\n }\n\n [data-theme="corporate"] .download-limiter-signin-btn {\n background: #3b82f6 !important;\n color: #ffffff !important;\n }\n\n [data-theme="forest"] .download-limiter-signin-btn {\n background: #22c55e !important;\n color: #1a1a1a !important;\n }\n\n [data-theme="halloween"] .download-limiter-signin-btn {\n background: #ff6500 !important;\n color: #1a1a1a !important;\n }\n\n [data-theme="synthwave"] .download-limiter-signin-btn {\n background: #ba55d3 !important;\n color: #201040 !important;\n }\n\n [data-theme="dracula"] .download-limiter-signin-btn {\n background: #8be9fd !important;\n color: #282a36 !important;\n }\n\n [data-theme="luxury"] .download-limiter-signin-btn {\n background: #d4af37 !important;\n color: #09090b !important;\n }\n\n [data-theme="night"] .download-limiter-signin-btn {\n background: #1e40af !important;\n color: #ffffff !important;\n }\n\n [data-theme="light"] .download-limiter-signin-btn {\n background: #3b82f6 !important;\n color: #ffffff !important;\n }\n\n [data-theme="cupcake"] .download-limiter-signin-btn {\n background: #8b4513 !important;\n color: #ffffff !important;\n }\n\n [data-theme="retro"] .download-limiter-signin-btn {\n background: #d4a574 !important;\n color: #ffffff !important;\n }\n\n [data-theme="aqua"] .download-limiter-signin-btn {\n background: #0891b2 !important;\n color: #ffffff !important;\n }\n\n [data-theme="lofi"] .download-limiter-signin-btn {\n background: #1a1a1a !important;\n color: #ffffff !important;\n }\n\n [data-theme="pastel"] .download-limiter-signin-btn {\n background: #7c3aed !important;\n color: #ffffff !important;\n }\n\n [data-theme="fantasy"] .download-limiter-signin-btn {\n background: #be185d !important;\n color: #ffffff !important;\n }\n\n [data-theme="wireframe"] .download-limiter-signin-btn {\n background: #dfdfdf !important;\n color: #000000 !important;\n border: 1px solid #000000 !important;\n }\n\n [data-theme="black"] .download-limiter-signin-btn {\n background: #ffffff !important;\n color: #000000 !important;\n }\n\n [data-theme="cmyk"] .download-limiter-signin-btn {\n background: #ff00ff !important;\n color: #000000 !important;\n }\n\n [data-theme="autumn"] .download-limiter-signin-btn {\n background: #ff8c00 !important;\n color: #ffffff !important;\n }\n\n [data-theme="business"] .download-limiter-signin-btn {\n background: #3b82f6 !important;\n color: #ffffff !important;\n }\n\n [data-theme="acid"] .download-limiter-signin-btn {\n background: #ff00ff !important;\n color: #000000 !important;\n }\n\n [data-theme="lemonade"] .download-limiter-signin-btn {\n background: #22c55e !important;\n color: #ffffff !important;\n }\n\n [data-theme="coffee"] .download-limiter-signin-btn {\n background: #a0522d !important;\n color: #ffffff !important;\n }\n\n [data-theme="winter"] .download-limiter-signin-btn {\n background: #3b82f6 !important;\n color: #ffffff !important;\n }\n\n .download-limiter-signin-btn:hover {\n opacity: 0.9;\n transform: translateY(-1px);\n box-shadow: 0 4px 8px rgba(0,0,0,0.15);\n }\n\n /* Upgrade Button Styles for All Themes */\n [data-theme="dark"] .upgrade-btn {\n background: #3b82f6 !important;\n color: #ffffff !important;\n }\n\n [data-theme="cyberpunk"] .upgrade-btn {\n background: #ff073a !important;\n color: #ffffff !important;\n }\n\n [data-theme="valentine"] .upgrade-btn {\n background: #e91e7a !important;\n color: #ffffff !important;\n }\n\n [data-theme="bumblebee"] .upgrade-btn {\n background: #f59e0b !important;\n color: #ffffff !important;\n }\n\n [data-theme="garden"] .upgrade-btn {\n background: #10b981 !important;\n color: #ffffff !important;\n }\n\n [data-theme="emerald"] .upgrade-btn {\n background: #10b981 !important;\n color: #ffffff !important;\n }\n\n [data-theme="corporate"] .upgrade-btn {\n background: #3b82f6 !important;\n color: #ffffff !important;\n }\n\n [data-theme="forest"] .upgrade-btn {\n background: #10b981 !important;\n color: #ffffff !important;\n }\n\n [data-theme="halloween"] .upgrade-btn {\n background: #ff7b00 !important;\n color: #000000 !important;\n }\n\n [data-theme="synthwave"] .upgrade-btn {\n background: #e879f9 !important;\n color: #ffffff !important;\n }\n\n [data-theme="dracula"] .upgrade-btn {\n background: #bd93f9 !important;\n color: #ffffff !important;\n }\n\n [data-theme="luxury"] .upgrade-btn {\n background: #d4af37 !important;\n color: #000000 !important;\n }\n\n [data-theme="night"] .upgrade-btn {\n background: #38bdf8 !important;\n color: #ffffff !important;\n }\n\n [data-theme="light"] .upgrade-btn {\n background: #3b82f6 !important;\n color: #ffffff !important;\n }\n\n [data-theme="cupcake"] .upgrade-btn {\n background: #f472b6 !important;\n color: #ffffff !important;\n }\n\n [data-theme="retro"] .upgrade-btn {\n background: #d4a574 !important;\n color: #ffffff !important;\n }\n\n [data-theme="aqua"] .upgrade-btn {\n background: #06b6d4 !important;\n color: #ffffff !important;\n }\n\n [data-theme="lofi"] .upgrade-btn {\n background: #a3a3a3 !important;\n color: #000000 !important;\n }\n\n [data-theme="pastel"] .upgrade-btn {\n background: #a78bfa !important;\n color: #ffffff !important;\n }\n\n [data-theme="fantasy"] .upgrade-btn {\n background: #f472b6 !important;\n color: #ffffff !important;\n }\n\n [data-theme="wireframe"] .upgrade-btn {\n background: #dfdfdf !important;\n color: #000000 !important;\n border: 1px solid #000000 !important;\n }\n\n [data-theme="black"] .upgrade-btn {\n background: #ffffff !important;\n color: #000000 !important;\n }\n\n [data-theme="cmyk"] .upgrade-btn {\n background: #0891b2 !important;\n color: #ffffff !important;\n }\n\n [data-theme="autumn"] .upgrade-btn {\n background: #d97706 !important;\n color: #ffffff !important;\n }\n\n [data-theme="business"] .upgrade-btn {\n background: #3b82f6 !important;\n color: #ffffff !important;\n }\n\n [data-theme="acid"] .upgrade-btn {\n background: #84cc16 !important;\n color: #000000 !important;\n }\n\n [data-theme="lemonade"] .upgrade-btn {\n background: #22c55e !important;\n color: #ffffff !important;\n }\n\n [data-theme="coffee"] .upgrade-btn {\n background: #a0522d !important;\n color: #ffffff !important;\n }\n\n [data-theme="winter"] .upgrade-btn {\n background: #3b82f6 !important;\n color: #ffffff !important;\n }\n\n /* Cancel Button Styles for All Themes */\n [data-theme="dark"] .cancel-btn {\n background: #4b5563 !important;\n color: #ffffff !important;\n }\n\n [data-theme="cyberpunk"] .cancel-btn {\n background: #7e22ce !important;\n color: #ffffff !important;\n }\n\n [data-theme="valentine"] .cancel-btn {\n background: #c11560 !important;\n color: #ffffff !important;\n }\n\n [data-theme="bumblebee"] .cancel-btn {\n background: #d97706 !important;\n color: #ffffff !important;\n }\n\n [data-theme="garden"] .cancel-btn {\n background: #059669 !important;\n color: #ffffff !important;\n }\n\n [data-theme="emerald"] .cancel-btn {\n background: #059669 !important;\n color: #ffffff !important;\n }\n\n [data-theme="corporate"] .cancel-btn {\n background: #6b7280 !important;\n color: #ffffff !important;\n }\n\n [data-theme="forest"] .cancel-btn {\n background: #059669 !important;\n color: #ffffff !important;\n }\n\n [data-theme="halloween"] .cancel-btn {\n background: #7c3aed !important;\n color: #ffffff !important;\n }\n\n [data-theme="synthwave"] .cancel-btn {\n background: #7e22ce !important;\n color: #ffffff !important;\n }\n\n [data-theme="dracula"] .cancel-btn {\n background: #6272a4 !important;\n color: #ffffff !important;\n }\n\n [data-theme="luxury"] .cancel-btn {\n background: #8b5cf6 !important;\n color: #ffffff !important;\n }\n\n [data-theme="night"] .cancel-btn {\n background: #0284c7 !important;\n color: #ffffff !important;\n }\n\n [data-theme="light"] .cancel-btn {\n background: #6b7280 !important;\n color: #ffffff !important;\n }\n\n [data-theme="cupcake"] .cancel-btn {\n background: #ec4899 !important;\n color: #ffffff !important;\n }\n\n [data-theme="retro"] .cancel-btn {\n background: #b8925c !important;\n color: #ffffff !important;\n }\n\n [data-theme="aqua"] .cancel-btn {\n background: #0891b2 !important;\n color: #ffffff !important;\n }\n\n [data-theme="lofi"] .cancel-btn {\n background: #6b7280 !important;\n color: #ffffff !important;\n }\n\n [data-theme="pastel"] .cancel-btn {\n background: #8b5cf6 !important;\n color: #ffffff !important;\n }\n\n [data-theme="fantasy"] .cancel-btn {\n background: #ec4899 !important;\n color: #ffffff !important;\n }\n\n [data-theme="wireframe"] .cancel-btn {\n background: #f5f5f5 !important;\n color: #000000 !important;\n border: 1px solid #000000 !important;\n }\n\n [data-theme="black"] .cancel-btn {\n background: #6b7280 !important;\n color: #ffffff !important;\n }\n\n [data-theme="cmyk"] .cancel-btn {\n background: #0369a1 !important;\n color: #ffffff !important;\n }\n\n [data-theme="autumn"] .cancel-btn {\n background: #c2410c !important;\n color: #ffffff !important;\n }\n\n [data-theme="business"] .cancel-btn {\n background: #6b7280 !important;\n color: #ffffff !important;\n }\n\n [data-theme="acid"] .cancel-btn {\n background: #65a30d !important;\n color: #ffffff !important;\n }\n\n [data-theme="lemonade"] .cancel-btn {\n background: #16a34a !important;\n color: #ffffff !important;\n }\n\n [data-theme="coffee"] .cancel-btn {\n background: #8b4513 !important;\n color: #ffffff !important;\n }\n\n [data-theme="winter"] .cancel-btn {\n background: #1e40af !important;\n color: #ffffff !important;\n }\n\n /* Success Button Styles for All Themes */\n [data-theme="dark"] .success-btn {\n background: #10b981 !important;\n color: #ffffff !important;\n }\n\n [data-theme="cyberpunk"] .success-btn {\n background: #00ff41 !important;\n color: #000000 !important;\n }\n\n [data-theme="valentine"] .success-btn {\n background: #e91e7a !important;\n color: #ffffff !important;\n }\n\n [data-theme="bumblebee"] .success-btn {\n background: #f59e0b !important;\n color: #ffffff !important;\n }\n\n [data-theme="garden"] .success-btn {\n background: #10b981 !important;\n color: #ffffff !important;\n }\n\n [data-theme="emerald"] .success-btn {\n background: #10b981 !important;\n color: #ffffff !important;\n }\n\n [data-theme="corporate"] .success-btn {\n background: #10b981 !important;\n color: #ffffff !important;\n }\n\n [data-theme="forest"] .success-btn {\n background: #10b981 !important;\n color: #ffffff !important;\n }\n\n [data-theme="halloween"] .success-btn {\n background: #ff7b00 !important;\n color: #000000 !important;\n }\n\n [data-theme="synthwave"] .success-btn {\n background: #00ff41 !important;\n color: #000000 !important;\n }\n\n [data-theme="dracula"] .success-btn {\n background: #50fa7b !important;\n color: #000000 !important;\n }\n\n [data-theme="luxury"] .success-btn {\n background: #d4af37 !important;\n color: #000000 !important;\n }\n\n [data-theme="night"] .success-btn {\n background: #22d3ee !important;\n color: #ffffff !important;\n }\n\n [data-theme="light"] .success-btn {\n background: #10b981 !important;\n color: #ffffff !important;\n }\n\n [data-theme="cupcake"] .success-btn {\n background: #f472b6 !important;\n color: #ffffff !important;\n }\n\n [data-theme="retro"] .success-btn {\n background: #d4a574 !important;\n color: #ffffff !important;\n }\n\n [data-theme="aqua"] .success-btn {\n background: #06b6d4 !important;\n color: #ffffff !important;\n }\n\n [data-theme="lofi"] .success-btn {\n background: #10b981 !important;\n color: #ffffff !important;\n }\n\n [data-theme="pastel"] .success-btn {\n background: #34d399 !important;\n color: #ffffff !important;\n }\n\n [data-theme="fantasy"] .success-btn {\n background: #f472b6 !important;\n color: #ffffff !important;\n }\n\n [data-theme="wireframe"] .success-btn {\n background: #dfdfdf !important;\n color: #000000 !important;\n border: 1px solid #000000 !important;\n }\n\n [data-theme="black"] .success-btn {\n background: #10b981 !important;\n color: #ffffff !important;\n }\n\n [data-theme="cmyk"] .success-btn {\n background: #06b6d4 !important;\n color: #ffffff !important;\n }\n\n [data-theme="autumn"] .success-btn {\n background: #d97706 !important;\n color: #ffffff !important;\n }\n\n [data-theme="business"] .success-btn {\n background: #10b981 !important;\n color: #ffffff !important;\n }\n\n [data-theme="acid"] .success-btn {\n background: #84cc16 !important;\n color: #000000 !important;\n }\n\n [data-theme="lemonade"] .success-btn {\n background: #22c55e !important;\n color: #ffffff !important;\n }\n\n [data-theme="coffee"] .success-btn {\n background: #a0522d !important;\n color: #ffffff !important;\n }\n\n [data-theme="winter"] .success-btn {\n background: #3b82f6 !important;\n color: #ffffff !important;\n }\n .download-limiter-signout-btn {\n background: #dc3545;\n color: white;\n border: none;\n padding: 6px 12px;\n border-radius: 4px;\n font-size: 12px;\n cursor: pointer;\n margin-left: 8px;\n }\n .download-limiter-premium-badge {\n background: linear-gradient(45deg, #f39c12, #e74c3c);\n color: white;\n padding: 2px 6px;\n border-radius: 3px;\n font-size: 10px;\n margin-left: 8px;\n font-weight: bold;\n }\n .download-limiter-btn-premium {\n opacity: 0.7;\n }\n .download-limiter-success-modal {\n display: none;\n position: fixed;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n background: rgba(0,0,0,0.5);\n z-index: 10000;\n align-items: center;\n justify-content: center;\n }\n .download-limiter-success-modal.show { display: flex; }\n .download-limiter-success-content {\n background: white;\n padding: 2rem;\n border-radius: 8px;\n max-width: 400px;\n text-align: center;\n box-shadow: 0 4px 20px rgba(0,0,0,0.15);\n border-left: 4px solid #38a169;\n }\n\n /* Single upgrade flow styles */\n .single-upgrade-container {\n margin: 20px 0;\n text-align: center;\n }\n\n .single-upgrade-content .upgrade-btn {\n background: linear-gradient(135deg, #059669, #0d9488) !important;\n color: white !important;\n border: none !important;\n padding: 16px 32px !important;\n border-radius: 12px !important;\n font-size: 18px !important;\n font-weight: 600 !important;\n cursor: pointer !important;\n transition: all 0.3s ease !important;\n box-shadow: 0 4px 12px rgba(5, 150, 105, 0.3) !important;\n margin-bottom: 16px !important;\n min-width: 200px !important;\n }\n\n .single-upgrade-content .upgrade-btn:hover {\n background: linear-gradient(135deg, #047857, #0f766e) !important;\n transform: translateY(-2px) !important;\n box-shadow: 0 6px 20px rgba(5, 150, 105, 0.4) !important;\n }\n\n .single-upgrade-content .upgrade-description {\n font-size: 14px !important;\n color: #6b7280 !important;\n margin: 12px 0 0 0 !important;\n line-height: 1.5 !important;\n max-width: 300px !important;\n margin-left: auto !important;\n margin-right: auto !important;\n }\n\n /* Anonymous user usage count styles */\n .lead-fast-anonymous-status {\n display: flex;\n align-items: center;\n gap: 12px;\n }\n\n .lead-fast-anonymous-status .lead-fast-count {\n background: rgba(59, 130, 246, 0.1);\n color: #1d4ed8;\n padding: 6px 12px;\n border-radius: 8px;\n font-size: 14px;\n font-weight: 500;\n border: 1px solid rgba(59, 130, 246, 0.2);\n }\n\n /* Loading state styles */\n .lead-fast-loading-status {\n display: flex;\n align-items: center;\n gap: 10px;\n }\n\n .lead-fast-spinner {\n width: 20px;\n height: 20px;\n color: #3b82f6;\n }\n\n .lead-fast-loading-text {\n font-size: 14px;\n color: #6b7280;\n font-weight: 500;\n }\n\n /* Success button theming */\n .download-limiter-btn.success-btn {\n background: #059669 !important;\n color: white !important;\n border: none !important;\n padding: 12px 24px !important;\n border-radius: 8px !important;\n cursor: pointer !important;\n margin-top: 20px !important;\n font-size: 16px !important;\n font-weight: 500 !important;\n transition: all 0.2s ease !important;\n }\n\n .download-limiter-btn.success-btn:hover {\n background: #047857 !important;\n transform: translateY(-1px) !important;\n }\n\n /* Theme-specific success button colors */\n [data-theme="cyberpunk"] .download-limiter-btn.success-btn {\n background: #0ea5e9 !important;\n box-shadow: 0 4px 12px rgba(14, 165, 233, 0.3) !important;\n }\n\n [data-theme="cyberpunk"] .download-limiter-btn.success-btn:hover {\n background: #0284c7 !important;\n }\n\n [data-theme="valentine"] .download-limiter-btn.success-btn {\n background: #be185d !important;\n }\n\n [data-theme="valentine"] .download-limiter-btn.success-btn:hover {\n background: #9d174d !important;\n }\n\n [data-theme="bumblebee"] .download-limiter-btn.success-btn {\n background: #f59e0b !important;\n }\n\n [data-theme="bumblebee"] .download-limiter-btn.success-btn:hover {\n background: #d97706 !important;\n }\n\n [data-theme="garden"] .download-limiter-btn.success-btn {\n background: #16a34a !important;\n }\n\n [data-theme="garden"] .download-limiter-btn.success-btn:hover {\n background: #15803d !important;\n }\n\n /* Google Sign-in button theming */\n .download-limiter-btn.google-signin-btn {\n background: #4285f4 !important;\n color: white !important;\n border: none !important;\n padding: 12px 24px !important;\n border-radius: 8px !important;\n cursor: pointer !important;\n margin-right: 10px !important;\n display: inline-flex !important;\n align-items: center !important;\n gap: 8px !important;\n font-size: 14px !important;\n font-weight: 500 !important;\n transition: all 0.2s ease !important;\n }\n\n .download-limiter-btn.google-signin-btn:hover {\n background: #3367d6 !important;\n transform: translateY(-1px) !important;\n }\n\n /* Upgrade button theming */\n .download-limiter-btn.upgrade-btn {\n background: #059669 !important;\n color: white !important;\n border: none !important;\n padding: 12px 24px !important;\n border-radius: 8px !important;\n cursor: pointer !important;\n margin-right: 10px !important;\n font-size: 16px !important;\n font-weight: 500 !important;\n transition: all 0.2s ease !important;\n }\n\n .download-limiter-btn.upgrade-btn:hover {\n background: #047857 !important;\n transform: translateY(-1px) !important;\n }\n\n /* Theme-specific button colors */\n [data-theme="cyberpunk"] .download-limiter-btn.upgrade-btn {\n background: #0ea5e9 !important;\n box-shadow: 0 4px 12px rgba(14, 165, 233, 0.3) !important;\n }\n\n [data-theme="valentine"] .download-limiter-btn.upgrade-btn {\n background: #be185d !important;\n }\n\n [data-theme="bumblebee"] .download-limiter-btn.upgrade-btn {\n background: #f59e0b !important;\n }\n\n [data-theme="garden"] .download-limiter-btn.upgrade-btn {\n background: #16a34a !important;\n }\n\n /* Cancel button container and styling - positioned at very bottom */\n .download-limiter-cancel-container {\n margin-top: 30px !important;\n padding-top: 20px !important;\n border-top: 1px solid rgba(0, 0, 0, 0.1) !important;\n text-align: center !important;\n position: relative !important;\n bottom: 0 !important;\n }\n\n .download-limiter-btn.cancel-btn {\n background: transparent !important;\n color: #6b7280 !important;\n border: none !important;\n padding: 8px 16px !important;\n border-radius: 6px !important;\n cursor: pointer !important;\n font-size: 13px !important;\n font-weight: 400 !important;\n transition: all 0.2s ease !important;\n text-decoration: underline !important;\n margin: 0 auto !important;\n display: block !important;\n }\n\n .download-limiter-btn.cancel-btn:hover {\n color: #374151 !important;\n background: rgba(107, 114, 128, 0.1) !important;\n text-decoration: none !important;\n }\n\n /* Theme-specific cancel button border */\n [data-theme="dark"] .download-limiter-cancel-container {\n border-top-color: rgba(255, 255, 255, 0.1) !important;\n }\n\n [data-theme="dark"] .download-limiter-btn.cancel-btn {\n color: #9ca3af !important;\n }\n\n [data-theme="dark"] .download-limiter-btn.cancel-btn:hover {\n color: #d1d5db !important;\n background: rgba(156, 163, 175, 0.1) !important;\n }\n\n [data-theme="cyberpunk"] .download-limiter-cancel-container {\n border-top-color: rgba(14, 165, 233, 0.2) !important;\n }\n\n [data-theme="cyberpunk"] .download-limiter-btn.cancel-btn {\n color: #0ea5e9 !important;\n }\n\n [data-theme="cyberpunk"] .download-limiter-btn.cancel-btn:hover {\n color: #38bdf8 !important;\n background: rgba(14, 165, 233, 0.1) !important;\n }\n `,document.head.appendChild(n)}injectDaisyUI(){if(document.querySelector('link[href*="daisyui"]')){if(this.config.theme?.name){const n=this.config.theme.name.toLowerCase();document.documentElement.setAttribute("data-theme",n)}}else if(this.config.theme?.name){const n=this.config.theme.name.toLowerCase();document.documentElement.setAttribute("data-theme",n),this.updateStatusDisplays()}}createPaywallModal(){if(document.getElementById("download-limiter-paywall"))return;const n=document.createElement("div");n.id="download-limiter-paywall",n.className="download-limiter-modal",n.innerHTML='\n <div class="download-limiter-content">\n <h3 id="download-limiter-paywall-title">Usage Limit Reached</h3>\n <p id="download-limiter-paywall-subtitle">You\'ve used all your free attempts. Upgrade to premium for unlimited usage!</p>\n\n \x3c!-- Auth Section (shows when not signed in) --\x3e\n <div id="download-limiter-auth-section" style="margin: 20px 0;">\n <p>Sign in to continue or upgrade to premium</p>\n <button id="download-limiter-signin-btn" class="download-limiter-btn google-signin-btn">\n <svg width="18" height="18" viewBox="0 0 18 18" fill="none">\n <path d="M16.51 8H8.98v3h4.3c-.18 1-.74 1.48-1.6 2.04v2.01h2.6a8.8 8.8 0 0 0 2.38-5.88c0-.57-.05-.66-.15-1.18z" fill="white"/>\n <path d="M8.98 17c2.16 0 3.97-.72 5.3-1.94l-2.6-2.04a4.8 4.8 0 0 1-2.7.75 4.8 4.8 0 0 1-4.52-3.4H1.83v2.07A8 8 0 0 0 8.98 17z" fill="white"/>\n <path d="M4.46 10.37a4.8 4.8 0 0 1-.25-1.37c0-.48.09-.94.25-1.37V5.56H1.83a8 8 0 0 0 0 6.88l2.63-2.07z" fill="white"/>\n <path d="M8.98 3.77c1.32 0 2.5.45 3.44 1.35l2.58-2.58C13.94.64 11.66 0 8.98 0A8 8 0 0 0 1.83 5.56l2.63 2.07c.61-1.8 2.26-3.86 4.52-3.86z" fill="white"/>\n </svg>\n Sign in with Google\n </button>\n </div>\n\n \x3c!-- Payment Section (shows when signed in) --\x3e\n <div id="download-limiter-payment-section" style="margin: 20px 0; display: none;">\n <button id="download-limiter-upgrade-btn" class="download-limiter-btn upgrade-btn">\n Upgrade to Premium\n </button>\n </div>\n\n <div class="download-limiter-cancel-container">\n <button id="download-limiter-close-btn" class="download-limiter-btn cancel-btn">\n Cancel\n </button>\n </div>\n </div>\n ',document.body.appendChild(n),n.querySelector("#download-limiter-signin-btn").addEventListener("click",async()=>{await this.signIn()}),n.querySelector("#download-limiter-upgrade-btn").addEventListener("click",async()=>{const n=await this.createPayment();n?.checkout_url&&(window.location.href=n.checkout_url)}),n.querySelector("#download-limiter-close-btn").addEventListener("click",()=>{this.config.options,this.config.feedback||this.config.email?(this.config.options,this.showFeedbackForm()):(this.config.options,n.classList.remove("show"))})}createSuccessModal(){if(document.getElementById("download-limiter-success"))return;const n=document.createElement("div");n.id="download-limiter-success",n.className="download-limiter-modal",n.innerHTML='\n <div class="download-limiter-content"> \x3c!-- Use same content class as paywall for theming --\x3e\n <h3 id="download-limiter-success-title">Action Started!</h3>\n <p id="download-limiter-success-message">Your action completed successfully!</p>\n <button id="download-limiter-success-close" class="download-limiter-btn success-btn">\n OK\n </button>\n </div>\n ',document.body.appendChild(n),n.querySelector("#download-limiter-success-close").addEventListener("click",()=>{n.classList.remove("show")}),n.addEventListener("click",t=>{t.target===n&&n.classList.remove("show")})}showFeedbackForm(){const n=document.getElementById("download-limiter-paywall");n&&n.classList.remove("show"),this.createFeedbackModal();const t=document.getElementById("download-limiter-feedback");t&&t.classList.add("show")}createFeedbackModal(){if(document.getElementById("download-limiter-feedback"))return void this.config.options;const n=this.config.feedback||(this.config.email?{form:{title:"Quick Feedback",description:"Why didn't you upgrade?",option1:"Not useful for my needs",option2:"Didn't find what I was looking for",option3:"Just trying it out"},email:this.config.email}:null);if(this.config.options,!n)return void this.config.options;const t=document.createElement("div");t.id="download-limiter-feedback",t.className="download-limiter-modal",t.innerHTML=`\n <div class="download-limiter-content">\n <h3>${n.form.title}</h3>\n <p style="margin-bottom: 20px;">${n.form.description}</p>\n\n <form id="feedback-form" style="text-align: left;">\n <div style="margin-bottom: 15px;">\n <label style="display: block; margin-bottom: 8px;">\n <input type="radio" name="reason" value="option1" style="margin-right: 8px;">\n ${n.form.option1}\n </label>\n <label style="display: block; margin-bottom: 8px;">\n <input type="radio" name="reason" value="option2" style="margin-right: 8px;">\n ${n.form.option2}\n </label>\n <label style="display: block; margin-bottom: 8px;">\n <input type="radio" name="reason" value="option3" style="margin-right: 8px;">\n ${n.form.option3}\n </label>\n </div>\n\n <div style="margin-bottom: 15px;">\n <label for="feedback-details" style="display: block; margin-bottom: 5px;">Tell us more:</label>\n <textarea\n id="feedback-details"\n name="details"\n rows="3"\n style="width: 100%; padding: 8px; border: 1px solid #ddd; border-radius: 4px;"\n placeholder="Your feedback helps us improve..." maxlength="200"></textarea>\n </div>\n\n <div style="margin-bottom: 20px;">\n <label for="feedback-email" style="display: block; margin-bottom: 5px;">\n Email (optional):\n </label>\n <input\n type="email"\n id="feedback-email"\n name="email"\n style="width: 100%; padding: 8px; border: 1px solid #ddd; border-radius: 4px;"\n placeholder="your@email.com">\n <small style="color: #666; display: block; margin-top: 4px;">\n Only if you want us to reach out about what you mentioned above. We don't follow up unless you want us to\n </small>\n </div>\n\n \n <div style="text-align: center;">\n <button type="submit" class="download-limiter-btn success-btn" style="margin-right: 10px;">\n Submit Feedback\n </button>\n <button type="button" id="feedback-skip-btn" class="download-limiter-btn cancel-btn">\n Skip\n </button>\n </div>\n </form>\n </div>\n `,document.body.appendChild(t),this.config.options;const e=t.querySelector("#feedback-form");e.addEventListener("submit",n=>{n.preventDefault(),this.submitFeedback(e)}),t.querySelector("#feedback-skip-btn").addEventListener("click",()=>{t.classList.remove("show")}),t.addEventListener("click",n=>{n.target===t&&t.classList.remove("show")})}async submitFeedback(n){const t=new FormData(n),e=t.get("reason"),a=t.get("details"),o=t.get("email");if(!e)return void alert("Please select a reason");const i={reason:e,details:a,email:o||void 0,timestamp:(new Date).toISOString(),userAgent:navigator.userAgent,appId:this.validatedAppName||"unknown"};try{await this.sendFeedbackEmail(i);const n=document.getElementById("download-limiter-feedback");n&&n.classList.remove("show"),alert("Thank you for your feedback!")}catch(n){console.error("Failed to send feedback:",n),alert("Failed to send feedback. Please try again.")}}async sendFeedbackEmail(n){let t;if(this.config.feedback?.email?t=Array.isArray(this.config.feedback.email)?this.config.feedback.email[0]:this.config.feedback.email:this.config.email&&(t={provider:"resend",apiKey:this.config.email.resendApiKey,fromEmail:this.config.email.fromEmail}),!t)throw new Error("Email configuration not available");const e=`\nNew Feedback from ${this.validatedAppName||"unknown"}\n\nReason: ${n.reason}\nDetails: ${n.details}\nUser Email: ${n.email||"Not provided"}\nTimestamp: ${n.timestamp}\nUser Agent: ${n.userAgent}\n `.trim();let a;if("resend"!==t.provider&&t.provider)throw new Error(`Unsupported email provider: ${t.provider}`);if(a=await fetch("https://api.resend.com/emails",{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${t.apiKey||t.resendApiKey}`},body:JSON.stringify({from:t.fromEmail,to:[t.fromEmail],subject:`Feedback from ${this.validatedAppName||"unknown"}`,text:e})}),!a.ok)throw new Error(`Email API error: ${a.status}`)}createAuthUI(){if(document.getElementById("lead-fast-profile"))return;const n=document.createElement("div");n.id="lead-fast-profile",n.className="lead-fast-profile",document.body.appendChild(n)}createStatusDisplay(){if(document.getElementById("download-limiter-status"))return;const n=document.createElement("div");n.id="download-limiter-status",n.className="download-limiter-status",document.body.appendChild(n)}createGlobalStatusDisplay(){this.createStatusDisplay()}showPaywallInstant(n){this.createPaywallModal();const t=document.getElementById("download-limiter-paywall");if(t){const e=t.querySelector("#download-limiter-paywall-title");e&&(e.textContent=`You've used ${n.limit} free attempts`);const a=t.querySelector("#download-limiter-auth-section"),o=t.querySelector("#download-limiter-payment-section");if(this.currentUser)a.style.display="none",o.style.display="block";else{const n=t.querySelector("#download-limiter-paywall-subtitle");n&&(n.textContent="Sign in to continue. If you're already premium, you'll get unlimited access. New users can upgrade after signing in."),a.style.display="none",o.style.display="none",this.showSingleUpgradeFlow(t)}t.classList.add("show")}}async showPaywall(){const n=await this.getDownloadStatus();this.showPaywallInstant(n)}showSingleUpgradeFlow(n){let t=n.querySelector(".single-upgrade-container");if(!t){t=document.createElement("div"),t.className="single-upgrade-container",t.innerHTML='\n <div class="single-upgrade-content">\n <button class="download-limiter-btn upgrade-btn" id="single-upgrade-btn">\n Continue with Google\n </button>\n \x3c!--<p class="upgrade-description">\n Sign in to restore access. Premium members get unlimited usage immediately.\n </p>--\x3e\n </div>\n ';const e=n.querySelector(".download-limiter-cancel-container");e?n.querySelector(".download-limiter-content")?.insertBefore(t,e):n.querySelector(".download-limiter-content")?.appendChild(t)}t.style.display="block";const e=n.querySelector("#single-upgrade-btn");if(e){e.replaceWith(e.cloneNode(!0));const t=n.querySelector("#single-upgrade-btn");t?.addEventListener("click",async()=>{try{const n=`${window.location.origin}${window.location.pathname}?upgrade=true`,t={currentUrl:window.location.href,origin:window.location.origin,pathname:window.location.pathname,redirectTo:n,provider:"google",flow:"upgrade",timestamp:(new Date).toISOString()};console.log("🟢 [MoneyBar OAuth Debug] BEFORE AUTH (Upgrade) - Initiating OAuth with:",t),sessionStorage.setItem("moneybar_oauth_debug_before",JSON.stringify(t));const{error:e}=await this.supabase.auth.signInWithOAuth({provider:"google",options:{redirectTo:n}});e&&(console.error("Sign in error:",e),this.showError("Sign In Failed","Failed to sign in with Google. Please try again."))}catch(n){console.error("Upgrade flow error:",n),this.showError("Upgrade Failed","Failed to start upgrade process. Please try again.")}})}}showSuccess(n,t){const e=document.getElementById("download-limiter-success");if(e){const a=e.querySelector("#download-limiter-success-title"),o=e.querySelector("#download-limiter-success-message");a&&(a.textContent=n),o&&(o.textContent=t),e.classList.add("show")}}showError(n,t){const e=document.createElement("div");e.style.cssText="\n position: fixed;\n top: 20px;\n right: 20px;\n background: #fee2e2;\n border: 1px solid #fecaca;\n color: #dc2626;\n padding: 12px 16px;\n border-radius: 8px;\n font-size: 14px;\n font-weight: 500;\n line-height: 1.4;\n max-width: 300px;\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);\n z-index: 10000;\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\n ",e.innerHTML=`\n <div style="font-weight: 600; margin-bottom: 4px;">${n}</div>\n <div style="font-size: 13px; opacity: 0.9;">${t}</div>\n `,document.body.appendChild(e),setTimeout(()=>{e.parentNode&&e.parentNode.removeChild(e)},5e3),e.addEventListener("click",()=>{e.parentNode&&e.parentNode.removeChild(e)})}showInfo(n,t){const e=document.createElement("div");e.style.cssText="\n position: fixed;\n top: 20px;\n right: 20px;\n background: #dbeafe;\n border: 1px solid #bfdbfe;\n color: #1e40af;\n padding: 12px 16px;\n border-radius: 8px;\n font-size: 14px;\n font-weight: 500;\n line-height: 1.4;\n max-width: 350px;\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);\n z-index: 10000;\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\n ",e.innerHTML=`\n <div style="font-weight: 600; margin-bottom: 4px;">⏳ ${n}</div>\n <div style="font-size: 13px; opacity: 0.9;">${t}</div>\n `,document.body.appendChild(e),setTimeout(()=>{e.parentNode&&e.parentNode.removeChild(e)},8e3),e.addEventListener("click",()=>{e.parentNode&&e.parentNode.removeChild(e)})}showConnectionError(){this.showError("Connection Error","Server connection required for download verification. Please check your configuration and try again.")}showPaymentConfigError(){this.showError("Payment Configuration Error","Payment system is not properly configured. Please contact support.")}disableDownloadButtons(n){const t=document.querySelectorAll("[data-leadfast-attached]"),e={connection:"Download disabled: Server connection required",payment:"Download disabled: Payment configuration error",security_key:"Download disabled: Invalid or missing security key"},a={connection:"⚠️ Connection Error - Downloads Disabled",payment:"⚠️ Payment Config Error - Downloads Disabled",security_key:"🔐 Invalid Security Key - Please Update Configuration"};t.forEach(t=>{const a=t;a.disabled=!0,a.style.opacity="0.5",a.style.cursor="not-allowed",a.title=e[n]});const o=document.querySelector(".lead-fast-user-section");o&&(o.innerHTML=`\n <div style="\n color: #ef4444;\n padding: 6px 8px;\n font-size: 12px;\n font-weight: 500;\n line-height: 1.2;\n border-radius: 4px;\n background: rgba(239, 68, 68, 0.05);\n border: 1px solid rgba(239, 68, 68, 0.2);\n max-width: 200px;\n text-align: center;\n ">\n ${a[n]}\n </div>\n `)}async updateStatusDisplays(){if(this.securityKeyFailed)return void this.disableDownloadButtons("security_key");if(this.supabaseConnectionFailed)return void this.disableDownloadButtons("connection");if(this.config.payment&&this.paymentConnectionFailed)return void this.disableDownloadButtons("payment");this.hasCachedPremiumStatus()||(this.isLoadingStatus=!0,this.updateUserSection(null));const n=await this.getDownloadStatus();this.isLoadingStatus=!1,this.securityKeyFailed?this.disableDownloadButtons("security_key"):this.supabaseConnectionFailed?this.disableDownloadButtons("connection"):this.updateUserSection(n)}createTitleBar(){let n=document.getElementById("lead-fast-profile");n||(n=document.createElement("div"),n.id="lead-fast-profile",n.className="lead-fast-profile",document.body.appendChild(n));const t=this.config.titleBar||{},e=t.title||"My App",a=t.titleImage,o=t.links||[];n.innerHTML=`\n <div class="lead-fast-title-bar">\n <div class="lead-fast-title-section">\n <a href="#" class="lead-fast-logo">\n ${a?`<img src="${a}" alt="${e}">`:""}\n <span>${e}</span>\n </a>\n <nav class="lead-fast-nav">\n ${o.map(n=>`\n <a href="${n.url}" class="lead-fast-nav-link" ${n.target?`target="${n.target}"`:""}>\n ${n.text}\n </a>\n `).join("")}\n </nav>\n </div>\n\n <div class="lead-fast-user-section" id="lead-fast-user-section">\n \x3c!-- User section will be populated when logged in --\x3e\n </div>\n\n \x3c!-- <a href="https://www.moneyfast.bar" target="_blank" class="lead-fast-branding" style="text-decoration: none; color: inherit;">moneyfast.bar</a>--\x3e\n </div>\n `}attachSubscriptionTooltip(n,t){let e=null,a=null;const o=()=>{if(a&&(clearTimeout(a),a=null),!e){e=document.createElement("div"),e.className="lead-fast-subscription-tooltip";const n=new Date(t.subscriptionExpiresAt),a=`${["January","February","March","April","May","June","July","August","September","October","November","December"][n.getMonth()]} ${n.getDate()}, ${n.getFullYear()}`,r=t.subscriptionDaysRemaining,s=t.isSubscriptionActive,c=s?"✓":"⚠️",l=s?"Active":"Cancelled",d=s?"Renews:":"Active until:",m=t.customerId?`<div class="tooltip-link">\n <a href="#" class="manage-link" data-customer-id="${t.customerId}">\n Manage Payments →\n <div style="font-size: 11px; color: #666; margin-top: 4px;">\n Manage subscription, orders, invoices, payment method, profile\n </div>\n </a>\n </div>`:"";e.innerHTML=`\n <div class="tooltip-content">\n <div class="tooltip-header">${t.email}</div>\n <div class="tooltip-divider"></div>\n <div class="tooltip-row">\n <span class="tooltip-label">${c} ${l} Subscription</span>\n </div>\n <div class="tooltip-row">\n <span class="tooltip-label">${d}</span>\n <span class="tooltip-value">${a}</span>\n </div>\n <div class="tooltip-row">\n <span class="tooltip-label">Time left:</span>\n <span class="tooltip-value">${r} days</span>\n </div>\n <div class="tooltip-row">\n <span class="tooltip-label">Plan:</span>\n <span class="tooltip-value">${t.subscriptionType||"Monthly"}</span>\n </div>\n ${m}\n </div>\n `,document.body.appendChild(e),e.addEventListener("mouseenter",o),e.addEventListener("mouseleave",i);const p=e.querySelector(".manage-link");p&&p.addEventListener("click",async n=>{n.preventDefault();const t=n.target.getAttribute("data-customer-id");t&&await this.openCustomerPortal(t)})}const r=n.getBoundingClientRect();e.style.top=`${r.bottom+8}px`,e.style.left=r.left-100+"px",e.classList.add("show")},i=()=>{a=setTimeout(()=>{e&&e.classList.remove("show")},200)};n.addEventListener("mouseenter",o),n.addEventListener("mouseleave",i)}async updateUserSection(n){const t=document.getElementById("lead-fast-user-section");if(t)if(null===n||this.isLoadingStatus)t.innerHTML='\n <div class="lead-fast-loading-status">\n <svg class="lead-fast-spinner" viewBox="0 0 24 24">\n <circle cx="12" cy="12" r="10" stroke="currentColor" stroke-width="3" fill="none" stroke-dasharray="31.4 31.4" stroke-linecap="round">\n <animateTransform attributeName="transform" type="rotate" from="0 12 12" to="360 12 12" dur="1s" repeatCount="indefinite"/>\n </circle>\n </svg>\n <span class="lead-fast-loading-text">Loading...</span>\n </div>\n ';else if(this.currentUser){const e=this.currentUser.email.charAt(0).toUpperCase(),a=this.currentUser.email,o=n.isPremium?"premium":"free";let i=n.isPremium?"Premium":"Free";const r=n.isPremium?"Unlimited":`${n.currentCount}/${n.limit}`;let s=!1,c=null;if(n.isPremium){const t=await this.getUserContext(n);if(t.subscriptionType&&"one-time"!==t.subscriptionType&&t.subscriptionExpiresAt){const n=new Date(t.subscriptionExpiresAt);i=`Premium • ${`${["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"][n.getMonth()]} ${n.getDate()}`}`,s=!0,c=t}}let l=i;s&&(l=`${i} <span class="lead-fast-info-icon" title="Click for subscription details">ⓘ</span>`),t.innerHTML=`\n <div class="lead-fast-avatar">${e}</div>\n <div class="lead-fast-user-info">\n <div class="lead-fast-user-email">${a}</div>\n <div class="lead-fast-user-status">\n <span class="lead-fast-badge ${o}">${l}</span>\n <span class="lead-fast-count">${r}</span>\n </div>\n </div>\n <button class="lead-fast-signout">signout</button>\n `;const d=document.querySelector(".lead-fast-title-bar");d&&getComputedStyle(d);const m=t.querySelector(".lead-fast-signout");if(m&&m.addEventListener("click",()=>{this.signOut()}),s&&c){const n=t.querySelector(".lead-fast-info-icon");n&&this.attachSubscriptionTooltip(n,c)}}else{const e=`${this.config.actionLabel}: ${n.currentCount}/${n.limit}`;t.innerHTML=`\n <div class="lead-fast-anonymous-status">\n <span class="lead-fast-count">${e}</span>\n </div>\n `}}setupUIUpdates(){this.on("authChanged",async n=>{const t=n.user?.email||null,e=this.lastAuthEmail!==t;this.lastAuthEmail=t,this.cachedStatus=null,this.cachedPremiumStatus=null,this.cachedDownloadCount=null,e&&this.clearPremiumStatusFromLocalStorage(),this.updateStatusDisplays();const a=document.getElementById("download-limiter-paywall");a&&a.classList.contains("show")&&(this.updatePaywallDisplay(),this.currentUser&&this.config.payment&&(n.isPremium?a.classList.remove("show"):setTimeout(async()=>{const n=await this.createPayment();n?.checkout_url&&(window.location.href=n.checkout_url)},500)))}),this.on("countChanged",()=>{this.updateStatusDisplays()}),this.updateStatusDisplays()}updatePaywallDisplay(){const n=document.getElementById("download-limiter-paywall");if(!n)return;const t=n.querySelector("#download-limiter-auth-section"),e=n.querySelector("#download-limiter-payment-section");this.currentUser?(t.style.display="none",e.style.display="block"):(t.style.display="block",e.style.display="none")}on(n,t){this.eventListeners.has(n)||this.eventListeners.set(n,[]),this.eventListeners.get(n).push(t)}off(n,t){const e=this.eventListeners.get(n);if(e){const n=e.indexOf(t);n>-1&&e.splice(n,1)}}emit(n,t){const e=this.eventListeners.get(n);e&&e.forEach(e=>{try{e(t)}catch(t){console.error(`Error in ${n} listener:`,t)}})}validateConfig(){if(!this.config.security_key)throw new Error("security_key is required");if(!this.config.actionLabel)throw new Error('actionLabel is required (e.g., "PDF Generations", "Image Exports")');if(!this.config.supabase?.url)throw new Error("supabase.url is required");if(!this.config.supabase?.anonKey)throw new Error("supabase.anonKey is required");if("number"!=typeof this.config.freeAttemptLimit||this.config.freeAttemptLimit<0)throw new Error("freeAttemptLimit must be a non-negative number")}async initializeSupabase(){try{this.supabase=n.createClient(this.config.supabase.url,this.config.supabase.anonKey),this.supabaseConnectionFailed=!1}catch(n){console.error("Failed to initialize Supabase:",n),this.supabaseConnectionFailed=!0}}async initializePayment(){if(!this.config.payment)return;const n=this.config.payment?.find(n=>"dodo"===n.provider);if(!n)return this.paymentConnectionFailed=!0,void(this.config.options?.debug&&console.warn("No dodo payment provider configured"));const t=n.productId;if(!t||!t.startsWith("pdt_")||t.length<10)return this.paymentConnectionFailed=!0,void(this.config.options?.debug&&console.warn("Invalid payment product ID format:",t));this.paymentConnectionFailed=!1}async initializeFingerprint(){try{this.userFingerprint=await this.generateFingerprint()}catch(n){this.userFingerprint=crypto.randomUUID?crypto.randomUUID():String(Date.now()),this.config.options?.debug&&console.warn("Fingerprint generation failed, using fallback:",n)}}async generateFingerprint(){const n=`${navigator.userAgent||""}||${Intl.DateTimeFormat().resolvedOptions().timeZone||""}||${`${screen.width}x${screen.height}`}||${navigator.language||""}`,t=(new TextEncoder).encode(n),e=await crypto.subtle.digest("SHA-256",t);return Array.from(new Uint8Array(e)).map(n=>n.toString(16).padStart(2,"0")).join("")}async setupAuthListener(){this.supabase.auth.onAuthStateChange(async(n,t)=>{const e=this.currentUser;this.currentUser=t?.user||null;let a=!1;if(this.currentUser){const t=!e||e.email!==this.currentUser.email,o=!this.cachedPremiumStatus||Date.now()-this.premiumStatusCacheTime>this.STATUS_CACHE_DURATION;if("INITIAL_SESSION"===n){const n=this.loadPremiumStatusFromLocalStorage(this.currentUser.email);n&&(a=n.isPremium,console.log(`🔍 [INITIAL_SESSION] Using localStorage premium status: ${a}`))}else if(t||o){a=(await this.checkPremiumStatus(this.currentUser.email)).isPremium,this.cachedPremiumStatus=a,this.premiumStatusCacheTime=Date.now()}else a=this.cachedPremiumStatus,console.log(`🔍 [CACHE] Using cached premium status from auth listener: ${a}`)}else this.cachedPremiumStatus=null,this.premiumStatusCacheTime=0;const o="true"===new URLSearchParams(window.location.search).get("upgrade");if("SIGNED_IN"===n&&!e&&this.currentUser&&this.config.payment&&o)if(a){window.history.replaceState({},document.title,window.location.pathname);const n=document.getElementById("download-limiter-paywall");n&&n.classList.remove("show")}else{const n=await this.createPayment();n?.checkout_url&&(window.history.replaceState({},document.title,window.location.pathname),window.location.href=n.checkout_url)}this.cachedStatus=null,this.statusCacheTime=0,this.emit("authChanged",{user:this.currentUser,isAuthenticated:!!this.currentUser,isPremium:a,email:this.currentUser?.email});const i=!!e&&(this.cachedPremiumStatus??!1);a!==i&&this.emit("premiumStatusChanged",{isPremium:a,previousStatus:i,email:this.currentUser?.email}),"INITIAL_SESSION"===n||("SIGNED_OUT"===n?this.updateUserSection(null):await this.updateStatusDisplays())});const{data:{user:n}}=await this.supabase.auth.getUser();this.currentUser=n}async getDownloadCount(){if(!this.userFingerprint)return 0;if(null!==this.cachedDownloadCount&&Date.now()-this.downloadCountCacheTime<this.DOWNLOAD_COUNT_CACHE_DURATION)return console.log(`🔍 [CACHE] Using cached download count: ${this.cachedDownloadCount} (age: ${Math.round((Date.now()-this.downloadCountCacheTime)/1e3)}s)`),this.cachedDownloadCount;if(this.downloadCountPromise)return console.log("🔍 [CACHE] Waiting for existing download count fetch"),await this.downloadCountPromise;this.downloadCountPromise=this.fetchDownloadCount();try{const n=await this.downloadCountPromise;return this.cachedDownloadCount=n,this.downloadCountCacheTime=Date.now(),console.log(`🔍 [CACHE] Cached download count: ${n}`),n}finally{this.downloadCountPromise=null}}async fetchDownloadCount(){try{const n=await fetch(`${this.config.supabase.url}/functions/v1/check-download-limit`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${this.config.supabase.anonKey}`},body:JSON.stringify({fingerprint:this.userFingerprint,security_key:this.config.security_key,action:"check"})});if(n.ok){const t=await n.json();return this.supabaseConnectionFailed=!1,t.app_id&&!this.validatedAppName?this.validatedAppName=t.app_id:this.validatedAppName,t.current_count||0}if(401===n.status||403===n.status)try{const t=await n.json(),e=t.error||t.message||"Authentication failed";e.toLowerCase().includes("security key")?(console.error(`❌ Security Key Validation Failed [check-download-limit]: ${e}`),console.error("💡 Backend Function: check-download-limit"),console.error("💡 Please check your security_key in the MoneyBar configuration"),this.securityKeyFailed=!0,this.supabaseConnectionFailed=!0):(console.warn(`Supabase authentication failed [check-download-limit]: ${n.status} - ${e}`),this.supabaseConnectionFailed=!0)}catch(t){console.warn(`Supabase authentication failed: ${n.status} - Unable to parse error`),this.supabaseConnectionFailed=!0}}catch(n){this.supabaseConnectionFailed=!0,this.config.options?.debug&&console.warn("Failed to get server usage count, connection failed:",n)}return 0}async incrementDownloadCount(){if(!this.userFingerprint)return 0;const n={fingerprint:this.userFingerprint,security_key:this.config.security_key,action:"increment"};try{const t=await fetch(`${this.config.supabase.url}/functions/v1/check-download-limit`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${this.config.supabase.anonKey}`},body:JSON.stringify(n)});if(this.config.options?.debug&&!t.ok){const n=await t.text();console.error("🔍 DEBUG: Error response:",n)}if(t.ok){const n=await t.json();return this.supabaseConnectionFailed=!1,n.app_id&&!this.validatedAppName?this.validatedAppName=n.app_id:this.validatedAppName,this.cachedDownloadCount=null,this.downloadCountCacheTime=0,console.log("🔍 [CACHE] Invalidated download count cache after increment"),n.new_count||0}if(401===t.status||403===t.status)try{const n=await t.json(),e=n.error||n.message||"Authentication failed";e.toLowerCase().includes("security key")?(console.error(`❌ Security Key Validation Failed [check-download-limit]: ${e}`),console.error("💡 Backend Function: check-download-limit"),console.error("💡 Please check your security_key in the MoneyBar configuration"),this.securityKeyFailed=!0,this.supabaseConnectionFailed=!0):(console.warn(`Supabase authentication failed [check-download-limit]: ${t.status} - ${e}`),this.supabaseConnectionFailed=!0)}catch(n){console.warn(`Supabase authentication failed: ${t.status} - Unable to parse error`),this.supabaseConnectionFailed=!0}}catch(n){this.supabaseConnectionFailed=!0,this.config.options?.debug&&console.warn("Failed to increment server count, connection failed:",n)}return 0}async checkPremiumStatus(n){if(this.premiumCheckPromise)return console.log("🔍 [CACHE] Waiting for existing premium check"),await this.premiumCheckPromise;const t=this.loadPremiumStatusFromLocalStorage(n);if(t)return console.log(`🔍 [LOCALSTORAGE] Using localStorage premium status: ${t.isPremium} (age: ${Math.round((Date.now()-t.timestamp)/1e3/60)}m)`),this.cachedPremiumStatus=t.isPremium,this.cachedSubscriptionDetails=t.subscriptionDetails,this.premiumStatusCacheTime=t.timestamp,this.lastCheckedEmail=n,{isPremium:t.isPremium,subscriptionDetails:t.subscriptionDetails};if(null!==this.cachedPremiumStatus&&Date.now()-this.premiumStatusCacheTime<this.STATUS_CACHE_DURATION&&this.lastCheckedEmail===n)return console.log(`🔍 [CACHE] Using cached premium status: ${this.cachedPremiumStatus}`),{isPremium:this.cachedPremiumStatus,subscriptionDetails:this.cachedSubscriptionDetails};this.premiumCheckPromise=this.fetchPremiumStatus(n);try{const t=await this.premiumCheckPromise;return this.savePremiumStatusToLocalStorage(n,t.isPremium,t.subscriptionDetails),t}finally{this.premiumCheckPromise=null}}savePremiumStatusToLocalStorage(n,t,e){try{const a={email:n,isPremium:t,subscriptionDetails:e,timestamp:Date.now(),appId:this.validatedAppName||"unknown"},o=`moneybar_premium_${this.validatedAppName||"unknown"}`;localStorage.setItem(o,JSON.stringify(a)),console.log("🔍 [LOCALSTORAGE] Saved premium status to localStorage (24h cache)")}catch(n){console.warn("Failed to save premium status to localStorage:",n)}}loadPremiumStatusFromLocalStorage(n){try{const t=`moneybar_premium_${this.validatedAppName||"unknown"}`,e=localStorage.getItem(t);if(!e)return null;const a=JSON.parse(e),o=Date.now()-a.timestamp,i=864e5;return a.email===n&&o<i?{isPremium:a.isPremium,subscriptionDetails:a.subscriptionDetails,timestamp:a.timestamp}:(localStorage.removeItem(t),null)}catch(n){return null}}clearPremiumStatusFromLocalStorage(){try{const n=`moneybar_premium_${this.validatedAppName||"unknown"}`;localStorage.removeItem(n),console.log("🔍 [LOCALSTORAGE] Cleared premium status from localStorage")}catch(n){}}hasCachedPremiumStatus(){if(!this.currentUser?.email)return!1;const n=this.loadPremiumStatusFromLocalStorage(this.currentUser.email);if(n&&n.isPremium)return console.log("🔍 [CACHE-CHECK] Premium user with valid cache - skip loading"),!0;return!(!(null!==this.cachedPremiumStatus&&Date.now()-this.premiumStatusCacheTime<this.STATUS_CACHE_DURATION&&this.lastCheckedEmail===this.currentUser.email)||!0!==this.cachedPremiumStatus)&&(console.log("🔍 [CACHE-CHECK] Premium user with valid memory cache - skip loading"),!0)}async fetchPremiumStatus(n){if(!this.validatedAppName&&this.userFingerprint)try{const n=await fetch(`${this.config.supabase.url}/functions/v1/check-download-limit`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${this.config.supabase.anonKey}`},body:JSON.stringify({fingerprint:this.userFingerprint,security_key:this.config.security_key,action:"check"})});if(n.ok){const t=await n.json();t.app_id&&(this.validatedAppName=t.app_id)}}catch(n){}try{const t=this.config.payment?.[0]?.mode||"live",e={email:n,app_id:this.validatedAppName||"unknown",mode:t},a=await fetch(`${this.config.supabase.url}/functions/v1/check-payment-status`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${this.config.supabase.anonKey}`},body:JSON.stringify(e)});if(a.ok){const t=await a.json();t.message&&"processing"===t.payment_status&&this.showInfo("Payment Verification",t.message);const e={isPremium:!0===t.is_premium,subscriptionDetails:t.subscription_details||null};return this.cachedPremiumStatus=e.isPremium,this.cachedSubscriptionDetails=e.subscriptionDetails,this.premiumStatusCacheTime=Date.now(),this.lastCheckedEmail=n,e}}catch(n){this.config.options?.debug&&console.warn("Failed to check premium status:",n)}return{isPremium:!1,subscriptionDetails:null}}getLocalDownloadCount(){const n=`download_count_${this.validatedAppName||"unknown"}`,t=parseInt(localStorage.getItem(n)||"0",10);return isNaN(t)?0:t}incrementLocalDownloadCount(){const n=`download_count_${this.validatedAppName||"unknown"}`,t=this.getLocalDownloadCount()+1;return localStorage.setItem(n,String(t)),t}handleError(n){this.config.options?.debug&&console.error("Lead Fast Error:",n),this.config.callbacks?.onError?this.config.callbacks.onError(n):console.error("Lead Fast:",n.message),this.emit("error",n)}async checkPaymentStatus(){"success"===new URLSearchParams(window.location.search).get("payment")&&setTimeout(async()=>{if(this.currentUser){const{isPremium:n,subscriptionDetails:t}=await this.checkPremiumStatus(this.currentUser.email);n?(this.showSuccess("Payment Successful!","Welcome to premium! You now have unlimited usage."),this.emit("paymentSucceeded",{email:this.currentUser.email,subscriptionType:t?.subscription_type}),t?.subscription_id&&this.emit("subscriptionCreated",{email:this.currentUser.email,subscriptionId:t.subscription_id,subscriptionType:t.subscription_type,expiresAt:t.subscription_expires_at})):(this.showSuccess("Processing Payment","Payment is being processed. Please refresh in a few moments."),this.emit("paymentPending",{email:this.currentUser.email}))}else this.showSuccess("Processing Payment","Please wait while we verify your payment...");const n=window.location.href.split("?")[0];window.history.replaceState({},document.title,n)},2e3)}};
|
|
2
2
|
//# sourceMappingURL=index.js.map
|