@encorekit/web-sdk 2.0.6 → 2.0.7
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/cjs/index.cjs +1 -1
- package/dist/esm/index.js +1 -1
- package/dist/umd/encore.min.js +1 -1
- package/package.json +1 -1
- package/types/core/version.d.ts +1 -1
package/dist/cjs/index.cjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";var e;Object.defineProperty(exports,"__esModule",{value:!0}),function(e){e.NETWORK_ERROR="NETWORK_ERROR",e.API_ERROR="API_ERROR",e.CONFIGURATION_ERROR="CONFIGURATION_ERROR",e.INITIALIZATION_ERROR="INITIALIZATION_ERROR",e.STORAGE_ERROR="STORAGE_ERROR",e.INVALID_REQUEST="INVALID_REQUEST",e.UNAUTHORIZED="UNAUTHORIZED",e.NOT_FOUND="NOT_FOUND",e.TIMEOUT="TIMEOUT",e.UNKNOWN_ERROR="UNKNOWN_ERROR"}(e||(e={}));const t={reduceChurn:"churn-intervention",rewardUsers:"post-action-reward"},n=Object.fromEntries(Object.entries(t).map(([e,t])=>[t,e])),r=Object.keys(t);function i(e){return t[e]}function o(e){if(e)return n[e]}function s(e){return"string"==typeof e?`'${e.slice(0,64)}'`:typeof e}function a(e){return r.includes(e)}const l=["none","error","warn","info","debug"],c="[Encore SDK]",d=e=>l.indexOf(e),h=new class{#e="none";setLogLevel(e){this.#e=e}getLogLevel(){return this.#e}#t(e){return d(this.#e)>=d(e)}debug(...e){this.#t("debug")&&console.debug(c,...e)}info(...e){this.#t("info")&&console.info(c,...e)}warn(...e){this.#t("warn")&&console.warn(c,...e)}error(...e){this.#t("error")&&console.error(c,...e)}critical(...e){console.error(c,"[CRITICAL]",...e)}};class u{#n=null;#r=!1;configure(e){if(this.#r)return h.warn("SDK already configured. Ignoring subsequent configure() call."),!1;const t=this.#i(e);if(t)return h.error("Invalid configuration:",t),!1;const n=e.logLevel??"none",r=e.environment??"production";return this.#n={apiKey:e.apiKey,environment:r,baseURL:this.#o(r),analyticsBaseURL:this.#s(r),logLevel:n,unlockMode:e.unlockMode??"optimistic"},h.setLogLevel(n),this.#r=!0,h.debug("SDK configured successfully",this.#n),!0}#i(e){return e.apiKey&&"string"==typeof e.apiKey&&""!==e.apiKey.trim()?e.environment&&!["production","development","staging","localhost"].includes(e.environment)?"environment must be 'production', 'development', 'staging', or 'localhost'":e.logLevel&&!l.includes(e.logLevel)?`logLevel must be one of: ${l.join(", ")}`:e.unlockMode&&!["strict","optimistic"].includes(e.unlockMode)?"unlockMode must be 'strict' or 'optimistic'":null:"apiKey is required and must be a non-empty string"}#o(e){switch(e){case"localhost":return"http://localhost:4000/publisher/sdk/v1";case"development":return"https://api.dev.encorekit.com/encore/publisher/sdk/v1";case"staging":return"https://api.staging.encorekit.com/encore/publisher/sdk/v1";default:return"https://api.encorekit.com/encore/publisher/sdk/v1"}}#s(e){switch(e){case"localhost":return"http://localhost:8081/v1";case"development":return"https://api.dev.encorekit.com/analytics/v1";case"staging":return"https://api.staging.encorekit.com/analytics/v1";default:return"https://api.encorekit.com/analytics/v1"}}getConfig(){return this.#n}isConfigured(){return this.#r}getApiKey(){return this.#n?.apiKey??null}getBaseURL(){return this.#n?.baseURL??null}getAnalyticsBaseURL(){return this.#n?.analyticsBaseURL??null}getEnvironment(){return this.#n?.environment??null}getUnlockMode(){return this.#n?.unlockMode??"optimistic"}reset(){this.#n=null,this.#r=!1,h.debug("Configuration reset")}}const p="encore_";class m{#a;#l;constructor(){this.#l=new Map,this.#a=this.#c(),h.debug(`StorageManager initialized with ${this.#a}`)}#c(){return this.#d("localStorage")?"localStorage":this.#d("sessionStorage")?"sessionStorage":(h.warn("Neither localStorage nor sessionStorage available, using in-memory storage"),"memory")}#d(e){try{const t="localStorage"===e?localStorage:sessionStorage,n="__encore_test__";return t.setItem(n,"test"),t.removeItem(n),!0}catch{return!1}}#h(){return"localStorage"===this.#a?localStorage:"sessionStorage"===this.#a?sessionStorage:this.#l}#u(e){return`${p}${e}`}set(e,t){if(void 0===t)return void h.warn(`Attempted to store undefined value for key: ${e}`);const n=this.#u(e),r=JSON.stringify(t);try{const t=this.#h();t instanceof Map?t.set(n,r):t.setItem(n,r),h.debug(`Stored ${e} in ${this.#a}`)}catch(e){e instanceof Error&&"QuotaExceededError"===e.name?h.error("Storage quota exceeded:",e):h.error("Failed to store item:",e),"memory"!==this.#a&&(h.warn("Falling back to memory storage for this item"),this.#l.set(n,r))}}get(e){const t=this.#u(e);try{const n=this.#h();let r=null;return r=n instanceof Map?n.get(t)??null:n.getItem(t),null===r||"undefined"===r?("undefined"===r&&(h.warn(`Found corrupted value "undefined" for key: ${e}, cleaning up`),this.remove(e)),null):JSON.parse(r)}catch(t){return h.error(`Failed to retrieve ${e}:`,t),this.remove(e),null}}remove(e){const t=this.#u(e);try{const n=this.#h();n instanceof Map?n.delete(t):n.removeItem(t),h.debug(`Removed ${e} from ${this.#a}`)}catch(t){h.error(`Failed to remove ${e}:`,t)}}clear(){try{const e=this.#h();if(e instanceof Map)for(const t of e.keys())t.startsWith(p)&&e.delete(t);else{const t=[];for(let n=0;n<e.length;n++){const r=e.key(n);r?.startsWith(p)&&t.push(r)}t.forEach(t=>e.removeItem(t))}h.debug(`Cleared all Encore data from ${this.#a}`)}catch(e){h.error("Failed to clear storage:",e)}}getStorageType(){return this.#a}}const f="signal_queue";class g{#p;#m;#f;#g=[];#b=!1;#v;constructor(e,t,n){this.#p=e,this.#m=t,this.#f=n,this.#w(),this.#y(),this.processQueue()}setUserId(e){this.#f!==e&&(h.debug("SignalManager: User ID changed, clearing queue"),this.#f=e,this.#g=[],this.#w())}#w(){try{const e=`${this.#f}_${f}`,t=this.#p.get(e);t&&Array.isArray(t)&&(this.#g=t,h.debug("Loaded grant signal queue from storage",{count:t.length}))}catch(e){h.error("Failed to load grant signal queue from storage:",e)}}#x(){try{const e=`${this.#f}_${f}`;this.#p.set(e,this.#g),h.debug("Saved grant signal queue to storage",{count:this.#g.length})}catch(e){h.error("Failed to save grant signal queue to storage:",e)}}enqueue(e,t){const n=this.#g.some(n=>n.transactionId===e&&n.grantType===t);if(n)return void h.debug("Grant signal already in queue, skipping",{transactionId:e,grantType:t});const r={transactionId:e,grantType:t,timestamp:(new Date).toISOString(),attempts:0};this.#g.push(r),this.#x(),h.info("Grant signal added to queue",{transactionId:e,grantType:t})}dequeue(e){const t=this.#g.findIndex(t=>t.transactionId===e.transactionId&&t.grantType===e.grantType);-1!==t&&(this.#g.splice(t,1),this.#x(),h.debug("Grant signal removed from queue",{transactionId:e.transactionId,grantType:e.grantType}))}getQueue(){return[...this.#g]}clearQueue(){this.#g=[],this.#x(),h.debug("Grant signal queue cleared")}async sendGrantSignal(e,t){try{if(h.debug("Sending grant signal",{transactionId:e,grantType:t}),!await this.#m.sendGrantSignal(e,t))throw new Error("Grant signal failed (returned false)");h.info("Grant signal sent successfully",{transactionId:e,grantType:t})}catch{h.warn("Failed to send grant signal, adding to queue",{transactionId:e,grantType:t}),this.enqueue(e,t)}}async processQueue(){if(this.#b)h.debug("Queue processing already in progress, skipping");else if(0!==this.#g.length){this.#b=!0,h.info("Processing grant signal queue",{count:this.#g.length});try{for(const e of[...this.#g])await this.#I(e),this.#g.length>1&&await this.#C(100)}finally{this.#b=!1}}}async#I(e){if(e.attempts>=3)return h.error("Grant signal max attempts reached, removing from queue",{transactionId:e.transactionId,grantType:e.grantType,attempts:e.attempts}),void this.dequeue(e);if(e.lastAttemptAt){const t=new Date(e.lastAttemptAt).getTime(),n=Date.now(),r=1e3*Math.pow(2,e.attempts-1),i=n-t;if(i<r)return void h.debug("Skipping signal, waiting for backoff period",{transactionId:e.transactionId,remainingWait:r-i})}e.attempts++,e.lastAttemptAt=(new Date).toISOString(),this.#x();try{h.debug("Attempting to send queued grant signal",{transactionId:e.transactionId,grantType:e.grantType,attempt:e.attempts}),await this.#m.sendGrantSignal(e.transactionId,e.grantType)?(h.info("Queued grant signal sent successfully",{transactionId:e.transactionId,grantType:e.grantType}),this.dequeue(e)):h.warn("Grant signal failed, will retry",{transactionId:e.transactionId,attempt:e.attempts})}catch(t){h.warn("Failed to send queued grant signal, will retry",{transactionId:e.transactionId,attempt:e.attempts,error:t})}}#y(){this.#v=function(e){const t=()=>{h.debug("Network status: online"),e()};return window.addEventListener("online",t),()=>{window.removeEventListener("online",t)}}(()=>{h.debug("Network came online, processing grant signal queue"),this.processQueue()})}destroy(){this.#v&&(this.#v(),this.#v=void 0)}#C(e){return new Promise(t=>setTimeout(t,e))}}function b(...e){for(const t of e){const e=t?.trim();if(e)return e}}function v(e){const t=b(e);return t?.slice(0,64)}const w={userClosedModal:"close_button",userClickedOutside:"dismissed",userDeclinedLastOffer:"last_offer_declined",error:"interrupted",appBackgrounded:"app_backgrounded",appTerminated:"app_terminated"};function y(e){if(null!=e)return w[e]??e}function x(e){return e?{use_case:i(e)}:{}}function I(e){const t=v(e);return t?{placement_id:t}:{}}function C(e,t,n,r,i,o){return{name:"sdk_offer_presentation_failed",distinctId:e,properties:{reason:t,presentationId:n,...r&&{variantId:r},...x(i),...I(o)}}}function k(e,t){const{useCase:n,placementId:r,...i}=t;return{name:"sdk_offer_time_spent",distinctId:e,properties:{...i,...x(n),...I(r)}}}function E(e){const{useCase:t,placementId:n,...r}=e,i={};for(const e in r){const t=r[e];void 0!==t&&(i[e]=t)}return{...i,...x(t),...I(n)}}function $(e,t){return{name:"sdk_sdui_button_tapped",distinctId:e,properties:{...t.variantId&&{variantId:t.variantId},actionType:t.actionType,presentationId:t.presentationId,currentState:t.currentState,...x(t.useCase),...I(t.placementId)}}}function S(){return"undefined"!=typeof crypto&&crypto.randomUUID?crypto.randomUUID():"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,e=>{const t=15&(crypto.getRandomValues(new Uint8Array(1))[0]??0);return("x"===e?t:3&t|8).toString(16)})}class A{#m;#k;#f;#E=[];#$=null;#S=null;#A=null;#T=new Map;#R=0;#N;#U;#L;#O=null;#_=!1;#P=null;constructor(e,t,n){this.#m=e,this.#f=t,this.#k=n??null,this.#M()}async fetchOffers(e,t=!0,n,r){const i=void 0!==r;if(!i&&t&&this.#E.length>0&&this.#$)return h.debug("Using cached offers",{count:this.#E.length}),{offers:[...this.#E]};try{h.debug("Fetching offers from API",{userId:this.#f,maxPostbackTimeMs:r});const t=await this.#m.fetchOffers(this.#f,e,n,r);return 0===t.offers?.length?(h.info("No offers available for user"),i||(this.#E=[],this.#$=Date.now()),{offers:[]}):(i||(this.#E=t.offers,this.#$=Date.now()),h.info("Offers fetched successfully",{count:t.offers.length,offerIds:t.offers.map(e=>e.id)}),{offers:[...t.offers]})}catch(e){throw h.error("Failed to fetch offers",e),e}}beginPresentation(e,t,n,r){return this.#S=r??S(),this.#A=Date.now(),this.#T.clear(),this.#R=0,this.#O=null,this.#N=e,this.#U=t,this.#L=n,this.#_=!1,this.#S}get placementId(){return this.#L}get presentationId(){return this.#S}#D(){return this.#N?{variantId:this.#N}:{}}#z(){return this.#L?{placementId:this.#L}:{}}trackOfferPresented(e,t,n,r,i){if(!this.#k||!this.#S)return;this.#R++,this.#O&&this.#O!==e.id&&this.trackOfferViewEnd(this.#O),this.#O=e.id;const o=this.#T.get(e.id);o?(o.viewCount++,o.startTime=Date.now()):this.#T.set(e.id,{startTime:Date.now(),totalTime:0,viewCount:1,reported:!1}),this.#k.track(function(e,t){const{useCase:n,placementId:r,...i}=t;return{name:"sdk_offer_presented",distinctId:e,properties:{...i,...x(n),...I(r)}}}(this.#f,{campaignId:e.campaignId,creativeId:e.creativeId,...null!=e.merchantName&&{advertiserName:e.merchantName},impressionId:t,offerIndex:n,totalOffers:r,presentationId:this.#S,...this.#D(),...this.#z(),...i&&{useCase:i}}))}trackOfferViewEnd(e){const t=this.#T.get(e);t&&t.startTime>0&&(t.totalTime+=(Date.now()-t.startTime)/1e3,t.startTime=0)}trackOfferClaimed(e,t,n,r,i,o){this.#k&&this.#S&&this.#k.track(function(e,t){const{useCase:n,placementId:r,...i}=t;return{name:"sdk_offer_claimed",distinctId:e,properties:{...i,...x(n),...I(r)}}}(this.#f,{campaignId:e.campaignId,creativeId:e.creativeId,...null!=e.merchantName&&{advertiserName:e.merchantName},impressionId:t,transactionId:n,offerIndex:r,totalOffers:i,presentationId:this.#S,...this.#D(),...this.#z(),...o&&{useCase:o}}))}trackOfferDeclined(e,t,n,r,i,o){if(!this.#k||!this.#S)return;const s=y(i);this.#k.track(function(e,t){const{useCase:n,placementId:r,...i}=t;return{name:"sdk_offer_declined",distinctId:e,properties:{...i,...x(n),...I(r)}}}(this.#f,{campaignId:e.campaignId,creativeId:e.creativeId,...null!=e.merchantName&&{advertiserName:e.merchantName},impressionId:t,offerIndex:n,totalOffers:r,...null!=s&&{declineReason:s},presentationId:this.#S,...this.#D(),...this.#z(),...o&&{useCase:o}}))}endPresentation(e,t){this.#F(e,t,!1),this.#S=null,this.#A=null,this.#T.clear(),this.#R=0,this.#O=null,this.#N=void 0,this.#U=void 0,this.#L=void 0,this.#_=!1}#F(e,t,n,r=!0){if(!this.#k||!this.#S||!this.#A)return;const i=Date.now(),o=(i-this.#A)/1e3,s=n?{keepalive:!0}:void 0;for(const[e,n]of this.#T){let r=n.totalTime;if(n.startTime>0&&(r+=(i-n.startTime)/1e3),n.reported&&r<=0)continue;n.reported=!0;const o=this.#E.find(t=>t.id===e),a=o?this.#E.indexOf(o):0;this.#k.track(k(this.#f,{campaignId:o?.campaignId??"",offerIndex:a,timeSpentSeconds:r,viewCount:n.viewCount,totalOffers:this.#E.length,presentationId:this.#S,...this.#D(),...this.#z(),...t&&{useCase:t}}),s),n.totalTime=0,n.startTime>0&&(n.startTime=i)}if(!r||this.#_)return;this.#_=!0;const a=y(e);this.#k.track(function(e,t){const{useCase:n,placementId:r,...i}=t;return{name:"sdk_offer_sheet_dismissed",distinctId:e,properties:{...i,...x(n),...I(r)}}}(this.#f,{presentationId:this.#S,totalTimeSpentSeconds:o,totalOffers:this.#E.length,offersViewed:this.#R,...null!=a&&{declineReason:a},...this.#D(),...this.#z(),...t&&{useCase:t}}),s)}flushForPageLifecycle(e,t){try{this.#F(e?"appTerminated":"appBackgrounded",t,!0,e)}catch{}}#M(){if("undefined"!=typeof window&&"undefined"!=typeof document)try{const e=()=>this.flushForPageLifecycle(!0,this.#U),t=()=>{"hidden"===document.visibilityState&&this.flushForPageLifecycle(!1,this.#U)};window.addEventListener("pagehide",e),document.addEventListener("visibilitychange",t),this.#P=()=>{window.removeEventListener("pagehide",e),document.removeEventListener("visibilitychange",t)}}catch{}}destroy(){this.#P?.(),this.#P=null}async startTransaction(e,t){try{h.debug("Starting transaction",{campaignId:e,useCase:t});const n=await this.#m.startTransaction(e,this.#f,t);if(!n.transactionId)throw new Error(n.error??"No transactionId in response");return h.info("Transaction started",{transactionId:n.transactionId,campaignId:e}),n.transactionId}catch(t){throw h.error("Failed to start transaction",{campaignId:e,error:t}),t}}clearCache(){this.#E=[],this.#$=null,h.debug("Offer cache cleared")}setUserId(e){this.#f=e,this.clearCache(),h.debug("OfferManager user ID updated",{userId:e})}}const T={[e.NETWORK_ERROR]:"network_error",[e.TIMEOUT]:"network_error",[e.STORAGE_ERROR]:"persistence_error",[e.CONFIGURATION_ERROR]:"not_configured",[e.INITIALIZATION_ERROR]:"not_configured",[e.INVALID_REQUEST]:"api_error",[e.UNKNOWN_ERROR]:"domain_error"};function R(e,t){const n=e[t];return"string"==typeof n?n:void 0}function N(t){if("object"!=typeof t||null===t)return"domain_error";const n=t,r=R(n,"code"),i="number"==typeof n.statusCode;if(r){return T[r]||(r===String(e.API_ERROR)&&i?"http_error":"api_error")}return i?"http_error":t instanceof SyntaxError?"decoding_error":"domain_error"}class U{#m;#B;#H;#V=0;#K=1e3;#q=8e3;#j=null;#W=!1;#G=!1;constructor(e,t){this.#m=e,this.#B=t.transactionId,this.#H=t.timeout??3e4}async poll(){return this.#W?(h.warn("Verification polling already in progress",{transactionId:this.#B}),"pending"):(this.#W=!0,this.#V=Date.now(),h.debug("Starting verification polling",{transactionId:this.#B,timeout:this.#H}),this.#Q())}stop(){this.#W=!1,null!==this.#j&&(clearTimeout(this.#j),this.#j=null),h.debug("Verification polling stopped",{transactionId:this.#B})}async#Q(){for(;this.#W;){const e=Date.now()-this.#V;if(e>=this.#H)return h.warn("Verification polling timeout",{transactionId:this.#B,elapsed:e}),this.stop(),"pending";try{const e=await this.#m.checkVerificationStatus(this.#B);if(h.debug("Verification status checked",{transactionId:this.#B,status:e.status,rawStatus:e.raw}),"verified"===e.status)return h.info("Transaction verified",{transactionId:this.#B}),this.stop(),"verified";if("failed"===e.status)return h.warn("Transaction failed verification",{transactionId:this.#B}),this.stop(),"failed";await this.#C(this.#K),this.#K=Math.min(2*this.#K,this.#q)}catch(e){h.error("Error checking verification status",{transactionId:this.#B,error:e}),this.#G||(this.#G=!0,this.#m.reportError({errorType:N(e),message:e instanceof Error?e.message:String(e),context:"verify_transaction",...e instanceof Error&&e.stack?{stackTrace:e.stack}:{}})),await this.#C(this.#K)}}return"pending"}async#C(e){return new Promise(t=>{this.#j=window.setTimeout(()=>{this.#j=null,t()},e)})}}const L=/^[A-Za-z0-9_-]+$/;class O{#p;#m;#f;constructor(e,t,n){this.#p=e,this.#m=t,this.#f=n}setUserId(e){if(this.#f===e)return;const t=this.getPending();this.clearPending(),this.#f=e,t&&this.#p.set(this.#Y(),t)}notePending(e,t){const n={transactionId:e,recordedAt:(new Date).toISOString(),grantsEntitlement:t?.grantsEntitlement??!1,...void 0!==t?.placementId&&{placementId:t.placementId},...void 0!==t?.useCase&&{useCase:t.useCase}};this.#p.set(this.#Y(),n),h.debug("StrictUnlockReconciler: noted pending claim",{transactionId:e})}clearPending(){this.#p.remove(this.#Y()),h.debug("StrictUnlockReconciler: cleared pending claim")}getPending(){const e=this.#p.get(this.#Y());if(!e)return null;if("string"!=typeof e.transactionId||"string"!=typeof e.recordedAt||!L.test(e.transactionId))return h.warn("StrictUnlockReconciler: dropping malformed pending claim"),this.clearPending(),null;const t=Date.now()-new Date(e.recordedAt).getTime();return!(t>=0)||t>6048e5?(h.debug("StrictUnlockReconciler: dropping stale pending claim",{age:t}),this.clearPending(),null):(void 0!==e.placementId&&"string"!=typeof e.placementId&&delete e.placementId,void 0===e.useCase||a(e.useCase)||(h.warn("StrictUnlockReconciler: dropping an unrecognised use case from a pending claim"),delete e.useCase),e)}async verify(e,t=15e3){try{const n=new U(this.#m,{transactionId:e,timeout:t});return await n.poll()}catch(t){return h.warn("StrictUnlockReconciler: verification poll failed",{transactionId:e,error:t}),"pending"}}#Y(){return`${this.#f}_strict_pending`}}class _{#X=null;#Z=null;#J;#ee;#te;#ne;constructor(e,t,n,r){this.#te=e,this.#J=t,this.#ne=n,this.#ee=r}useCase(e){return this.#ne={...this.#ne,useCase:e},this}headline(e){return this.#ne={...this.#ne,headline:e},this}subheadline(e){return this.#ne={...this.#ne,subheadline:e},this}onNotGranted(e){return this.#X=e,this}onLoadingStateChange(e){return this.#Z=e,this}async show(){try{this.#Z&&this.#Z(!0),h.debug("PlacementBuilder: Executing presentation",{id:this.#te});const e=await this.#J(this.#ne);return this.#Z&&this.#Z(!1),"dismissed"===e.status&&e.reason&&this.#X&&this.#X(e.reason),e}catch(t){this.#Z&&this.#Z(!1),h.error("PlacementBuilder: Error during presentation",t);const n={type:"error",error:{code:e.UNKNOWN_ERROR,message:t instanceof Error?t.message:"Unknown error"}};return this.#X&&this.#X(n),{status:"dismissed",reason:n}}}async redeem(){return h.debug("PlacementBuilder: Redeeming",{id:this.#te}),this.#ee(this.#te)}}function P(e){return"immediate"!==e}const M={reduceChurn:"deferred",rewardUsers:"immediate"},D=["immediate","deferred","deferredWhileAlive"];const z="transactions";function F(e){const t=new Date(e.createdAt).getTime();return Number.isFinite(t)?t:0}function B(e){return"object"==typeof e&&null!==e&&!Array.isArray(e)}function H(e,t){if(!B(e))return{};const n={};for(const[r,i]of Object.entries(e))t(i)&&(n[r]=i);return n}class V{#re;constructor(e){this.#re=e}#ie(){const e=this.#re.read();return B(e)?{transactions:H(e.transactions,B),placements:H(e.placements,e=>"string"==typeof e),latest:"string"==typeof e.latest?e.latest:null}:{transactions:{},placements:{},latest:null}}#oe(e){this.#re.write(e)}#se(e){return!!e&&"claimed"===e.status&&!this.#ae(e)}#ae(e){const t=new Date(e.expiresAt).getTime();return!Number.isFinite(t)||t<=Date.now()}save(e){const t=this.#ie();t.transactions[e.id]=e,e.placementId&&(t.placements[e.placementId]=e.id),t.latest=e.id,this.#le(t),this.#oe(t),h.debug("TransactionStore: saved transaction",{transactionId:e.id,placement:e.placementId})}getByTransactionId(e){return this.#ie().transactions[e]??null}getByPlacement(e){const t=this.#ie(),n=t.placements[e];if(!n)return null;const r=t.transactions[n];return this.#se(r)?r:null}getLatest(){const e=this.#ie();if(e.latest){const t=e.transactions[e.latest];if(this.#se(t))return t}return Object.values(e.transactions).filter(e=>this.#se(e)).sort((e,t)=>F(t)-F(e))[0]??null}markRedeemed(e){const t=this.#ie(),n=t.transactions[e];n&&(n.status="redeemed",n.redeemedAt=(new Date).toISOString(),n.placementId&&t.placements[n.placementId]===e&&delete t.placements[n.placementId],t.latest===e&&(t.latest=null),this.#oe(t),h.debug("TransactionStore: marked redeemed",{transactionId:e}))}#le(e){for(const[t,n]of Object.entries(e.transactions))(this.#ae(n)||"redeemed"===n.status)&&delete e.transactions[t];for(const[t,n]of Object.entries(e.placements))e.transactions[n]||delete e.placements[t];e.latest&&!e.transactions[e.latest]&&(e.latest=null)}clear(){this.#oe({transactions:{},placements:{},latest:null})}}const K=e=>{const t=e?.trim();if(void 0!==t&&t.length>0)return t};const q=e=>`All ${e} features are now unlocked.`;function j(e,t){let n=e;for(const[e,r]of Object.entries(t))n=n.replace(`:${e}`,encodeURIComponent(r));return n}const W="2.0.6";function G(e,t){return e.length<=t?e:e.slice(0,t-15)+"... [truncated]"}function Q(e,t,n){return G(""===e.trim()?n:e,t)}function Y(e,t){return Object.assign(e,{code:t})}class X{#ce;#de;#he;constructor(e,t){this.#ce=e,this.#de=t,this.#he=new Map}setApiKey(e){this.#ce=e}setBaseURL(e){this.#de=e}async get(e,t){return this.#ue({url:`${this.#de}${e}`,options:{method:"GET",...t},apiKey:this.#ce})}async post(e,t,n){return this.#ue({url:`${this.#de}${e}`,options:{method:"POST",body:t,...n},apiKey:this.#ce})}async patch(e,t,n){return this.#ue({url:`${this.#de}${e}`,options:{method:"PATCH",body:t,...n},apiKey:this.#ce})}async#ue(e){const{url:t,options:n,apiKey:r}=e,i=this.#pe(t,n),o=this.#he.get(i);if(o)return h.debug("Deduplicating request:",t),o;const s=this.#me(t,n,r);this.#he.set(i,s);try{return await s}finally{this.#he.delete(i)}}async#me(e,t,n){const r=t.retries??3;let i=null;for(let o=0;o<=r;o++)try{if(o>0){const e=1e3*Math.pow(2,o-1);h.debug(`Retrying request (attempt ${o}/${r}) after ${e}ms`),await this.#C(e)}return await this.#fe(e,t,n)}catch(e){if(i=e,this.#ge(e))throw e;if(o===r)throw h.error(`Request failed after ${r} retries:`,e),e;h.warn("Request failed, will retry:",e)}throw i??new Error("Request failed")}async#fe(t,n,r){const i=n.timeout??3e4,o=new AbortController,s=setTimeout(()=>o.abort(),i);try{const e={"X-API-Key":r,"X-Platform":"web","Content-Type":"application/json","User-Agent":`Encore-Web-SDK/${W}`,...n.headers},i={method:n.method,headers:e,signal:o.signal};n.body&&(i.body=JSON.stringify(n.body)),h.debug(`${n.method} ${t}`);const s=await fetch(t,i);return s.ok||await this.#be(s),await s.json()}catch(t){if(t instanceof Error){if("AbortError"===t.name)throw Y(new Error("Request timeout"),e.TIMEOUT);if(this.#ve(t))throw Y(new Error(`Network error: ${t.message}`),e.NETWORK_ERROR)}if(t instanceof Error)throw t;throw Y(new Error(String(t)),e.UNKNOWN_ERROR)}finally{clearTimeout(s)}}async#be(t){let n,r=`HTTP ${t.status}: ${t.statusText}`;try{const e=await t.json();"object"==typeof e&&null!==e&&"string"==typeof e.error&&(r=e.error,n="string"==typeof e.code?e.code:void 0)}catch{}const i=n?{code:n,message:r}:{code:e.API_ERROR,statusCode:t.status,message:r},o=new Error(r);throw Object.assign(o,i),o}#ge(e){if("object"==typeof e&&null!==e&&"statusCode"in e&&void 0!==e.statusCode){const t=e.statusCode;return t>=400&&t<500}return!1}#ve(e){return e.message.includes("fetch")||e.message.includes("network")||e.message.includes("ECONNREFUSED")||e.message.includes("ETIMEDOUT")}#pe(e,t){const n=t.body?JSON.stringify(t.body):"";return`${t.method}:${e}:${n}`}#C(e){return new Promise(t=>setTimeout(t,e))}#we(e){switch(e){case"pending_conversion":case"provisional_granted":default:return"pending";case"verified":case"final_granted":return"verified";case"expired":case"failed":return"failed"}}async fetchOffers(e,t,n,r){try{const i=v(n),o=await this.post("/offers/search",{userId:e,attributes:t,platform:"web",sdkVersion:W,...i&&{placementId:i},...void 0!==r&&{maxPostbackTimeMs:r}}),s=[];for(const e of o.offers){const t=e.creatives??[];for(const n of t){const t={id:n.id,title:n.title,description:n.quickInstructions??n.subtitle??n.description??"",imageUrl:n.primaryImageUrl,ctaText:n.ctaText,advertiserUrl:n.destinationUrl??e.destinationUrl??"",campaignId:e.id,creativeId:n.id,quickInstructions:n.quickInstructions??"",instructions:(n.instructions??[]).map(e=>({title:e.title,subtitle:e.subtitle,...null!=e.ctaButtonText&&{ctaButtonText:e.ctaButtonText}})),tooltipText:n.tooltipText??"",...e.organization?.name&&{merchantName:e.organization.name},...e.perk&&{perk:e.perk},...n.logoUrl&&{logoUrl:n.logoUrl},...n.trackingParameters&&{trackingParameters:Object.fromEntries(Object.entries(n.trackingParameters).filter(([,e])=>"string"==typeof e||"number"==typeof e||"boolean"==typeof e).map(([e,t])=>[e,String(t)]))}};s.push(t)}}return{offers:s}}catch(e){throw h.error("Failed to fetch offers:",e),e}}async startTransaction(e,t,n){try{return await this.post("/transactions",{campaignId:e,userId:t,...n&&"reduceChurn"!==n&&{useCase:i(n)}})}catch(e){throw h.error("Failed to start transaction:",e),e}}async sendGrantSignal(e,t){try{const n=function(e){return j("/transactions/:transactionId/signals",{transactionId:e})}(e);return(await this.post(n,{grantType:t})).success}catch(e){throw h.error("Failed to send grant signal:",e),e}}async fetchEntitlements(e){try{const t=await this.get(`/entitlements?userId=${encodeURIComponent(e)}`),n=[],r=[{details:t.provisional,scope:"provisional"},{details:t.verified,scope:"verified"}];for(const{details:e,scope:t}of r)if(e){if(e.freeTrial&&n.push({type:"freeTrial",transactionId:"",scope:t,grantedAt:e.freeTrial.startedAt??"",expiresAt:e.freeTrial.expiresAt??""}),e.discounts)for(const r of e.discounts)n.push({type:"discount",value:r.value,unit:r.unit,transactionId:"",scope:t,grantedAt:"",expiresAt:r.expiresAt??""});e.credits&&n.push({type:"credit",value:e.credits.totalAmount,unit:"dollars",transactionId:"",scope:t,grantedAt:"",expiresAt:e.credits.expiresAt??""})}return h.debug("Transformed entitlements response",{totalCount:n.length}),n}catch(e){throw h.error("Failed to fetch entitlements:",e),e}}async checkVerificationStatus(e){try{const t=function(e){return j("/transactions/:transactionId/status",{transactionId:e})}(e),n=await this.get(t);return{status:this.#we(n.status),raw:n.status}}catch(e){throw h.error("Failed to check verification status:",e),e}}async initUser(e,t){try{return await this.post("/users",{userId:e,...t&&{attributes:t}})}catch(e){throw h.error("Failed to init user:",e),e}}async identifyUser(e,t,n){try{return await this.patch("/users/identify",{currentUserId:e,newUserId:t,...n&&{attributes:n}})}catch(e){throw h.error("Failed to identify user:",e),e}}async fetchConfig(e,t,n){try{const r=`/config?userId=${encodeURIComponent(e)}&sdkVersion=${encodeURIComponent(t)}`+(n&&"reduceChurn"!==n?`&useCase=${encodeURIComponent(i(n))}`:"");return await this.get(r)}catch(e){throw h.error("Failed to fetch config:",e),e}}async reportError(e){try{const n="undefined"!=typeof window?window.location.hostname:"unknown";await this.post("/errors",{errorType:G(e.errorType,100),message:Q(e.message,2e3,"Unknown error"),context:G(e.context,200),severity:e.severity??"error",timestamp:(new Date).toISOString(),platform:"web",sdkVersion:W,appBundleId:Q(n,200,"unknown"),...e.stackTrace&&{stackTrace:G(e.stackTrace,1e4)},...e.userId&&{userId:G(e.userId,200)},...e.metadata&&{metadata:(t=e.metadata,Object.fromEntries(Object.entries(t).map(([e,t])=>[e,G(t,500)])))}},{retries:0})}catch(e){h.error("Failed to report error (non-blocking):",e)}var t}async revokeEntitlements(e){try{return(await this.post("/entitlements/revoke",{userId:e})).success}catch(e){throw h.error("Failed to revoke entitlements:",e),e}}}function Z(e){return e.replace(/([a-z0-9])([A-Z])/g,"$1_$2").toLowerCase()}function J(e){const t={};for(const[n,r]of Object.entries(e))t[Z(n)]=r;return t}function ee(e,t=S()){const n="undefined"!=typeof window?window.location.hostname:"unknown";return{event_id:t,event_name:e.name,event_timestamp:(new Date).toISOString(),distinct_id:e.distinctId,properties:{...J(e.properties),platform:"web",sdk_version:W,app_bundle_id:n}}}function te(e,t,n,r){return fetch(`${e}/events`,{method:"POST",...r?.keepalive&&{keepalive:!0},headers:{"X-Analytics-Key":t,"X-Platform":"web","Content-Type":"application/json"},body:JSON.stringify(n)})}const ne=new Set(["user_identified"]);class re{#ce;#ye;#p;constructor(e,t,n){this.#ce=e,this.#ye=t,this.#p=n??null}track(e,t){try{if(this.#xe(e))return;const n=ee(e);te(this.#ye,this.#ce,n,t).catch(t=>{h.warn("Analytics event dispatch failed",{eventName:e.name,error:t})})}catch{}}#xe(e){if(!this.#p||!ne.has(e.name))return!1;const t=`analytics_dedup_${e.name}_${e.distinctId}`;try{const e=this.#p.get(t),n=Date.now();return"number"==typeof e&&n-e<864e5||(this.#p.set(t,n),!1)}catch{return!1}}}async function ie(e,t){const n=`${e}:${t}`,r=(new TextEncoder).encode(n),i=new Uint8Array(await crypto.subtle.digest("SHA-256",r));let o=0n;for(let e=0;e<8;e++)o=o<<8n|BigInt(i[e]??0);return Number(o%100n)}const oe="ncl_assignment",se="ncl_exposure_marker";class ae{#p;#Ie;#Ce;#n=null;constructor(e,t,n){this.#p=e,this.#Ie=t,this.#Ce=n}setConfig(e){this.#n=e??null}async getCohort(){try{return await this.#ke()}catch(e){return h.warn("[Experiment] getCohort failed — treating as notEnrolled",e),"notEnrolled"}}async#ke(){const e=this.#Ie();if(!e)return"notEnrolled";const t=this.#n;if(!t?.enabled)return"notEnrolled";const n=this.#p.get(oe);if(n?.appAccountId===e&&n?.assignmentVersion===t.assignmentVersion)return n.cohort;if("undefined"==typeof crypto||!crypto.subtle)return h.warn("[Experiment] NCL disabled — crypto.subtle unavailable (page is not a secure context: serve over HTTPS)"),"notEnrolled";const r=await ie(e,t.assignmentVersion),i=function(e,t){return e<t?"treatment":"control"}(r,t.rolloutPct);return this.#p.set(oe,{cohort:i,appAccountId:e,assignmentVersion:t.assignmentVersion}),h.debug("[Experiment] Assigned NCL cohort",{cohort:i,version:t.assignmentVersion,rolloutPct:t.rolloutPct,bucket:r}),i}logExposure(e){if("notEnrolled"===e)return;const t=this.#n,n=this.#Ie();if(!t||!n)return;const r=`${n}:${t.assignmentVersion}`;if(this.#p.get(se)===r)return;const i=function(e,t){return{name:"sdk_experiment_exposure",distinctId:e,properties:{experiment:t.experiment,cohort:t.cohort,assignment_version:t.assignmentVersion,app_account_id:e}}}(n,{experiment:"ncl",cohort:e,assignmentVersion:t.assignmentVersion}),o=S();this.#Ce.enqueue(i,o)&&this.#p.set(se,r)}async getState(){const e=this.#Ie(),t=this.#n,n=await this.getCohort();let r=null;if(e&&t?.enabled&&"undefined"!=typeof crypto&&crypto.subtle)try{r=await ie(e,t.assignmentVersion)}catch{r=null}const i=!!e&&!!t&&this.#p.get(se)===`${e}:${t.assignmentVersion}`;return{experiment:"ncl",enabled:t?.enabled??!1,rolloutPct:t?.rolloutPct??null,assignmentVersion:t?.assignmentVersion??null,appAccountId:e,bucket:r,cohort:n,exposureLogged:i}}}class le{#ce;#ye;#p;#Ee;#$e=new Set;constructor(e,t,n,r){this.#ce=e,this.#ye=t,this.#p=n,this.#Ee=r,this.#M()}enqueue(e,t){const n=ee(e,t),r=this.#Se();r.some(e=>e.event_id===t)||(r.push(n),this.#Ae(r));const i=this.#Se().some(e=>e.event_id===t);return this.#Te(n),i}flush(){for(const e of this.#Se())this.#Te(e)}async#Te(e){if(!this.#$e.has(e.event_id)){this.#$e.add(e.event_id);try{const t=await te(this.#ye,this.#ce,e,{keepalive:!0});t.ok?this.#Re(e.event_id):h.warn("Reliable delivery non-OK, will retry",{status:t.status})}catch(e){h.warn("Reliable delivery failed, will retry",{error:e})}finally{this.#$e.delete(e.event_id)}}}#Re(e){const t=this.#Se().filter(t=>t.event_id!==e);this.#Ae(t)}#Se(){return this.#p.get(this.#Ee)??[]}#Ae(e){this.#p.set(this.#Ee,e)}#M(){"undefined"!=typeof window&&"undefined"!=typeof document&&(window.addEventListener("pagehide",()=>this.flush()),document.addEventListener("visibilitychange",()=>{"hidden"===document.visibilityState&&this.flush()}))}}class ce extends le{constructor(e,t,n){super(e,t,n,"ncl_exposure_outbox")}}class de extends le{constructor(e,t,n){super(e,t,n,"diagnostics_outbox")}}const he={userClosedModal:"close_button",userClickedOutside:"dismissed",userDeclinedLastOffer:"last_offer_declined"},ue={advertiserOutcome:"not_attempted",publisherOutcome:"not_attempted",dismissal:"dismissed"};function pe(e,t){if("claimed"===e.status)return{resolution:"presented",...ue,advertiserOutcome:t?.advertiserOutcome??"claimed",dismissal:t?.dismissal??"flow_completed",campaignId:e.campaignId,offerId:e.offerId,...void 0!==e.transactionId&&{transactionId:e.transactionId}};if("unavailable"===e.status)return{resolution:"not_presented",notPresentedReason:t?.notPresentedReason??"error.unknown_error"};const n=e.reason;return t?void 0!==t.notPresentedReason?{resolution:"not_presented",notPresentedReason:t.notPresentedReason}:{resolution:"presented",...ue,...void 0!==t.advertiserOutcome&&{advertiserOutcome:t.advertiserOutcome},...void 0!==t.dismissal&&{dismissal:t.dismissal}}:n?"string"==typeof n?"alreadyPresenting"===n?{resolution:"not_presented",notPresentedReason:"already_presenting"}:"notConfigured"===n?{resolution:"not_presented",notPresentedReason:"not_configured"}:{resolution:"presented",...ue,...void 0!==he[n]&&{dismissal:he[n]}}:{resolution:"not_presented",notPresentedReason:(r=n.error.code,`error.${r.toLowerCase()}`)}:{resolution:"presented",...ue};var r}class me{#Ne;constructor(){this.#Ne=new Map}on(e,t){this.#Ne.has(e)||this.#Ne.set(e,new Set);const n=this.#Ne.get(e);if(!n)throw new Error(`Failed to get handlers for event '${String(e)}'`);return n.add(t),h.debug(`Event listener added for '${String(e)}'`),()=>{this.off(e,t)}}off(e,t){const n=this.#Ne.get(e);n&&(n.delete(t),h.debug(`Event listener removed for '${String(e)}'`),0===n.size&&this.#Ne.delete(e))}emit(e,t){const n=this.#Ne.get(e);if(n&&0!==n.size){h.debug(`Emitting event '${String(e)}'`,{listenerCount:n.size});for(const r of n)try{r(t)}catch(t){h.error(`Error in event handler for '${String(e)}':`,t)}}}removeAllListeners(e){e?(this.#Ne.delete(e),h.debug(`All listeners removed for '${String(e)}'`)):(this.#Ne.clear(),h.debug("All event listeners removed"))}listenerCount(e){return this.#Ne.get(e)?.size??0}hasListeners(e){const t=this.#Ne.get(e);return void 0!==t&&t.size>0}}const fe=16;function ge(e,t,n){return Math.min(n,Math.max(t,e))}function be(e,t,n){return(.2126*e+.7152*t+.0722*n)/255}function ve(e,t,n){const r=e/255,i=t/255,o=n/255,s=Math.max(r,i,o),a=Math.min(r,i,o),l=(s+a)/2,c=s-a;return 0===c?{h:0,s:0,l:l}:{h:((s===r?(i-o)/c%6*60:s===i?60*((o-r)/c+2):60*((r-i)/c+4))%360+360)%360,s:c/(1-Math.abs(2*l-1)),l:l}}function we(e,t,n){return function(e,t,n){const r=(1-Math.abs(2*n-1))*t,i=(e%360+360)%360/60,o=r*(1-Math.abs(i%2-1)),[s,a,l]=i<1?[r,o,0]:i<2?[o,r,0]:i<3?[0,r,o]:i<4?[0,o,r]:i<5?[o,0,r]:[r,0,o],c=n-r/2,d=e=>Math.round(ge(255*(e+c),0,255)).toString(16).padStart(2,"0");return`#${d(s)}${d(a)}${d(l)}`}(e,ge(t,.45,.95),ge(n,.45,.62))}const ye=/^#(?:[0-9a-f]{3,4}|[0-9a-f]{6}|[0-9a-f]{8})$/i,xe=/^(?:rgb|rgba|hsl|hsla|hwb|lab|lch|oklab|oklch|color|color-mix)\(\s*[0-9a-z.,%\s/+-]{1,80}\)$/i,Ie=/^[a-z]{3,24}$/i,Ce=/^var\(\s*--[a-z0-9_-]{1,60}\s*(?:,[a-z0-9#%.,\s-]{0,60})?\)$/i,ke=/^[a-z0-9\s,'"_\-\u00C0-\u024F\u1E00-\u1EFF]{1,128}$/i,Ee=/^(?:0|-?(?:\d{1,5}|\d{0,5}\.\d{1,3})(?:px|rem|em|%|pt|vh|vw|ch|ex))$/i,$e=/^(?:normal|bold|lighter|bolder)$/i,Se=new Set(["left","center","right","start","end"]),Ae=/\/\*|\*\/|[;{}<>\\]/;function Te(e,t){h.warn(`[Encore SDK] Ignoring unsupported ${e} appearance value`,{value:t})}function Re(e){if(null==e)return;if("string"!=typeof e)return null;const t=e.trim();return 0!==t.length?t.length>128||Ae.test(t)?null:t:void 0}function Ne(e){const t=Re(e);if(void 0!==t)return null===t?Te("colour",e):ye.test(t)||xe.test(t)||Ie.test(t)||Ce.test(t)?t:Te("colour",e)}function Ue(e){const t=Re(e);if(void 0!==t)return null===t?Te("font-family",e):ke.test(t)?t:Te("font-family",e)}function Le(e){const t=Re(e);if(void 0!==t)return null===t?Te("length",e):Ee.test(t)?t:Te("length",e)}const Oe="encore-sdk-styles",_e="encore-",Pe="767px",Me="#B728F5";function De(e){const t={},n=Ne(e.primaryColor),r=Ne(e.backgroundColor),i=Ne(e.textColor),o=Le(e.borderRadius),s=Ue(e.fontFamily);return n&&(t.primaryColor=n),r&&(t.backgroundColor=r),i&&(t.textColor=i),o&&(t.borderRadius=o),s&&(t.fontFamily=s),t}const ze="12px",Fe="20px",Be="40px";function He(e={}){if(document.getElementById(Oe))h.debug("Encore styles already injected");else try{const t=document.createElement("style");t.id=Oe,t.textContent=function(e={}){const t=De(e),n=function(e){const t=[];return e.primaryColor&&t.push(`--encore-primary-color: ${e.primaryColor};`),e.backgroundColor&&t.push(`--encore-bg-color: ${e.backgroundColor};`),e.textColor&&t.push(`--encore-text-color: ${e.textColor};`),e.borderRadius&&t.push(`--encore-border-radius: ${e.borderRadius};`),e.fontFamily&&t.push(`--encore-font-family: ${e.fontFamily};`),t.join("\n ")}(t);return`\n /* CSS Custom Properties (Theme Variables) */\n :root {\n ${n||"/* No custom theme variables */"}\n --encore-primary-color: ${t.primaryColor??"#4F46E5"};\n --encore-bg-color: ${t.backgroundColor??"#ffffff"};\n --encore-text-color: ${t.textColor??"#1F2937"};\n --encore-text-muted: color-mix(in srgb, var(--encore-text-color) 60%, transparent);\n /* One step darker than muted, lighter than full text — lead-in copy that must\n read above captions without competing with the page title. */\n --encore-text-secondary: color-mix(in srgb, var(--encore-text-color) 78%, transparent);\n --encore-surface-color: color-mix(in srgb, var(--encore-text-color) 5%, var(--encore-bg-color));\n --encore-border-color: color-mix(in srgb, var(--encore-text-color) 10%, var(--encore-bg-color));\n --encore-border-radius: ${t.borderRadius??"12px"};\n /* Semantic success hue (the reward sheet's status check). Deliberately independent of the\n accent color: the check states a payment fact; the accent sells the offer CTA. */\n --encore-success-color: #159a5b;\n --encore-font-family: ${t.fontFamily??'-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif'};\n }\n\n /* Backdrop */\n .${_e}backdrop {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background-color: rgba(0, 0, 0, 0.55);\n backdrop-filter: blur(2px);\n z-index: 9998;\n opacity: 0;\n transition: opacity 250ms cubic-bezier(0.4, 0, 0.2, 1);\n }\n\n .${_e}backdrop.${_e}visible {\n opacity: 1;\n }\n\n /* Box-sizing reset scoped to the SDK modal so padding/borders never cause\n horizontal overflow on host pages that don't set border-box globally. */\n .${_e}modal,\n .${_e}modal *,\n .${_e}backdrop {\n box-sizing: border-box;\n }\n\n /* Modal Container */\n .${_e}modal {\n position: fixed;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n z-index: 9999;\n background-color: var(--encore-bg-color);\n border-radius: 20px;\n box-shadow: 0 24px 48px -12px rgba(0, 0, 0, 0.18), 0 12px 24px -8px rgba(0, 0, 0, 0.08);\n max-width: 800px;\n max-height: 90vh;\n width: calc(100% - 32px);\n overflow-x: hidden;\n overflow-y: auto;\n opacity: 0;\n transform: translate(-50%, -50%) scale(0.96);\n transition: opacity 250ms cubic-bezier(0.4, 0, 0.2, 1), transform 250ms cubic-bezier(0.4, 0, 0.2, 1);\n font-family: var(--encore-font-family);\n color: var(--encore-text-color);\n /* Anchor the inherited typographic properties at the modal root so host\n page styles can't cascade in. Children inherit OUR values, not the\n host's. Interim guard until Shadow DOM — see web-sdk-style-isolation.md. */\n font-size: 16px;\n font-weight: 400;\n font-style: normal;\n line-height: 1.5;\n letter-spacing: normal;\n word-spacing: normal;\n text-align: left;\n text-transform: none;\n text-indent: 0;\n white-space: normal;\n text-shadow: none;\n }\n\n .${_e}modal.${_e}visible {\n opacity: 1;\n transform: translate(-50%, -50%) scale(1);\n }\n\n /* Close Button */\n .${_e}close-button {\n position: absolute;\n top: 20px;\n right: 20px;\n width: 40px;\n height: 40px;\n border: none;\n background-color: var(--encore-surface-color);\n cursor: pointer;\n border-radius: 50%;\n display: flex;\n align-items: center;\n justify-content: center;\n color: var(--encore-text-muted);\n transition: all 200ms cubic-bezier(0.4, 0, 0.2, 1);\n padding: 0;\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);\n z-index: 10;\n }\n\n .${_e}close-button:hover {\n background-color: var(--encore-bg-color);\n color: var(--encore-text-color);\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.12);\n transform: scale(1.05);\n }\n\n .${_e}close-button:active {\n transform: scale(0.98);\n }\n\n .${_e}close-button:hover {\n outline: 2px solid var(--encore-primary-color);\n outline-offset: 2px;\n }\n\n .${_e}close-button svg {\n width: 18px;\n height: 18px;\n }\n\n /* Body scroll lock */\n body.${_e}no-scroll {\n overflow: hidden;\n }\n\n /* Modal Header */\n .${_e}modal-header {\n padding: 24px 24px 16px;\n border-bottom: 1px solid var(--encore-border-color);\n }\n\n .${_e}modal-title {\n margin: 0;\n font-size: 24px;\n font-weight: 700;\n line-height: 1.25;\n color: var(--encore-text-color);\n }\n\n .${_e}modal-subtitle {\n margin: 8px 0 0;\n font-size: 14px;\n color: var(--encore-text-muted);\n line-height: 1.5;\n }\n\n /* Modal Body */\n .${_e}modal-body {\n padding: 0;\n position: relative;\n isolation: isolate;\n }\n\n /* Carousel Container */\n .${_e}carousel {\n display: flex;\n flex-direction: column;\n overflow: visible;\n }\n\n /* Carousel Header */\n .${_e}carousel-header {\n padding: 40px 68px 28px;\n text-align: center;\n }\n\n .${_e}carousel-title {\n font-size: 32px;\n font-weight: 510;\n line-height: 1.1;\n color: var(--encore-text-color);\n margin: 0 0 8px 0;\n letter-spacing: -0.3px;\n }\n\n .${_e}carousel-subtitle {\n font-size: 16px;\n line-height: 1.2;\n color: var(--encore-text-color);\n margin: 0;\n font-weight: 400;\n }\n\n /* Carousel Cards Container - Horizontal Scroll */\n .${_e}carousel-cards {\n display: flex;\n flex-direction: row;\n overflow-x: auto;\n overflow-y: hidden;\n scroll-behavior: smooth;\n scroll-snap-type: x mandatory;\n -webkit-overflow-scrolling: touch;\n scrollbar-width: none;\n -ms-overflow-style: none;\n gap: 24px;\n padding: 24px 78px;\n position: relative;\n }\n\n .${_e}carousel-cards::-webkit-scrollbar {\n display: none;\n }\n\n /* Carousel Item Wrapper. Only opacity ever animates (active-card dimming) — a\n short 200ms so the highlight reads as tracking the swipe, not trailing it. */\n .${_e}carousel-item {\n flex: 0 0 426px;\n width: 426px;\n scroll-snap-align: center;\n scroll-snap-stop: always;\n opacity: 0.5;\n transition: opacity 200ms cubic-bezier(0.4, 0, 0.2, 1);\n pointer-events: auto;\n }\n\n /* Active carousel item */\n .${_e}carousel-item.${_e}active {\n opacity: 1;\n z-index: 1;\n }\n\n /* Offer Card */\n .${_e}offer-card {\n display: flex;\n flex-direction: column;\n background: var(--encore-bg-color);\n border-radius: 16px;\n box-shadow: 0 2px 12px rgba(116, 112, 133, 0.16);\n overflow: hidden;\n }\n\n /* Offer Banner */\n .${_e}offer-banner {\n width: 100%;\n background-color: transparent;\n position: relative;\n padding: 0;\n height: 180px;\n overflow: hidden;\n border-radius: 16px 16px 0 0;\n }\n\n .${_e}offer-banner-image {\n width: 100%;\n height: 100%;\n display: block;\n object-fit: cover;\n background-color: var(--encore-surface-color);\n opacity: 0;\n transition: opacity 200ms ease-out;\n }\n\n .${_e}offer-banner-image.${_e}loaded {\n opacity: 1;\n }\n\n /* Info button on banner */\n .${_e}banner-info-button {\n position: absolute;\n top: 20px;\n right: 20px;\n width: 24px;\n height: 24px;\n border-radius: 50%;\n background-color: var(--encore-surface-color);\n backdrop-filter: blur(6px);\n border: none;\n display: flex;\n align-items: center;\n justify-content: center;\n cursor: pointer;\n transition: all 150ms ease;\n z-index: 3;\n padding: 0;\n }\n\n .${_e}banner-info-button:hover {\n background-color: var(--encore-border-color);\n transform: scale(1.05);\n }\n\n .${_e}banner-info-button:focus {\n outline: 2px solid var(--encore-primary-color);\n outline-offset: 2px;\n }\n\n .${_e}banner-info-button svg {\n width: 14px;\n height: 14px;\n color: var(--encore-text-color);\n stroke-width: 2;\n }\n\n /* Tooltip */\n .${_e}tooltip {\n position: fixed;\n background-color: rgba(28, 28, 32, 0.95);\n color: #ffffff;\n padding: 8px 12px;\n border-radius: 8px;\n font-size: 12px;\n line-height: 1.4;\n font-weight: 500;\n z-index: 10000;\n pointer-events: none;\n opacity: 0;\n transform: translateY(4px);\n transition: opacity 200ms cubic-bezier(0.4, 0, 0.2, 1), transform 200ms cubic-bezier(0.4, 0, 0.2, 1);\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);\n white-space: normal;\n word-wrap: break-word;\n }\n\n .${_e}tooltip-visible {\n opacity: 1;\n transform: translateY(0);\n }\n\n /* Tooltip arrow (optional - using pseudo-element) */\n .${_e}tooltip::after {\n content: '';\n position: absolute;\n width: 0;\n height: 0;\n border-style: solid;\n }\n\n .${_e}tooltip-top::after {\n bottom: -4px;\n left: 50%;\n transform: translateX(-50%);\n border-width: 4px 4px 0 4px;\n border-color: rgba(28, 28, 32, 0.95) transparent transparent transparent;\n }\n\n .${_e}tooltip-bottom::after {\n top: -4px;\n left: 50%;\n transform: translateX(-50%);\n border-width: 0 4px 4px 4px;\n border-color: transparent transparent rgba(28, 28, 32, 0.95) transparent;\n }\n\n .${_e}tooltip-left::after {\n right: -4px;\n top: 50%;\n transform: translateY(-50%);\n border-width: 4px 0 4px 4px;\n border-color: transparent transparent transparent rgba(28, 28, 32, 0.95);\n }\n\n .${_e}tooltip-right::after {\n left: -4px;\n top: 50%;\n transform: translateY(-50%);\n border-width: 4px 4px 4px 0;\n border-color: transparent rgba(28, 28, 32, 0.95) transparent transparent;\n }\n\n /* Offer Footer */\n .${_e}offer-footer {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 16px 20px;\n border-top: 1px solid var(--encore-border-color);\n gap: 12px;\n min-height: 74px;\n }\n\n /* Offer Merchant */\n .${_e}offer-merchant {\n display: flex;\n align-items: center;\n gap: 8px;\n flex: 1;\n min-width: 0;\n }\n\n .${_e}offer-logo {\n width: 42px;\n height: 42px;\n border-radius: 8px;\n object-fit: contain;\n background-color: var(--encore-surface-color);\n flex-shrink: 0;\n opacity: 0;\n transition: opacity 200ms ease-out;\n }\n\n .${_e}offer-logo.${_e}loaded {\n opacity: 1;\n }\n\n .${_e}offer-merchant-text {\n display: flex;\n flex-direction: column;\n gap: 2px;\n flex: 1;\n min-width: 0;\n }\n\n .${_e}offer-merchant-name {\n font-size: 16px;\n font-weight: 590;\n color: var(--encore-text-color);\n line-height: 1.1;\n letter-spacing: -1px;\n }\n\n .${_e}offer-merchant-desc {\n font-size: 14px;\n color: var(--encore-text-muted);\n line-height: 1.2;\n letter-spacing: -1px;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n }\n\n /* Claim Button */\n .${_e}button-claim {\n padding: 10px 16px;\n height: 34px;\n min-width: 78px;\n font-size: 14px;\n font-weight: 590;\n border-radius: 999px;\n border: none;\n background: var(--encore-primary-color);\n color: white;\n cursor: pointer;\n transition: all 200ms cubic-bezier(0.4, 0, 0.2, 1);\n font-family: var(--encore-font-family);\n white-space: nowrap;\n line-height: 1.2;\n display: flex;\n align-items: center;\n justify-content: center;\n }\n\n .${_e}button-claim:hover:not(:disabled) {\n background: color-mix(in srgb, var(--encore-primary-color) 85%, black);\n transform: translateY(-1px);\n box-shadow: 0 2px 8px color-mix(in srgb, var(--encore-primary-color) 30%, transparent);\n }\n\n .${_e}button-claim:active {\n transform: translateY(0);\n background: color-mix(in srgb, var(--encore-primary-color) 75%, black);\n }\n\n .${_e}button-claim:focus {\n outline: 2px solid var(--encore-primary-color);\n outline-offset: 2px;\n }\n\n .${_e}button-claim:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n transform: none;\n }\n\n /* Carousel Navigation */\n .${_e}carousel-navigation {\n display: flex;\n justify-content: center;\n align-items: center;\n gap: 40px;\n padding: 28px 32px 32px;\n }\n\n .${_e}nav-button {\n width: 32px;\n height: 32px;\n border-radius: 50%;\n border: 1px solid var(--encore-text-muted);\n background-color: var(--encore-bg-color);\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n color: var(--encore-text-muted);\n transition: all 200ms cubic-bezier(0.4, 0, 0.2, 1);\n padding: 0;\n }\n\n .${_e}nav-button:hover:not(:disabled) {\n border-color: var(--encore-primary-color);\n color: var(--encore-primary-color);\n transform: scale(1.05);\n }\n\n .${_e}nav-button:active:not(:disabled) {\n transform: scale(0.95);\n }\n\n .${_e}nav-button:focus {\n outline: 2px solid var(--encore-primary-color);\n outline-offset: 2px;\n }\n\n .${_e}nav-button svg {\n width: 20px;\n height: 20px;\n stroke-width: 2;\n }\n\n .${_e}nav-button:not(:disabled) {\n border-color: var(--encore-primary-color);\n color: var(--encore-primary-color);\n }\n\n .${_e}nav-button:disabled,\n .${_e}nav-button.${_e}disabled {\n opacity: 1;\n cursor: not-allowed;\n border-color: var(--encore-text-muted);\n color: var(--encore-text-muted);\n }\n\n .${_e}nav-button:disabled:hover,\n .${_e}nav-button.${_e}disabled:hover {\n border-color: var(--encore-text-muted);\n color: var(--encore-text-muted);\n transform: none;\n }\n\n /* Loading State */\n .${_e}loading {\n display: flex;\n align-items: center;\n justify-content: center;\n padding: 48px;\n }\n\n .${_e}spinner {\n width: 40px;\n height: 40px;\n border: 3px solid var(--encore-border-color);\n border-top-color: var(--encore-primary-color);\n border-radius: 50%;\n animation: ${_e}spin 0.8s linear infinite;\n }\n\n @keyframes ${_e}spin {\n to { transform: rotate(360deg); }\n }\n\n /* Responsive: Mobile (0-767px) — full-screen vertical sheet */\n @media (max-width: ${Pe}) {\n /* Modal becomes a full-screen sheet. dvh fallback so mobile browser URL\n bars don't clip the bottom. It is a flex column so the height\n propagates down to the scrollable cards region. */\n .${_e}modal {\n display: flex;\n flex-direction: column;\n inset: 0;\n top: 0;\n left: 0;\n transform: none;\n width: 100%;\n height: 100vh;\n height: 100dvh;\n max-width: none;\n max-height: none;\n border-radius: 0;\n margin: 0;\n overflow: hidden;\n }\n\n /* Fade only — override the desktop scale/translate transition. */\n .${_e}modal.${_e}visible {\n transform: none;\n }\n\n /* Body fills the sheet and forwards the height to the carousel.\n min-height:0 lets the inner scroll container actually overflow. */\n .${_e}modal-body {\n display: flex;\n flex: 1 1 auto;\n min-height: 0;\n flex-direction: column;\n }\n\n /* Carousel fills the body so the cards region can flex to fill height. */\n .${_e}carousel {\n flex: 1 1 auto;\n min-height: 0;\n overflow: hidden;\n }\n\n /* Sticky header pinned while the list scrolls; respect the notch. 64px side\n The close button is an absolute overlay (top 16 + 40px tall), so the\n header reserves that band VERTICALLY: the title starts below the X and\n spans the full sheet width with slim symmetric side padding — no dead\n 64px gutters squeezing the headline into the X's row. */\n .${_e}carousel-header {\n position: sticky;\n top: 0;\n z-index: 2;\n background: var(--encore-bg-color);\n padding: calc(64px + env(safe-area-inset-top)) 24px 20px;\n }\n\n .${_e}carousel-title {\n font-size: 22px;\n }\n\n .${_e}carousel-subtitle {\n font-size: 14px;\n }\n\n /* Vertical, full-height scrollable feed. */\n .${_e}carousel-cards {\n flex: 1 1 auto;\n min-height: 0;\n flex-direction: column;\n overflow-x: hidden;\n overflow-y: auto;\n scroll-snap-type: none;\n overscroll-behavior: contain;\n gap: 16px;\n padding: 16px 16px calc(16px + env(safe-area-inset-bottom));\n }\n\n /* Full-width stacked cards, no carousel dimming or snapping.\n overflow:visible so each card's shadow isn't clipped by the item box. */\n .${_e}carousel-item {\n flex: 0 0 auto;\n width: 100%;\n opacity: 1;\n scroll-snap-align: none;\n overflow: visible;\n }\n\n /* Keep the rounded card + visible shadow on mobile (matches design). */\n .${_e}offer-card {\n width: 100%;\n max-width: 100%;\n border-radius: 16px;\n box-shadow: 0 4px 16px rgba(116, 112, 133, 0.22);\n border: 1px solid var(--encore-border-color);\n }\n\n /* Image fills the card edge-to-edge with rounded top corners\n (no inset padding, banner already clips to the card radius). */\n .${_e}offer-banner {\n height: auto;\n padding: 0;\n border-radius: 16px 16px 0 0;\n }\n\n .${_e}offer-banner-image {\n width: 100%;\n height: auto;\n display: block;\n }\n\n /* Logo + name + description on the left, small claim button pinned far\n right on a single row (no wrap / no full-width stacking). */\n .${_e}offer-footer {\n flex-wrap: nowrap;\n align-items: center;\n justify-content: space-between;\n gap: 12px;\n padding: 14px 16px;\n }\n\n .${_e}offer-merchant {\n flex: 1 1 auto;\n min-width: 0;\n }\n\n /* Small button hugging its label, to the far right. */\n .${_e}button-claim {\n flex: 0 0 auto;\n width: auto;\n }\n\n /* No nav arrows in vertical mode. */\n .${_e}carousel-navigation {\n display: none;\n }\n\n /* Keep the close button reachable inside the sticky header / below the notch. */\n .${_e}close-button {\n top: calc(16px + env(safe-area-inset-top));\n right: 16px;\n }\n\n /* Paged carousel keeps its nav bubbles on mobile (the display:none above is\n the responsive/'list' vertical mode only). */\n .${_e}carousel-paged .${_e}carousel-navigation {\n display: flex;\n }\n\n /* NOTE: the reward sheet's own mobile overrides live in a dedicated media\n block AFTER the base reward-sheet section (source order matters at equal\n specificity — a media query adds none). */\n }\n\n /* Responsive: Tablet (768-1023px) */\n @media (min-width: 768px) and (max-width: 1023px) {\n .${_e}modal {\n max-width: 600px;\n }\n }\n\n /* Responsive: Desktop (1024px+) */\n @media (min-width: 1024px) {\n .${_e}modal {\n max-width: 600px;\n }\n }\n\n /* Accessibility: High Contrast Mode */\n @media (prefers-contrast: high) {\n .${_e}button {\n border: 2px solid currentColor;\n }\n }\n\n /* Accessibility: Reduced Motion */\n @media (prefers-reduced-motion: reduce) {\n .${_e}backdrop,\n .${_e}modal,\n .${_e}button,\n .${_e}close-button {\n transition: none;\n }\n\n .${_e}spinner {\n animation: none;\n }\n }\n\n /* Focus Visible (for keyboard navigation) */\n .${_e}button:focus-visible,\n .${_e}close-button:focus-visible {\n outline: 2px solid var(--encore-primary-color);\n outline-offset: 2px;\n }\n\n\n /* ===== Paged carousel (the reward sheet) ===== */\n /* Always-horizontal, one-card-per-view, scroll-snap paged — at every breakpoint.\n Scoped under carousel-paged so the responsive ('list') carousel rules are\n untouched. Each page is slightly narrower than the viewport so the neighboring\n cards PEEK in at the edges at reduced opacity — the same visual grammar as the\n list carousel: "there are more offers, swipe". Desktop caps the page width so\n the peek survives wide modals (no 426px hardcode). */\n .${_e}carousel-paged .${_e}carousel-cards {\n flex-direction: row;\n align-items: center;\n overflow-x: auto;\n overflow-y: hidden;\n scroll-snap-type: x mandatory;\n /* auto, NOT the base 'smooth': smooth scroll-behavior makes the browser ANIMATE\n its own snap re-alignments (e.g. when an async banner image loads and reflows\n the row mid-gesture), which reads as a laggy post-swipe snap. Native gesture\n snapping is untouched, and programmatic paging still requests smooth\n explicitly via scrollIntoView's behavior option. */\n scroll-behavior: auto;\n gap: 12px;\n /* Horizontal padding is 0 — the symmetric first/last-item gutters below own\n the side spacing so the ACTIVE card is always centered. Vertical padding is\n shadow room: overflow-y:hidden would clip the card shadows without it. */\n padding: ${Fe} 0;\n /* One "page" = the card slot. 64px total side allowance → 32px gutter each\n side (a ~20px neighbor-peek after the 12px gap at the 375px design width);\n the 480px cap keeps the peek alive in wide modals. Declared once here and\n shared by the item basis and the centering gutters so they can never drift. */\n --encore-page-size: min(100% - 64px, 480px);\n }\n\n .${_e}carousel-paged .${_e}carousel-item {\n /* Size via width (flex-basis:auto → width), NOT a math function inside the\n flex shorthand: engines that choke on functions in the shorthand drop the\n whole declaration and fall back to the base 426px item — which is exactly a\n clipped, overflowing card on a 375px phone. width + the max-width guard\n make overflow impossible at any breakpoint. */\n flex: 0 0 auto;\n width: var(--encore-page-size);\n max-width: 100%;\n /* Peek legibility: light creatives on the white sheet disappear below ~0.5,\n killing the "more offers" affordance. 0.65 keeps the active card clearly\n dominant while the neighbors stay readable. */\n opacity: 0.65;\n scroll-snap-align: center;\n scroll-snap-stop: always;\n overflow: visible;\n }\n\n /* Symmetric centering gutters: first/last pages get margins of exactly\n (container − page) / 2, so card 0 RESTS CENTERED at scrollLeft 0 (empty gutter\n left, peek right), mid-cards show symmetric peeks, and the last card can reach\n center too. Both the margin percentage and the flex-basis percentage resolve against the same\n container content width, so the math is exact at any size — the natural resting\n position IS the snap position and mount needs no scroll correction. */\n .${_e}carousel-paged .${_e}carousel-item:first-child {\n margin-inline-start: calc((100% - var(--encore-page-size)) / 2);\n }\n\n .${_e}carousel-paged .${_e}carousel-item:last-child {\n margin-inline-end: calc((100% - var(--encore-page-size)) / 2);\n }\n\n .${_e}carousel-paged .${_e}carousel-item.${_e}active {\n opacity: 1;\n }\n\n .${_e}carousel-paged .${_e}offer-card {\n max-width: 460px;\n margin: 0 auto;\n border: 1px solid var(--encore-border-color);\n box-shadow: 0 4px 16px rgba(116, 112, 133, 0.18);\n }\n\n /* Fluid banner: natural aspect, scales with the card. */\n .${_e}carousel-paged .${_e}offer-banner {\n height: auto;\n }\n\n .${_e}carousel-paged .${_e}offer-banner-image {\n width: 100%;\n height: auto;\n display: block;\n }\n\n /* Nav row: centered DIRECTLY beneath the cards — these chevrons are carousel\n controls and must read as part of the carousel unit, so they hug it (never\n bottom-anchored away from it). Comfortable 48px circular tap targets in normal\n flow — no overlay, no z-index games. Rhythm: cards→nav gap = the cards' bottom\n shadow gutter + 4px here (16px total inside the sheet); the 20px bottom padding\n is the nav→footer gap (and the sheet's bottom inset when no trust footer is\n configured). */\n .${_e}carousel-paged .${_e}carousel-navigation {\n display: flex;\n justify-content: center;\n align-items: center;\n gap: 24px;\n padding: 4px 20px ${Fe};\n }\n\n .${_e}carousel-paged .${_e}nav-button {\n width: 48px;\n height: 48px;\n background-color: var(--encore-bg-color);\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);\n }\n\n /* Neutral idle bubble (the accent belongs to the Claim CTA); accent only on hover. */\n .${_e}carousel-paged .${_e}nav-button:not(:disabled) {\n border-color: var(--encore-border-color);\n color: var(--encore-text-color);\n }\n\n .${_e}carousel-paged .${_e}nav-button:hover:not(:disabled) {\n border-color: var(--encore-primary-color);\n color: var(--encore-primary-color);\n box-shadow: 0 4px 14px rgba(0, 0, 0, 0.16);\n }\n\n .${_e}carousel-paged .${_e}nav-button svg {\n width: 22px;\n height: 22px;\n }\n\n .${_e}carousel-paged .${_e}nav-button:disabled,\n .${_e}carousel-paged .${_e}nav-button.${_e}disabled {\n opacity: 0.35;\n box-shadow: none;\n border-color: var(--encore-border-color);\n color: var(--encore-text-muted);\n }\n\n /* ===== Reward sheet chrome (useCase: 'rewardUsers') =====\n The encore-thankyou class names predate the 3.0.0 rename — they are internal\n style hooks, kept so the whole visual system (including the --reward parity\n block below) did not have to churn. See ui/RewardLayout.ts. */\n /* Pure chrome around the unchanged carousel: status block above, trust footer\n below. Desktop: normal flow inside the content-sized modal (the stack is\n inherently tight there). Mobile: joins the sheet's flex chain — the content\n stack is optically centered while the trust footer stays bottom-pinned. */\n .${_e}thankyou {\n display: flex;\n flex-direction: column;\n }\n\n /* SUCCESS UNIT — check → title → receipt as ONE tight visual group. Internal\n gaps are deliberately tight (proximity = grouping); the heading below is the\n sheet's single focal point. No bottom padding: the 32px section break lives\n on the intro header so it is owned in exactly one place. */\n .${_e}thankyou-status {\n display: flex;\n flex-direction: column;\n align-items: center;\n text-align: center;\n padding: ${Be} 24px 0;\n }\n\n /* "Receipt stamp" check: deep-green disc in a soft halo. Calm by design — no\n pulse, no gradient (a payment fact, stated quietly). Margin-bottom is the\n 12px halo ring + the 12px check→title step of the ladder. */\n .${_e}thankyou-check {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 48px;\n height: 48px;\n border-radius: 50%;\n background: var(--encore-success-color);\n color: #ffffff;\n box-shadow: 0 0 0 12px color-mix(in srgb, var(--encore-success-color) 14%, var(--encore-bg-color));\n margin: 0 0 calc(12px + ${ze});\n }\n\n .${_e}thankyou-check svg {\n width: 24px;\n height: 24px;\n }\n\n /* The ONLY large/heavy type on the sheet — everything else defers to it. */\n .${_e}thankyou-title {\n margin: 0;\n font-size: 20px;\n font-weight: 600;\n line-height: 1.25;\n letter-spacing: -0.2px;\n color: var(--encore-text-color);\n overflow-wrap: anywhere;\n }\n\n /* Subheadline — sits tight under the title (same statement, quieter voice). */\n .${_e}thankyou-subtitle {\n margin: 4px 0 0;\n font-size: 14px;\n line-height: 1.5;\n color: var(--encore-text-muted);\n overflow-wrap: anywhere;\n }\n\n /* Context → cards 16px, cards → nav 16px (12px shadow gutter + the nav row's 4px\n top padding): the carousel unit is bound tight to its lead-in above and its\n controls below. The 12px bottom gutter still clears the visible card shadow. */\n .${_e}thankyou .${_e}carousel-cards {\n padding-top: 16px;\n padding-bottom: ${ze};\n }\n\n;\n font-size: 12px;\n line-height: 1.5;\n text-align: center;\n color: var(--encore-text-muted);\n overflow-wrap: anywhere;\n display: -webkit-box;\n -webkit-line-clamp: 2;\n -webkit-box-orient: vertical;\n overflow: hidden;\n }\n\n /* The reward sheet on mobile full-screen: join the sheet's flex chain — the\n content stack floats optically centered above the bottom-pinned trust footer,\n and the carousel keeps its internal scroll. Type + rhythm come from the base\n system above (375px IS its design target) — only sheet-specific bits\n are overridden. This block must stay AFTER the base rules: it wins by\n source order, not specificity. */\n @media (max-width: ${Pe}) {\n .${_e}thankyou {\n flex: 1 1 auto;\n min-height: 0;\n }\n\n /* Full-height composition: everything except the trust footer is ONE tight,\n internally-rigid stack (success unit → context pair → cards → nav row),\n OPTICALLY CENTERED in the space above the bottom-pinned footer. Two\n zero-basis flex spaces own ALL the slack — this ::before above the stack\n (grow 1) and the carousel's ::after below it (grow 1.35, via the carousel's\n own grow factor) — an above:below ratio of 1:1.35 so the stack rests\n slightly high of true center. The stack's internal ladder gaps never\n stretch, so the composition compresses as a unit on short sheets and\n floats as a unit on tall ones. */\n .${_e}thankyou::before {\n content: '';\n flex: 1 1 0;\n min-height: 0;\n }\n\n .${_e}thankyou-status {\n flex: 0 0 auto;\n /* Real fixed margin above the check — the floor when the flex space above\n has fully compressed; the notch inset always survives. */\n padding-top: calc(${Be} + env(safe-area-inset-top));\n }\n\n .${_e}thankyou-check {\n width: 44px;\n height: 44px;\n }\n\n /* The carousel's grow factor IS the below-stack share: its extra height is\n absorbed entirely by the ::after spacer under the nav row, giving the\n 1:1.35 above:below split against the ::before above. Shrinks like before\n (basis auto, min-height 0) so short sheets compress the cards region. */\n .${_e}thankyou .${_e}carousel {\n flex: 1.35 1 auto;\n min-height: 0;\n }\n\n .${_e}thankyou .${_e}carousel::after {\n content: '';\n flex: 1 1 0;\n min-height: 0;\n }\n\n /* Nav hugs the cards (rigid ladder gap) — the old auto-margin bottom-anchor\n is gone: the arrows are carousel controls and read as part of the carousel\n unit, not footer furniture. */\n .${_e}thankyou .${_e}carousel-cards {\n flex: 0 1 auto;\n min-height: 0;\n }\n\n }\n\n /* ===== Reward parity with the native SDUI variant =====\n Tracks streaksCarousel.json — the SAME screen iOS and Android render — so a\n publisher running reward on more than one platform sees one design rather\n than three. Values are read off that file, not eyeballed from a screenshot:\n\n headline 28 / semibold, centered\n subheadline 16 / regular, centered\n offer card cornerRadius 24\n primary CTA cornerRadius 12 (deliberately NOT the pill the churn\n carousel uses — the variant is explicit)\n gutters 20 leading/trailing\n\n Scoped entirely to the --reward modifier, which the chrome always sets: the\n base rules keep a tighter 20/14 scale, and these override it with the\n celebration scale. Placed AFTER the mobile block so it wins on source\n order, matching the convention that block already documents. */\n .${_e}thankyou--reward .${_e}thankyou-title {\n font-size: 28px;\n font-weight: 600;\n line-height: 1.2;\n letter-spacing: -0.4px;\n text-align: center;\n }\n\n .${_e}thankyou--reward .${_e}thankyou-subtitle {\n font-size: 16px;\n font-weight: 400;\n line-height: 1.35;\n text-align: center;\n }\n\n .${_e}thankyou--reward .${_e}thankyou-status {\n padding-left: 20px;\n padding-right: 20px;\n }\n\n /* On the mobile full-screen sheet the variant is edge-to-edge (fullScreenCover,\n detent 1.0, no drag indicator) with 20px gutters. */\n @media (max-width: ${Pe}) {\n .${_e}thankyou--reward .${_e}carousel-cards {\n padding-left: 20px;\n padding-right: 20px;\n }\n }\n\n /* ===== Reward interaction model — tracks streaksCarousel.json's browse state.\n Reward DOM only: either --reward-scoped, or a class (page-indicator / dot /\n reward-*) the reward composition alone renders. See RewardActions.ts and\n OfferCarousel's \`selectable\` option for the per-value rationale. ===== */\n .${_e}thankyou--reward .${_e}carousel-item[aria-selected] {\n cursor: pointer;\n }\n\n /* The listbox is one tab stop, so it needs its own ring. Inset — an outset one\n is clipped by the container's horizontal overflow.\n \n KEYBOARD DEVICES ONLY, and :focus-visible alone is not enough to say so.\n This is a div with tabindex="0", and Safari focuses one on TAP and then\n matches :focus-visible on it — so an iOS user tapping a card to browse\n got a 2px ring around the whole carousel, on a sheet where there is no\n Tab key and so nothing the ring could be telling them. Chrome on desktop\n does not do this, which is why it survived review.\n\n Gated on a fine pointer rather than on :focus-visible being smarter:\n a device with no keyboard has no use for a focus ring, and a device with\n one keeps it exactly as before. */\n .${_e}carousel-select:focus {\n outline: none;\n }\n\n @media (hover: hover) and (pointer: fine) {\n .${_e}carousel-select:focus-visible {\n outline: 2px solid var(--encore-primary-color);\n outline-offset: -2px;\n border-radius: 16px;\n }\n }\n\n /* compactPageIndicator: position feedback only, never a control. */\n .${_e}page-indicator {\n display: flex;\n justify-content: center;\n align-items: center;\n gap: 8px;\n padding: 19px 20px 0;\n }\n\n /* Figma 18304:3071 — four ellipses, inactive 6px, active 10px, 8px edge gaps\n (52px total for four). The size change IS the state change here, so both\n dimensions animate alongside the fill. */\n .${_e}dot {\n flex: 0 0 auto;\n width: 6px;\n height: 6px;\n border-radius: 50%;\n /* var() fallback = today's value, so an unset override is byte-identical. */\n background: var(\n --encore-dot-color,\n color-mix(in srgb, #6A6D81 30%, transparent)\n );\n transition:\n background 200ms cubic-bezier(0.4, 0, 0.2, 1),\n width 200ms cubic-bezier(0.4, 0, 0.2, 1),\n height 200ms cubic-bezier(0.4, 0, 0.2, 1);\n }\n\n .${_e}dot.${_e}active {\n width: 10px;\n height: 10px;\n background: var(--encore-dot-active-color, var(--encore-reward-brand));\n }\n\n /* Trust line + CTA stack, 12px apart, 20px gutters. 31px bottom inset is the\n variant's browse-state padding; env() is ADDED so the 31 always survives. */\n .${_e}reward-actions {\n display: flex;\n flex-direction: column;\n gap: 12px;\n /* max(), not addition. The 31px is the variant's browse-state padding\n and the inset is the hardware's; adding them stacked a full\n home-indicator gap ON TOP of a padding that was already clear of it,\n which is the space under the CTAs in a tall-phone screenshot. Taking\n the larger of the two keeps the 31 as the floor and lets the inset win\n only where it is genuinely bigger.\n\n A mobile browser's own bottom bar is NOT covered by this: it shrinks\n the viewport, which 100dvh on the sheet already tracks. */\n padding: 20px 20px max(31px, env(safe-area-inset-bottom));\n }\n\n .${_e}reward-trust {\n margin: 0;\n font-size: 14px;\n font-weight: 400;\n line-height: 1.2;\n text-align: center;\n color: color-mix(in srgb, var(--encore-text-color) 55%, transparent);\n overflow-wrap: anywhere;\n display: -webkit-box;\n -webkit-line-clamp: 2;\n -webkit-box-orient: vertical;\n overflow: hidden;\n }\n\n .${_e}reward-cta-stack {\n display: flex;\n flex-direction: column;\n gap: 8px;\n }\n\n /* Both buttons are full pills (Figma radius 100), not the variant's 12 — see\n REWARD_BRAND. Heights are the Figma's: primary 51, secondary 48. */\n .${_e}reward-cta-primary,\n .${_e}reward-cta-secondary {\n width: 100%;\n box-sizing: border-box;\n border-radius: 100px;\n font-family: var(--encore-font-family);\n font-size: 16px;\n line-height: 1.2;\n text-align: center;\n cursor: pointer;\n transition: all 200ms cubic-bezier(0.4, 0, 0.2, 1);\n }\n\n /*\n * Claiming switched off (Encore.isClaimEnabled). Matches the carousel's own\n * disabled Claim button: without this the reward CTA is unclickable but still\n * looks and feels live, which reads as a broken button rather than an\n * unavailable one.\n *\n * TWO selectors because there are two elements. The default CTA is a button and\n * carries the native disabled property. A publisher-supplied claim slot is mounted\n * in a div[role=button] host, where disabled is meaningless and :disabled never\n * matches it — that one carries aria-disabled instead. Dropping either selector\n * leaves one of the two paths looking live while it is inert.\n *\n * No backticks in this comment: the whole stylesheet is a template literal, and a\n * backtick here closes it.\n */\n .${_e}reward-cta-primary:disabled,\n .${_e}reward-cta-primary[aria-disabled='true'] {\n opacity: 0.5;\n cursor: not-allowed;\n }\n\n .${_e}reward-cta-primary {\n height: 51px;\n padding: 0 12px;\n border: none;\n font-weight: 700;\n background-image: linear-gradient(\n 98.22deg,\n var(--encore-reward-brand) 0%,\n var(--encore-reward-brand-deep) 100%\n );\n color: #ffffff;\n }\n\n /* Darken via an overlay rather than swapping the background: \`background-image\`\n cannot be color-mixed, and re-declaring the whole gradient per state would put\n the stops in four places. */\n .${_e}reward-cta-primary:hover {\n box-shadow: inset 0 0 0 999px rgba(0, 0, 0, 0.12);\n }\n\n .${_e}reward-cta-primary:active {\n box-shadow: inset 0 0 0 999px rgba(0, 0, 0, 0.2);\n }\n\n .${_e}reward-cta-secondary {\n height: 48px;\n padding: 0 12px;\n border: 1px solid rgba(0, 0, 0, 0.1);\n font-weight: 500;\n background: transparent;\n color: #9c9c9c;\n }\n\n .${_e}reward-cta-secondary:hover {\n border-color: rgba(0, 0, 0, 0.22);\n color: var(--encore-text-color);\n }\n\n .${_e}reward-cta-primary:focus-visible,\n .${_e}reward-cta-secondary:focus-visible {\n outline: 2px solid var(--encore-primary-color);\n outline-offset: 2px;\n }\n\n /* Publisher appearance slots — see APPEARANCE_SLOT_NOTES. */\n .${_e}slot-custom {\n font: inherit;\n color: inherit;\n letter-spacing: normal;\n margin: 0;\n }\n\n .${_e}slot-host {\n display: flex;\n align-items: center;\n justify-content: center;\n height: auto;\n padding: 0;\n border: none;\n background: none;\n background-image: none;\n box-shadow: none;\n color: inherit;\n cursor: pointer;\n }\n\n .${_e}slot-host:hover,\n .${_e}slot-host:active {\n box-shadow: none;\n border-color: transparent;\n color: inherit;\n }\n\n /* Rigid furniture on the sheet: never absorbs slack, never compresses. The\n carousel's ::after owns the elastic space that floats it to the bottom. */\n @media (max-width: ${Pe}) {\n .${_e}thankyou--reward .${_e}reward-actions {\n flex: 0 0 auto;\n /* Pinned to the bottom of the sheet rather than left wherever the\n space split above it happened to end. auto absorbs ALL remaining\n slack, so the CTAs sit against the bottom inset at every height\n instead of floating with a gap under them on a tall phone.\n\n It does not fight the carousel's 1.35:1 share above: that split\n governs the space the carousel and its ::after divide between them,\n and this only claims what is left after the whole column is laid\n out — which on a short sheet is nothing. */\n margin-top: auto;\n }\n }\n\n /* ===== Reward visual parity — Figma 18304:2399. Reward-only selectors.\n Rationale lives in REWARD_VISUAL_NOTES (JS, stripped from the bundle). ===== */\n\n /* Flat: declares NO background, so the sheet inherits the modal's colour like\n every other composition. position stays as the confetti canvas's positioning\n context — it is not background. */\n .${_e}thankyou--reward {\n --encore-reward-brand: ${Me};\n --encore-reward-brand-deep: #6515ED;\n position: relative;\n }\n\n /* Content column holds the 393 design width and centres.\n z-index 1 lifts content over the confetti, per the zStack order. */\n .${_e}thankyou--reward > .${_e}thankyou-status,\n .${_e}thankyou--reward > .${_e}carousel,\n .${_e}thankyou--reward > .${_e}reward-actions {\n position: relative;\n z-index: 1;\n width: 100%;\n max-width: 393px;\n margin-left: auto;\n margin-right: auto;\n }\n\n /* Header (Figma 18304:3391). Text colours stay THEME TOKENS, never the Figma\n hexes — the variant's dark-mode rule (backend #426/#427). */\n .${_e}thankyou--reward .${_e}thankyou-title {\n margin: 0;\n font-size: 28px;\n font-weight: 600;\n line-height: 1.1;\n letter-spacing: -0.28px;\n text-align: center;\n text-wrap: balance;\n }\n\n .${_e}thankyou--reward .${_e}thankyou-subtitle {\n margin: 12px 0 0;\n font-size: 16px;\n font-weight: 400;\n line-height: 1.3;\n text-align: center;\n /* 0.55, not the Figma's 0.50: the variant's WCAG AA figure wins on contrast. */\n color: color-mix(in srgb, var(--encore-text-color) 55%, transparent);\n }\n\n /* Hero carousel. Neighbour = opacity .55 + scale .95 + translateY(11px),\n MEASURED off the render; no filter (opacity composites on the GPU). */\n .${_e}thankyou--reward .${_e}carousel {\n position: relative;\n }\n\n .${_e}thankyou--reward .${_e}carousel-cards {\n gap: 10px;\n /* Half container minus half card — lets the first/last card reach centre. */\n padding: 26px calc(50% - 105px);\n align-items: center;\n }\n\n .${_e}thankyou--reward .${_e}carousel-item {\n flex: 0 0 210px;\n width: 210px;\n opacity: 0.55;\n transform: translateY(11px) scale(0.95);\n transform-origin: center center;\n transition:\n opacity 260ms cubic-bezier(0.4, 0, 0.2, 1),\n transform 260ms cubic-bezier(0.4, 0, 0.2, 1);\n }\n\n /* \`.active\` (geometric, tracks the drag), not \`[aria-selected]\` (commits on\n settle). One index, so they converge at rest. */\n .${_e}thankyou--reward .${_e}carousel-item.${_e}active {\n opacity: 1;\n transform: none;\n z-index: 1;\n }\n\n /* Registering the tint makes it an ANIMATABLE colour rather than an opaque\n token, so the tier-1 -> tier-2 upgrade eases instead of popping. Measured at\n 69-156ms cold against production logos — inside the modal's 250ms fade, so the\n swap is normally masked — but that is a property of a fast connection, not a\n guarantee, and a slow one would land the swap on a fully-visible sheet.\n Browsers without @property ignore this and swap instantly, exactly as before. */\n @property --encore-card-tint {\n syntax: '<color>';\n inherits: false;\n initial-value: ${Me};\n }\n\n /* ---- The card itself (Figma 18304:3383) ---- */\n .${_e}reward-card {\n --encore-card-tint: ${Me};\n position: relative;\n box-sizing: border-box;\n width: 210px;\n height: 260px;\n /* 43 to the pill, then the ladder below is gap-driven. */\n padding: 43px 15px 0;\n display: flex;\n flex-direction: column;\n align-items: center;\n border-radius: 24px;\n overflow: hidden;\n background-color: #ffffff;\n /* Body = tint@10% over white (measured). The radials add the Figma's deeper\n right/bottom wash, derived from the same tint so any brand colour works. */\n background-image:\n radial-gradient(\n 120% 85% at 100% 0%,\n color-mix(in srgb, var(--encore-card-tint) 22%, transparent) 0%,\n transparent 68%\n ),\n radial-gradient(\n 140% 60% at 62% 112%,\n color-mix(in srgb, var(--encore-card-tint) 20%, transparent) 0%,\n transparent 74%\n ),\n linear-gradient(\n 0deg,\n color-mix(in srgb, var(--encore-card-tint) ${Math.round(10)}%, transparent) 0%,\n color-mix(in srgb, var(--encore-card-tint) ${Math.round(10)}%, transparent) 100%\n );\n box-shadow:\n 0 4px 12px rgba(0, 0, 0, 0.09),\n 0 4px 12px rgba(0, 0, 0, 0.02),\n 0 4px 74px rgba(0, 0, 0, 0.06),\n inset -8px 1px 13px color-mix(in srgb, var(--encore-card-tint) 13%, transparent);\n transition: --encore-card-tint 320ms cubic-bezier(0.4, 0, 0.2, 1);\n }\n\n .${_e}reward-card-badge {\n flex: 0 0 auto;\n max-width: 100%;\n box-sizing: border-box;\n padding: 4px 10px;\n border-radius: 16px;\n background: #ffffff;\n box-shadow: 0 2.769px 5.538px rgba(56, 30, 0, 0.03);\n font-size: 14px;\n font-weight: 500;\n line-height: 1.2;\n letter-spacing: -0.3px;\n color: var(--encore-text-color);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n }\n\n /* 84 from the card top = 43 (pad) + 25 (pill) + 16. */\n .${_e}reward-card-icon {\n flex: 0 0 auto;\n margin-top: 16px;\n width: 72px;\n height: 72px;\n border-radius: 18px;\n overflow: hidden;\n display: flex;\n align-items: center;\n justify-content: center;\n background: color-mix(in srgb, var(--encore-card-tint) 92%, #ffffff);\n box-shadow: 0 2.769px 5.538px rgba(56, 30, 0, 0.15);\n }\n\n .${_e}reward-card-icon-image {\n width: 100%;\n height: 100%;\n object-fit: cover;\n display: block;\n }\n\n /* No logo, or a failed load. Ordinary rendering — logoUrl is optional. */\n .${_e}reward-card-monogram {\n font-size: 32px;\n font-weight: 700;\n line-height: 1;\n color: #ffffff;\n }\n\n /* 176 from the card top = 84 + 72 (icon) + 20. */\n .${_e}reward-card-text {\n margin-top: 20px;\n width: 100%;\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 4px;\n min-width: 0;\n }\n\n /* One line: a long name must not push the offer line out of a fixed card. */\n .${_e}reward-card-name {\n max-width: 100%;\n font-size: 18px;\n font-weight: 600;\n line-height: 1.2;\n letter-spacing: -0.18px;\n text-align: center;\n color: var(--encore-text-color);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n }\n\n /* Two lines then clamp — remote perk copy runs longer than the Figma's one. */\n .${_e}reward-card-offer {\n max-width: 100%;\n font-size: 14px;\n font-weight: 400;\n line-height: 1.2;\n letter-spacing: -0.28px;\n text-align: center;\n color: color-mix(in srgb, var(--encore-text-color) 75%, transparent);\n overflow-wrap: anywhere;\n display: -webkit-box;\n -webkit-line-clamp: 2;\n -webkit-box-orient: vertical;\n overflow: hidden;\n }\n\n /* Desktop arrows (mobile has swipe). Rendered only above the breakpoint —\n see OfferCarousel.#createRewardArrows. Centred on padY + half the card. */\n .${_e}reward-arrow {\n position: absolute;\n top: 156px;\n margin-top: -20px;\n z-index: 2;\n width: 40px;\n height: 40px;\n display: flex;\n align-items: center;\n justify-content: center;\n padding: 0;\n border: 1px solid rgba(0, 0, 0, 0.06);\n border-radius: 50%;\n background: rgba(255, 255, 255, 0.92);\n color: var(--encore-text-color);\n box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);\n cursor: pointer;\n transition:\n opacity 200ms cubic-bezier(0.4, 0, 0.2, 1),\n background 200ms cubic-bezier(0.4, 0, 0.2, 1);\n }\n\n .${_e}reward-arrow svg {\n width: 20px;\n height: 20px;\n display: block;\n }\n\n .${_e}reward-arrow-prev {\n left: 12px;\n }\n\n .${_e}reward-arrow-next {\n right: 12px;\n }\n\n .${_e}reward-arrow:hover {\n background: #ffffff;\n }\n\n .${_e}reward-arrow:focus-visible {\n outline: 2px solid var(--encore-reward-brand);\n outline-offset: 2px;\n }\n\n /* Stays in place and in the tab order: vanishing would shift layout. */\n .${_e}reward-arrow:disabled {\n opacity: 0.35;\n cursor: default;\n }\n\n /* The variant's confetti: full-bleed, inert, self-removing after 2s. */\n .${_e}reward-confetti {\n position: absolute;\n inset: 0;\n z-index: 0;\n width: 100%;\n height: 100%;\n pointer-events: none;\n }\n\n /* Reduced motion: confetti is skipped in JS; the hero becomes an instant\n state change. Selection is unaffected. */\n @media (prefers-reduced-motion: reduce) {\n .${_e}thankyou--reward .${_e}carousel-item,\n .${_e}reward-card,\n .${_e}dot,\n .${_e}reward-arrow {\n transition: none;\n }\n }\n\n /* ===== Success Screen ===== */\n .${_e}success-container {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n padding: 3rem 2rem;\n text-align: center;\n min-height: 400px;\n animation: ${_e}fade-in 0.3s ease-out;\n }\n\n .${_e}success-icon {\n width: 80px;\n height: 80px;\n background: var(--encore-primary-color);\n border-radius: 50%;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 48px;\n color: white;\n margin-bottom: 1.5rem;\n animation: ${_e}scale-in 0.5s ease-out;\n }\n\n .${_e}success-title {\n font-size: 1.75rem;\n font-weight: 700;\n color: var(--encore-text-color);\n margin: 0 0 0.75rem 0;\n }\n\n .${_e}success-subtitle {\n font-size: 1.125rem;\n color: var(--encore-text-muted);\n margin: 0 0 2rem 0;\n line-height: 1.6;\n }\n\n .${_e}success-details {\n background: color-mix(in srgb, var(--encore-primary-color) 5%, transparent);\n border-radius: 12px;\n padding: 1.5rem;\n margin-bottom: 2rem;\n min-width: 280px;\n }\n\n .${_e}success-detail {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 0.5rem 0;\n }\n\n .${_e}success-detail:not(:last-child) {\n border-bottom: 1px solid rgba(0, 0, 0, 0.05);\n }\n\n .${_e}success-detail-label {\n font-size: 0.875rem;\n color: var(--encore-text-muted);\n font-weight: 500;\n }\n\n .${_e}success-detail-value {\n font-size: 1rem;\n color: var(--encore-text-color);\n font-weight: 600;\n }\n\n .${_e}success-button {\n background: var(--encore-primary-color);\n color: white;\n border: none;\n border-radius: var(--encore-border-radius);\n padding: 0.875rem 2.5rem;\n font-size: 1rem;\n font-weight: 600;\n cursor: pointer;\n transition: all 0.2s ease;\n box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1);\n }\n\n .${_e}success-button:hover {\n transform: translateY(-2px);\n box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1);\n }\n\n .${_e}success-button:active {\n transform: translateY(0);\n }\n\n .${_e}success-button:focus-visible {\n outline: 2px solid var(--encore-primary-color);\n outline-offset: 2px;\n }\n\n @keyframes ${_e}scale-in {\n from {\n transform: scale(0);\n opacity: 0;\n }\n to {\n transform: scale(1);\n opacity: 1;\n }\n }\n\n /* Referenced by the reward chrome above as well as both deferred screens. */\n @keyframes ${_e}fade-in {\n from { opacity: 0; }\n to { opacity: 1; }\n }\n\n /* ==========================================================================\n Deferred flow: primer (the hold) + redemption (the ready state), and the\n brand components both share.\n ========================================================================== */\n\n /* Shared monogram tile — the guaranteed first paint for every brand logo. */\n .${_e}brand-tile-placeholder {\n display: flex;\n align-items: center;\n justify-content: center;\n background: color-mix(in srgb, var(--encore-primary-color) 12%, var(--encore-bg-color));\n color: var(--encore-primary-color);\n font-weight: 700;\n font-size: 1.2rem;\n }\n\n /* Dual-brand lockup — two tiles settling together ("two brands, one deal"). */\n .${_e}lockup {\n display: flex;\n justify-content: center;\n align-items: center;\n margin: 0.5rem 0 1.5rem 0;\n }\n\n .${_e}lockup-tile {\n width: 56px;\n height: 56px;\n border-radius: 14px;\n object-fit: cover;\n box-shadow: 0 2px 8px color-mix(in srgb, var(--encore-text-color) 14%, transparent);\n background: var(--encore-bg-color);\n }\n\n .${_e}lockup-tile-partner {\n transform: rotate(-4deg);\n animation: ${_e}lockup-settle-left 250ms cubic-bezier(0.4, 0, 0.2, 1) forwards;\n z-index: 1;\n }\n\n .${_e}lockup-tile-host {\n margin-left: -10px;\n transform: rotate(4deg);\n animation: ${_e}lockup-settle-right 250ms cubic-bezier(0.4, 0, 0.2, 1) forwards;\n z-index: 2;\n }\n\n @keyframes ${_e}lockup-settle-left {\n from { transform: rotate(-6deg) translateX(-4px); }\n to { transform: rotate(-4deg) translateX(0); }\n }\n\n @keyframes ${_e}lockup-settle-right {\n from { transform: rotate(6deg) translateX(4px); }\n to { transform: rotate(4deg) translateX(0); }\n }\n\n /* Deal ledger — the claim state machine, rendered. */\n .${_e}ledger {\n display: flex;\n flex-direction: column;\n border: 1px solid var(--encore-border-color);\n border-radius: 16px;\n background: var(--encore-bg-color);\n box-shadow: 0 1px 3px color-mix(in srgb, var(--encore-text-color) 6%, transparent);\n text-align: left;\n overflow: hidden;\n }\n\n .${_e}ledger-row {\n display: flex;\n align-items: center;\n gap: 12px;\n padding: 14px 16px;\n }\n\n .${_e}ledger-row + .${_e}ledger-row {\n border-top: 1px solid var(--encore-border-color);\n }\n\n /* The size class is worn by BOTH forms of the tile — the monogram div and the\n image that replaces it — so it must not set a display. It is emitted after\n .brand-tile-placeholder at equal specificity, so a block display here would\n beat that rule's flex centering and un-center every monogram in a ledger\n row. Scoped to the element that actually needs it, below. */\n .${_e}ledger-logo {\n width: 44px;\n height: 44px;\n border-radius: 11px;\n object-fit: cover;\n flex-shrink: 0;\n }\n\n img.${_e}ledger-logo {\n display: block;\n }\n\n .${_e}ledger-text {\n display: flex;\n flex-direction: column;\n gap: 2px;\n flex: 1 1 auto;\n min-width: 0;\n }\n\n .${_e}ledger-name {\n font-size: 0.95rem;\n font-weight: 600;\n color: var(--encore-text-color);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n }\n\n .${_e}ledger-detail {\n font-size: 0.8rem;\n color: var(--encore-text-muted);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n }\n\n .${_e}ledger-status {\n font-size: 0.85rem;\n font-weight: 600;\n flex-shrink: 0;\n }\n\n .${_e}ledger-status-active {\n color: var(--encore-success-color);\n }\n\n .${_e}ledger-status-pending {\n color: var(--encore-text-muted);\n }\n\n /* Primer screen — centered column, one forward CTA. */\n .${_e}primer-container {\n display: flex;\n flex-direction: column;\n justify-content: center;\n max-width: 440px;\n margin: 0 auto;\n padding: 2.5rem 1.75rem 2rem;\n text-align: center;\n animation: ${_e}fade-in 0.3s ease-out;\n }\n\n .${_e}primer-title {\n font-size: 1.6rem;\n font-weight: 700;\n color: var(--encore-text-color);\n margin: 0 0 0.5rem 0;\n line-height: 1.2;\n }\n\n .${_e}primer-subtitle {\n font-size: 1.05rem;\n color: var(--encore-text-muted);\n margin: 0 0 2rem 0;\n line-height: 1.5;\n }\n\n /* Reuses .encore-button-claim (the clean pill) — full-width + prominent. */\n .${_e}primer-cta {\n width: 100%;\n height: auto;\n min-height: 50px;\n padding: 14px 24px;\n font-size: 1rem;\n font-weight: 600;\n }\n\n /* Redemption screen — the ready state shown by redeem(). */\n .${_e}redemption-container {\n display: flex;\n flex-direction: column;\n max-width: 440px;\n margin: 0 auto;\n padding: 2rem 1.75rem;\n text-align: center;\n animation: ${_e}fade-in 0.3s ease-out;\n }\n\n .${_e}redemption-title {\n font-size: 1.6rem;\n font-weight: 700;\n color: var(--encore-text-color);\n margin: 0 0 0.5rem 0;\n line-height: 1.2;\n }\n\n .${_e}redemption-subtitle {\n font-size: 1.05rem;\n color: var(--encore-text-muted);\n margin: 0 0 1.75rem 0;\n line-height: 1.5;\n }\n\n .${_e}redemption-note {\n font-size: 0.8rem;\n color: var(--encore-text-muted);\n line-height: 1.5;\n margin: 1.25rem 0;\n }\n\n .${_e}redemption-cta {\n width: 100%;\n height: auto;\n min-height: 50px;\n padding: 14px 24px;\n font-size: 1rem;\n font-weight: 600;\n }\n\n /* Mobile sheet composition for both screens. MUST stay AFTER the rules above:\n it overrides their paddings and margins, and the cascade is source order at\n equal specificity. */\n @media (max-width: ${Pe}) {\n /* Both fill the full-height sheet (modal-body is a flex column). Top padding\n clears the close button's overlay band; bottom clears the home indicator. */\n .${_e}primer-container,\n .${_e}redemption-container {\n flex: 1 1 auto;\n max-width: none;\n width: 100%;\n box-sizing: border-box;\n padding: calc(64px + env(safe-area-inset-top)) 24px\n calc(24px + env(safe-area-inset-bottom));\n }\n\n /* The content block floats centered between two flexible spaces (auto margins\n above the lockup and above the CTA); the CTA sits on the bottom edge. */\n .${_e}primer-container .${_e}lockup {\n margin-top: auto;\n }\n\n .${_e}primer-cta {\n margin-top: auto;\n }\n\n .${_e}redemption-container > :first-child {\n margin-top: auto;\n }\n\n .${_e}redemption-cta {\n margin-top: auto;\n }\n }\n `}(e),document.head.appendChild(t),h.debug("Encore styles injected successfully")}catch(e){h.error("Failed to inject Encore styles:",e)}}function Ve(e){return`${_e}${e}`}class Ke{#Ue;#Le=null;#Oe=null;#_e=null;#Pe=null;#Me=!1;#De=null;#ze=[];#Fe=null;#Be=null;#He;#Ve;#Ke;constructor(e={},t={}){this.#Ue=new me,this.#Ve=t.dismissible??!0,this.#He=(t.showCloseButton??!0)&&this.#Ve,this.#Ke=Ne(t.backgroundColor),He(e)}show(){this.#Me?h.warn("Modal is already visible"):(this.#De=document.activeElement,this.#qe(),this.#Le&&document.body.appendChild(this.#Le),this.#Oe&&document.body.appendChild(this.#Oe),document.body.classList.add(Ve("no-scroll")),requestAnimationFrame(()=>{this.#Le?.classList.add(Ve("visible")),this.#Oe?.classList.add(Ve("visible"))}),this.#je(),this.#We(),this.#Ge(),this.#Me=!0,this.#Ue.emit("show",void 0),h.debug("Modal shown"))}hide(){this.#Me&&(this.#Le?.classList.remove(Ve("visible")),this.#Oe?.classList.remove(Ve("visible")),this.#Qe(),this.#Be=setTimeout(()=>{this.#Be=null,this.#Ye()},200))}#Ye(){this.#Xe(),document.body.classList.remove(Ve("no-scroll")),this.#De instanceof HTMLElement&&this.#De.focus(),this.#Me=!1,this.#Ue.emit("hide",void 0),h.debug("Modal hidden")}#Qe(){null!==this.#Be&&(clearTimeout(this.#Be),this.#Be=null)}isVisible(){return this.#Me}setLabelledBy(e){this.#Oe?.setAttribute("aria-labelledby",e)}setContent(e){this.#Pe?(this.#Pe.innerHTML="",this.#Pe.appendChild(e),this.#We(),this.#Oe?.contains(document.activeElement)||this.#Ge()):h.error("Modal body not initialized")}on(e,t){return this.#Ue.on(e,t)}#qe(){this.#Le=document.createElement("div"),this.#Le.className=Ve("backdrop"),this.#Le.setAttribute("aria-hidden","true"),this.#Oe=document.createElement("div"),this.#Oe.className=Ve("modal"),this.#Oe.setAttribute("role","dialog"),this.#Oe.setAttribute("aria-modal","true"),this.#Oe.setAttribute("aria-labelledby",Ve("modal-title")),this.#Ke&&this.#Oe.style.setProperty("background-color",this.#Ke),this.#He&&(this.#_e=document.createElement("button"),this.#_e.className=Ve("close-button"),this.#_e.setAttribute("aria-label","Close modal"),this.#_e.innerHTML='\n <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor">\n <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />\n </svg>\n '),this.#Pe=document.createElement("div"),this.#Pe.className=Ve("modal-body"),this.#_e&&this.#Oe.appendChild(this.#_e),this.#Oe.appendChild(this.#Pe)}#Xe(){this.#Le?.remove(),this.#Oe?.remove(),this.#Le=null,this.#Oe=null,this.#_e=null,this.#Pe=null}#je(){this.#_e?.addEventListener("click",()=>{this.#Ue.emit("close",void 0),this.hide()}),this.#Ve&&this.#Le?.addEventListener("click",()=>{this.#Ue.emit("backdropClick",void 0),this.hide()}),this.#Fe=this.#Ze.bind(this),document.addEventListener("keydown",this.#Fe)}#Ze(e){if(this.#Me)switch(e.key){case"Escape":if(e.preventDefault(),!this.#Ve)break;this.#Ue.emit("close",void 0),this.hide();break;case"Tab":e.preventDefault(),this.#Je(e.shiftKey)}}#Je(e){if(0===this.#ze.length)return;const t=this.#ze.findIndex(e=>e===document.activeElement);let n;n=e?t<=0?this.#ze.length-1:t-1:t>=this.#ze.length-1?0:t+1,this.#ze[n]?.focus()}#We(){if(!this.#Oe)return;const e=['button:not([disabled]):not([tabindex="-1"])','a[href]:not([tabindex="-1"])','input:not([disabled]):not([tabindex="-1"])','select:not([disabled]):not([tabindex="-1"])','textarea:not([disabled]):not([tabindex="-1"])','[tabindex]:not([tabindex="-1"])'].join(", ");this.#ze=Array.from(this.#Oe.querySelectorAll(e))}#Ge(){this.#ze.length>0&&this.#ze[0]?.focus()}destroy(){this.#Fe&&document.removeEventListener("keydown",this.#Fe),this.#Ue.removeAllListeners(),this.#Qe(),this.#Me&&this.#Ye()}}const qe=new Set(["localhost","127.0.0.1","[::1]"]);function je(e){if(!e)return;let t;try{t=new URL(e)}catch{return}return"https:"===t.protocol||"http:"===t.protocol&&qe.has(t.hostname)?e:void 0}class We{#et=null;#tt;#ne;#Me=!1;#nt=null;#rt=null;#it=null;#ot=null;#st=null;constructor(e,t){this.#tt=e,this.#ne={position:"top",maxWidth:200,...t},this.#at()}#at(){this.#it=this.#lt.bind(this),this.#ot=this.#ct.bind(this),this.#st=this.#dt.bind(this),this.#tt.addEventListener("mouseenter",this.#it),this.#tt.addEventListener("mouseleave",this.#ot)}#lt(){this.#rt&&(clearTimeout(this.#rt),this.#rt=null),this.#nt=window.setTimeout(()=>{this.#ht()},50)}#ct(){this.#nt&&(clearTimeout(this.#nt),this.#nt=null),this.#rt=window.setTimeout(()=>{this.#ut()},100)}#ht(){if(this.#Me)return;this.#et=document.createElement("div"),this.#et.className=Ve("tooltip"),this.#et.setAttribute("role","tooltip"),this.#et.textContent=this.#ne.content,this.#ne.maxWidth&&(this.#et.style.maxWidth=`${this.#ne.maxWidth}px`),this.#ne.position&&this.#et.classList.add(Ve(`tooltip-${this.#ne.position}`));const e=this.#tt.getBoundingClientRect();this.#et.style.top=`${e.top}px`,this.#et.style.left=`${e.left}px`,document.body.appendChild(this.#et),this.#st&&(window.addEventListener("scroll",this.#st,!0),window.addEventListener("resize",this.#st)),requestAnimationFrame(()=>{requestAnimationFrame(()=>{this.#et&&(this.#dt(),this.#et.classList.add(Ve("tooltip-visible")))})}),this.#Me=!0}#ut(){this.#Me&&this.#et&&(this.#st&&(window.removeEventListener("scroll",this.#st,!0),window.removeEventListener("resize",this.#st)),this.#et.classList.remove(Ve("tooltip-visible")),setTimeout(()=>{this.#et&&this.#et.parentNode&&this.#et.parentNode.removeChild(this.#et),this.#et=null},200),this.#Me=!1)}#dt(){if(!this.#et||!this.#Me)return;const e=this.#tt.getBoundingClientRect(),t=this.#et.getBoundingClientRect();let n=0,r=0;switch(this.#ne.position??"top"){case"top":n=e.top-t.height-8,r=e.left+e.width/2-t.width/2;break;case"bottom":n=e.bottom+8,r=e.left+e.width/2-t.width/2;break;case"left":n=e.top+e.height/2-t.height/2,r=e.left-t.width-8;break;case"right":n=e.top+e.height/2-t.height/2,r=e.right+8}r=Math.max(8,Math.min(r,window.innerWidth-t.width-8)),n=Math.max(8,Math.min(n,window.innerHeight-t.height-8)),this.#et.style.top=`${n}px`,this.#et.style.left=`${r}px`}updateContent(e){this.#ne.content=e,this.#et&&(this.#et.textContent=e,this.#dt())}destroy(){this.#nt&&(clearTimeout(this.#nt),this.#nt=null),this.#rt&&(clearTimeout(this.#rt),this.#rt=null),this.#Me&&this.#ut(),this.#it&&this.#tt.removeEventListener("mouseenter",this.#it),this.#ot&&this.#tt.removeEventListener("mouseleave",this.#ot),this.#st&&(window.removeEventListener("scroll",this.#st,!0),window.removeEventListener("resize",this.#st))}}class Ge{#Ue;#pt=null;#mt=null;#ft=null;#gt=!0;constructor(e){this.#Ue=new me,this.#gt=e?.claimEnabled??!0}render(e){this.#pt=e,this.#mt=document.createElement("div"),this.#mt.className=Ve("offer-card");const t=this.#bt(e.imageUrl,e.title,e.tooltipText);this.#mt.appendChild(t);const n=this.#vt(e);return this.#mt.appendChild(n),this.#mt}on(e,t){return this.#Ue.on(e,t)}#bt(e,t,n){const r=document.createElement("div");r.className=Ve("offer-banner");const i=document.createElement("img");i.className=Ve("offer-banner-image"),i.alt=t??"Offer image";const o=je(e);o?(i.src=o,i.complete?i.classList.add(Ve("loaded")):i.onload=()=>{i.classList.add(Ve("loaded"))},i.onerror=()=>{h.warn("Failed to load offer image, using fallback"),i.src=this.#wt(),i.classList.add(Ve("loaded"))}):(i.src=this.#wt(),i.classList.add(Ve("loaded"))),r.appendChild(i);const s=document.createElement("button");return s.className=Ve("banner-info-button"),s.setAttribute("aria-label","More information"),s.innerHTML='\n <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor">\n <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" />\n </svg>\n ',s.addEventListener("click",e=>{e.preventDefault(),e.stopPropagation(),h.debug("Info button clicked for offer",{title:t,tooltipText:n})}),n&&(this.#ft=new We(s,{content:n,position:"bottom",maxWidth:200}),r.appendChild(s)),r}#wt(){return`data:image/svg+xml;base64,${btoa('\n <svg xmlns="http://www.w3.org/2000/svg" width="600" height="240" viewBox="0 0 600 240">\n <rect width="600" height="240" fill="#E5E7EB"/>\n <text x="50%" y="50%" text-anchor="middle" dy=".3em" fill="#9CA3AF" font-family="sans-serif" font-size="18">\n Offer Image\n </text>\n </svg>\n ')}`}#vt(e){const t=document.createElement("div");t.className=Ve("offer-footer");const n=document.createElement("div");n.className=Ve("offer-merchant");const r=je(e.logoUrl);if(r){const t=document.createElement("img");t.className=Ve("offer-logo"),t.src=r,t.alt=`${e.merchantName??"Merchant"} logo`,t.complete?t.classList.add(Ve("loaded")):t.onload=()=>{t.classList.add(Ve("loaded"))},t.onerror=()=>{h.warn("Failed to load merchant logo",{merchantName:e.merchantName}),t.style.display="none"},n.appendChild(t)}const i=document.createElement("div");if(i.className=Ve("offer-merchant-text"),e.merchantName){const t=document.createElement("div");t.className=Ve("offer-merchant-name"),t.textContent=e.merchantName,i.appendChild(t)}if(e.description){const t=document.createElement("div");t.className=Ve("offer-merchant-desc"),t.textContent=e.description,i.appendChild(t)}n.appendChild(i);const o=document.createElement("button");return o.className=`${Ve("button")} ${Ve("button-claim")}`,o.textContent=e.ctaText??"Claim",o.setAttribute("aria-label",`Claim offer: ${e.title??"offer"}`),this.#gt?o.addEventListener("click",()=>{this.#pt&&this.#Ue.emit("claim",{offer:this.#pt})}):(o.disabled=!0,o.setAttribute("aria-disabled","true")),t.appendChild(n),t.appendChild(o),t}destroy(){this.#ft&&(this.#ft.destroy(),this.#ft=null),this.#Ue.removeAllListeners(),this.#mt=null,this.#pt=null}}class Qe{#ne;#yt=null;#xt=!1;constructor(e={}){this.#ne=e}render(e){const t=document.createElement("div");t.className=Ve("reward-card"),this.#yt=t;const n=b(e.merchantName,e.title)??e.id;t.style.setProperty("--encore-card-tint",function(e){return we(function(e){let t=2166136261;for(let n=0;n<e.length;n+=1)t^=e.charCodeAt(n),t=Math.imul(t,16777619)>>>0;return t>>>0}(e||"encore")%360,.72,.55)}(n)),this.#It(e);const r=b(this.#ne.badgeText)??"Free trial",i=document.createElement("span");i.className=Ve("reward-card-badge"),i.textContent=r,t.appendChild(i),t.appendChild(this.#Ct(e));const o=document.createElement("div");o.className=Ve("reward-card-text");const s=document.createElement("div");s.className=Ve("reward-card-name"),s.textContent=b(e.merchantName,e.title)??"",o.appendChild(s);const a=b(e.perk,e.description);if(a){const e=document.createElement("div");e.className=Ve("reward-card-offer"),e.textContent=a,o.appendChild(e)}return t.appendChild(o),t}#Ct(e){const t=document.createElement("div");t.className=Ve("reward-card-icon");const n=b(e.merchantName,e.title)??"",r=je(e.logoUrl);if(!r)return t.appendChild(this.#kt(n)),t;const i=document.createElement("img");return i.className=Ve("reward-card-icon-image"),i.alt="",i.setAttribute("aria-hidden","true"),i.src=r,i.onerror=()=>{i.remove(),t.appendChild(this.#kt(n))},t.appendChild(i),t}#kt(e){const t=document.createElement("span");return t.className=Ve("reward-card-monogram"),t.setAttribute("aria-hidden","true"),t.textContent=(Array.from(e)[0]??"★").toUpperCase(),t}#It(e){const t=je(e.logoUrl);var n;t&&(n=t,n?new Promise(e=>{let t=!1;const r=n=>{t||(t=!0,window.clearTimeout(i),e(n))},i=window.setTimeout(()=>r(null),4e3);try{const e=new Image;e.crossOrigin="anonymous",e.onload=()=>{try{r(function(e){const t=document.createElement("canvas");t.width=fe,t.height=fe;const n=t.getContext("2d");if(!n)return null;n.drawImage(e,0,0,fe,fe);try{return function(e){let t=0,n=0,r=0,i=0;for(let o=0;o<e.length;o+=4){if((e[o+3]??0)<200)continue;const s=e[o]??0,a=e[o+1]??0,l=e[o+2]??0,c=be(s,a,l);if(c>.92||c<.1)continue;const{s:d}=ve(s,a,l);if(d<.18)continue;const h=d*d;t+=h,n+=s*h,r+=a*h,i+=l*h}if(0===t)return null;const{h:o,s:s,l:a}=ve(n/t,r/t,i/t);return we(o,s,a)}(n.getImageData(0,0,fe,fe).data)}catch{return null}}(e))}catch(e){h.debug("Brand tint sampling failed — keeping the fallback tint",e),r(null)}},e.onerror=()=>r(null),e.src=n}catch(e){h.debug("Brand tint sampling unavailable — keeping the fallback tint",e),r(null)}}):Promise.resolve(null)).then(e=>{e&&!this.#xt&&this.#yt&&this.#yt.style.setProperty("--encore-card-tint",e)})}destroy(){this.#xt=!0,this.#yt?.remove(),this.#yt=null}}let Ye=0;class Xe{#Ue;#Et;#$t=0;#mt=null;#St=null;#At=null;#Tt=null;#Rt=[];#Nt=null;#Ut=null;#Lt=null;#Ot=null;#_t=null;#Pt=0;#Mt=null;#Dt=-1;#zt=-1;#Ft;#Bt=window.matchMedia(`(max-width: ${Pe})`);#Ht=!1;#Vt=null;#Kt=null;#qt=-1;#jt=!1;#Wt=!1;#Gt=!1;#gt=!0;#Qt=[];#Yt=[];#Xt=[];#Zt="";#Jt=null;#en;#tn;constructor(e,t,n){if(this.#Ue=new me,this.#Et=e,this.#Ft=t,this.#jt="paged"===n?.mode,this.#Wt=n?.hideHeader??!1,this.#Gt=n?.selectable??!1,this.#gt=n?.claimEnabled??!0,this.#en=Ne(n?.dotColor),this.#tn=Ne(n?.dotActiveColor),this.#Zt=`${Ve("offer-option")}-${Ye+=1}-`,0===e.length)throw new Error("OfferCarousel requires at least one offer");this.#nn()}render(){if(this.#mt=document.createElement("div"),this.#mt.className=this.#jt?`${Ve("carousel")} ${Ve("carousel-paged")}`:Ve("carousel"),this.#Nt=document.createElement("div"),this.#Nt.setAttribute("role","status"),this.#Nt.setAttribute("aria-live","polite"),this.#Nt.setAttribute("aria-atomic","true"),this.#Nt.className="sr-only",this.#Nt.style.position="absolute",this.#Nt.style.width="1px",this.#Nt.style.height="1px",this.#Nt.style.padding="0",this.#Nt.style.margin="-1px",this.#Nt.style.overflow="hidden",this.#Nt.style.clip="rect(0, 0, 0, 0)",this.#Nt.style.whiteSpace="nowrap",this.#Nt.style.border="0",!this.#Wt){const e=this.#rn();this.#mt.appendChild(e)}if(this.#St=document.createElement("div"),this.#St.className=Ve("carousel-cards"),this.#Gt&&(this.#St.setAttribute("role","listbox"),this.#St.setAttribute("tabindex","0"),this.#St.setAttribute("aria-label","Choose an offer"),this.#St.classList.add(Ve("carousel-select"))),this.#mt.appendChild(this.#Nt),this.#mt.appendChild(this.#St),this.#Et.length>1){const e=this.#Gt?this.#in():this.#on();if(this.#mt.appendChild(e),this.#Gt&&!this.#Bt.matches)for(const e of this.#sn())this.#mt.appendChild(e)}return this.#an(),this.#Ht=!this.#jt&&this.#Bt.matches,this.#ln(),this.#jt||(this.#Vt=this.#cn.bind(this),this.#Bt.addEventListener("change",this.#Vt)),this.#mt}#ln(){if(this.#dn(),this.#zt=this.#$t,this.#Ht)this.#hn();else{this.#Gt?this.#un():this.#pn(),this.#mn(),this.#fn(0,!1),this.#gn(this.#$t),this.#bn(this.#$t);const e=this.#Et[this.#$t];e&&this.#Dt!==this.#$t&&(this.#Dt=this.#$t,this.#Ue.emit("offerView",{offer:e,index:this.#$t}))}}#cn(){const e=this.#Bt.matches;e!==this.#Ht&&(this.#Ht=e,this.#ln())}#dn(){this.#Ut&&(document.removeEventListener("keydown",this.#Ut),this.#Ut=null),this.#St&&this.#Jt&&(this.#St.removeEventListener("keydown",this.#Jt),this.#Jt=null),this.#St&&this.#Lt&&(this.#St.removeEventListener("scroll",this.#Lt),this.#Lt=null),this.#St&&this.#Ot&&(this.#St.removeEventListener("scrollend",this.#Ot),this.#Ot=null),null!==this.#_t&&(cancelAnimationFrame(this.#_t),this.#_t=null),this.#Mt&&(clearTimeout(this.#Mt),this.#Mt=null),this.#Kt&&(this.#Kt.disconnect(),this.#Kt=null)}#hn(){this.#St&&(this.#Kt=new IntersectionObserver(e=>{let t=null;for(const n of e){if(!n.isIntersecting)continue;const e=n.target.getAttribute("data-index");if(null===e)continue;const r=Number(e);(!t||n.intersectionRatio>t.ratio)&&(t={index:r,ratio:n.intersectionRatio})}if(!t)return;const{index:n}=t;if(n===this.#qt)return;this.#qt=n,this.#$t=n,n!==this.#zt&&(this.#zt=n,this.#Ue.emit("scroll",{axis:"vertical",position:n}));const r=this.#Et[n];r&&(this.#Ue.emit("offerView",{offer:r,index:n}),h.debug(`Offer ${n+1} entered view`))},{root:this.#St,threshold:.5}),this.#St.querySelectorAll(`.${Ve("carousel-item")}`).forEach(e=>this.#Kt?.observe(e)))}on(e,t){return this.#Ue.on(e,t)}getCurrentIndex(){return this.#$t}getTotalOffers(){return this.#Et.length}next(){const e=Math.min(this.#$t+1,this.#Et.length-1);e!==this.#$t&&(this.#$t=e,this.#gn(e),this.#fn(e),this.#vn(`Showing offer ${e+1} of ${this.#Et.length}`),h.debug(`Navigated to offer ${e+1}`))}getSelectedOffer(){return this.#Et[this.#$t]}claimSelected(){const e=this.getSelectedOffer();e?this.#Ue.emit("offerClaim",{offer:e,index:this.#$t}):h.warn("Claim requested with no selected offer — ignoring")}selectOffer(e){e<0||e>=this.#Et.length||e===this.#$t||(this.#$t=e,this.#gn(e),this.#fn(e),this.#vn(`Selected offer ${e+1} of ${this.#Et.length}`),e!==this.#zt&&(this.#zt=e,this.#Ue.emit("scroll",{axis:"horizontal",position:e})))}previous(){const e=Math.max(this.#$t-1,0);e!==this.#$t&&(this.#$t=e,this.#gn(e),this.#fn(e),this.#vn(`Showing offer ${e+1} of ${this.#Et.length}`),h.debug(`Navigated to offer ${e+1}`))}#an(){if(!this.#St)return;const e=this.#St;this.#Et.forEach((t,n)=>{let r;if(this.#Gt){const e=new Qe;r=e.render(t),this.#Yt.push(e)}else{const e=new Ge({claimEnabled:this.#gt});r=e.render(t),this.#Rt.push(e),e.on("claim",()=>{this.#Ue.emit("offerClaim",{offer:t,index:n})})}const i=document.createElement("div");i.className=Ve("carousel-item"),i.setAttribute("data-index",n.toString()),i.appendChild(r),this.#Gt&&(i.id=`${this.#Zt}${n}`,i.setAttribute("role","option"),i.setAttribute("aria-selected",String(n===this.#$t)),i.addEventListener("click",()=>this.selectOffer(n))),e.appendChild(i)}),requestAnimationFrame(()=>{e.classList.add(Ve("cards-ready"))})}#fn(e,t=!0){if(!this.#St)return;const n=this.#St.querySelectorAll(`.${Ve("carousel-item")}`)[e];if(n){if(this.#Gt){const e=this.#St,r=n.getBoundingClientRect(),i=e.getBoundingClientRect(),o=e.scrollLeft+(r.left+r.width/2-(i.left+i.width/2));return void("function"==typeof e.scrollTo?e.scrollTo({left:o,behavior:t?"smooth":"auto"}):e.scrollLeft=o)}n.scrollIntoView({behavior:t?"smooth":"auto",block:"nearest",inline:"center"})}}#gn(e){this.#wn(),this.#yn(e),this.#xn(e)}#xn(e){if(!this.#Gt||!this.#St)return;const t=this.#St.querySelectorAll(`.${Ve("carousel-item")}`);t.forEach((t,n)=>t.setAttribute("aria-selected",String(n===e)));const n=t[e]?.id;n?this.#St.setAttribute("aria-activedescendant",n):this.#St.removeAttribute("aria-activedescendant"),this.#Qt.forEach((t,n)=>t.classList.toggle(Ve("active"),n===e)),this.#In(e);const r=this.#Et[e];r&&this.#Ue.emit("offerSelect",{offer:r,index:e})}#in(){const e=document.createElement("div");return e.className=Ve("page-indicator"),e.setAttribute("aria-hidden","true"),this.#en&&e.style.setProperty("--encore-dot-color",this.#en),this.#tn&&e.style.setProperty("--encore-dot-active-color",this.#tn),this.#Qt=this.#Et.map((t,n)=>{const r=document.createElement("span");return r.className=n===this.#$t?`${Ve("dot")} ${Ve("active")}`:Ve("dot"),e.appendChild(r),r}),e}#sn(){const e=(e,t,n,r)=>{const i=document.createElement("button");return i.type="button",i.className=`${Ve("reward-arrow")} ${Ve(`reward-arrow-${e}`)}`,i.setAttribute("aria-label",t),i.innerHTML=`<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.25" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="${n}" /></svg>`,i.addEventListener("click",r),i};return this.#Xt=[e("prev","Previous offer","M14.5 5.5L8 12l6.5 6.5",()=>this.selectOffer(this.#$t-1)),e("next","Next offer","M9.5 5.5L16 12l-6.5 6.5",()=>this.selectOffer(this.#$t+1))],this.#In(this.#$t),this.#Xt}#In(e){const[t,n]=this.#Xt;t&&(t.disabled=0===e,t.classList.toggle(Ve("disabled"),t.disabled)),n&&(n.disabled=e===this.#Et.length-1,n.classList.toggle(Ve("disabled"),n.disabled))}#un(){this.#St&&(this.#Jt=e=>{let t=null;switch(e.key){case"ArrowLeft":case"ArrowUp":t=this.#$t-1;break;case"ArrowRight":case"ArrowDown":t=this.#$t+1;break;case"Home":t=0;break;case"End":t=this.#Et.length-1;break;default:return}e.preventDefault(),this.selectOffer(Math.max(0,Math.min(t,this.#Et.length-1)))},this.#St.addEventListener("keydown",this.#Jt))}#bn(e){this.#St&&(this.#Pt=e,this.#St.querySelectorAll(`.${Ve("carousel-item")}`).forEach((t,n)=>{n===e?t.classList.add(Ve("active")):t.classList.remove(Ve("active"))}))}#rn(){const e=document.createElement("div");e.className=Ve("carousel-header");const t=document.createElement("h2");t.className=Ve("carousel-title"),t.id=Ve("modal-title"),t.textContent=this.#Ft?.customHeadline??this.#Ft?.titleText??"Unlock 10 free articles – choose an offer below";const n=document.createElement("p");return n.className=Ve("carousel-subtitle"),n.textContent=this.#Cn(this.#$t),this.#At=n,e.appendChild(t),e.appendChild(n),e}#Cn(e){const t=this.#Ft?.customSubheadline??this.#Ft?.subtitleText??"";if(!this.#jt)return t;const n=this.#Et[e]?.perk?.trim();return n||t}#yn(e){if(!this.#jt||!this.#At)return;const t=this.#Cn(e);this.#At.textContent!==t&&(this.#At.textContent=t)}#on(){const e=document.createElement("div");e.className=Ve("carousel-navigation");const t=document.createElement("button");t.className=Ve("nav-button"),t.setAttribute("aria-label","Previous offer"),t.innerHTML=this.#jt?'\n <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.25" stroke-linecap="round" stroke-linejoin="round">\n <path d="M14.5 5.5L8 12l6.5 6.5" />\n </svg>\n ':'\n <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor" style="transform: rotate(90deg);">\n <path stroke-linecap="round" stroke-linejoin="round" d="M19 9l-7 7-7-7" />\n </svg>\n ',t.addEventListener("click",()=>this.previous());const n=document.createElement("button");return n.className=Ve("nav-button"),n.setAttribute("aria-label","Next offer"),n.innerHTML=this.#jt?'\n <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.25" stroke-linecap="round" stroke-linejoin="round">\n <path d="M9.5 5.5L16 12l-6.5 6.5" />\n </svg>\n ':'\n <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor" style="transform: rotate(270deg);">\n <path stroke-linecap="round" stroke-linejoin="round" d="M19 9l-7 7-7-7" />\n </svg>\n ',n.addEventListener("click",()=>this.next()),e.appendChild(t),e.appendChild(n),this.#Tt=e,this.#wn(t,n),e}#wn(e,t){if(!this.#Tt)return;const n=this.#Tt.querySelectorAll(`.${Ve("nav-button")}`),r=e??n[0],i=t??n[1];r&&(r.disabled=0===this.#$t,r.classList.toggle(Ve("disabled"),0===this.#$t)),i&&(i.disabled=this.#$t===this.#Et.length-1,i.classList.toggle(Ve("disabled"),this.#$t===this.#Et.length-1))}#pn(){this.#Ut=this.#kn.bind(this),document.addEventListener("keydown",this.#Ut)}#kn(e){if(this.#mt)switch(e.key){case"ArrowLeft":e.preventDefault(),this.previous();break;case"ArrowRight":e.preventDefault(),this.next()}}#mn(){if(!this.#St)return;const e=this.#St,t="onscrollend"in e;this.#Lt=()=>{null===this.#_t&&(this.#_t=window.requestAnimationFrame(()=>{this.#_t=null,this.#En()})),t||(this.#Mt&&clearTimeout(this.#Mt),this.#Mt=window.setTimeout(()=>this.#$n(),120))},e.addEventListener("scroll",this.#Lt),t&&(this.#Ot=()=>this.#$n(),e.addEventListener("scrollend",this.#Ot))}#Sn(){if(!this.#St)return this.#$t;const e=this.#St,t=e.querySelectorAll(`.${Ve("carousel-item")}`),n=e.getBoundingClientRect(),r=n.left+n.width/2;let i=0,o=1/0;return t.forEach((e,t)=>{const n=e.getBoundingClientRect(),s=Math.abs(r-(n.left+n.width/2));s<o&&(o=s,i=t)}),i}#En(){if(!this.#St)return;const e=this.#Sn();e!==this.#Pt&&this.#bn(e)}#$n(){this.#Mt&&(clearTimeout(this.#Mt),this.#Mt=null);const e=this.#Sn();e!==this.#$t&&(this.#$t=e,this.#gn(e),h.debug(`Gesture settled on offer ${e+1}`)),this.#bn(e),e!==this.#zt&&(this.#zt=e,this.#Ue.emit("scroll",{axis:"horizontal",position:e}));const t=this.#$t;if(t===this.#Dt)return;const n=this.#Et[t];n&&(this.#Dt=t,this.#Ue.emit("offerView",{offer:n,index:t}))}#vn(e){this.#Nt&&(this.#Nt.textContent=e)}#nn(){this.#Et.forEach(e=>{e.imageUrl&&((new Image).src=e.imageUrl,h.debug("Preloading offer image",{offerId:e.id,url:e.imageUrl})),e.logoUrl&&((new Image).src=e.logoUrl,h.debug("Preloading merchant logo",{offerId:e.id,url:e.logoUrl}))})}destroy(){this.#dn(),this.#Vt&&(this.#Bt.removeEventListener("change",this.#Vt),this.#Vt=null),this.#Rt.forEach(e=>e.destroy()),this.#Rt=[],this.#Yt.forEach(e=>e.destroy()),this.#Yt=[],this.#Xt=[],this.#Ue.removeAllListeners(),this.#mt=null,this.#St=null,this.#At=null,this.#Tt=null,this.#Nt=null,this.#Qt=[]}}function Ze(e,t,n,r=!1){const i=document.createElement("div");i.className=`${t} ${Ve("brand-tile-placeholder")}`;const o=e.name?.trim().charAt(0);i.textContent=o?o.toUpperCase():"★",r&&i.setAttribute("aria-hidden","true");const s=je(e.logoUrl);if(s){const o=document.createElement("img");o.className=t,o.alt=r?"":e.name?`${e.name} logo`:"Brand logo",r&&o.setAttribute("aria-hidden","true"),o.width=n,o.height=n,o.decoding="async",o.addEventListener("load",()=>i.replaceWith(o)),o.src=s}return i}function Je(e,t){const n=document.createElement("div");n.className=Ve("lockup"),n.setAttribute("aria-hidden","true");const r=Ze(e,`${Ve("lockup-tile")} ${Ve("lockup-tile-partner")}`,56);return n.appendChild(r),(t.name||t.logoUrl)&&n.appendChild(Ze(t,`${Ve("lockup-tile")} ${Ve("lockup-tile-host")}`,56)),n}function et(e){const t=document.createElement("div");return t.className=Ve("ledger"),e.forEach(e=>t.appendChild(function(e){const t=document.createElement("div");t.className=Ve("ledger-row");const n=Ze(e.brand,Ve("ledger-logo"),44,!0),r=document.createElement("div");r.className=Ve("ledger-text");const i=document.createElement("div");if(i.className=Ve("ledger-name"),i.textContent=e.name,r.appendChild(i),e.detail){const t=document.createElement("div");t.className=Ve("ledger-detail"),t.textContent=e.detail,r.appendChild(t)}const o=document.createElement("div");return o.className=`${Ve("ledger-status")} ${Ve(`ledger-status-${e.status.tone}`)}`,o.textContent=e.status.text,t.appendChild(n),t.appendChild(r),t.appendChild(o),t}(e))),t}function tt(e,t,n){const r=document.createElement("button");return r.className=`encore-button-claim ${t}`,r.setAttribute("type","button"),r.textContent=e,r.addEventListener("click",n),r}class nt{#mt=null;#Ue;#n;constructor(e){this.#n=e,this.#Ue=new me}render(){const{display:e,partner:t}=this.#n,n=e.appDisplayName,r="activation"===this.#n.variant&&n?"activation":"holding",i=document.createElement("div");i.className=Ve("primer-container");const o=t.logoUrl??t.imageUrl,s=Je({...t.name&&{name:t.name},...o&&{logoUrl:o}},{...n&&{name:n},...e.logoUrl&&{logoUrl:e.logoUrl}}),a=document.createElement("h2");var l,c;a.className=Ve("primer-title"),a.id=Ve("modal-title"),a.textContent="activation"===r&&n?(l=n,(c=e.trialPeriod)?`Amazing! Your ${c} free trial of ${l} is ready`:`Amazing! Your ${l} reward is ready`):"Your reward is saved";const d=document.createElement("p");var u;d.className=Ve("primer-subtitle"),d.textContent="activation"===r&&n?(e=>`Next you'll see the ${e} activation screen. No charge today.`)(n):(u=t.name)?`Come back any time to claim it from ${u}. No charge today.`:"Come back any time to claim it. No charge today.";const p=tt("activation"===r&&n?((e,t)=>t?`Activate ${e} trial`:`Continue to ${e}`)(n,e.trialPeriod):"Continue",Ve("primer-cta"),()=>{h.debug("User tapped the primer CTA"),this.#Ue.emit("continue",void 0)});return i.appendChild(s),i.appendChild(a),i.appendChild(d),i.appendChild(p),this.#mt=i,h.debug("Primer screen rendered",{variant:r}),i}on(e,t){return this.#Ue.on(e,t)}destroy(){this.#mt&&(this.#mt.remove(),this.#mt=null),this.#Ue.removeAllListeners(),h.debug("Primer screen destroyed")}}const rt=e=>({...e.advertiserName&&{name:e.advertiserName},...(e.logoUrl??e.imageUrl)&&{logoUrl:e.logoUrl??e.imageUrl}}),it=e=>({brand:rt(e),name:e.advertiserName??"Your reward",...e.reward&&{detail:e.reward},status:{text:"Pending",tone:"pending"}}),ot=e=>{const t=document.createElement("h2");return t.className=Ve("redemption-title"),t.id=Ve("modal-title"),t.textContent=e,t},st=e=>{const t=document.createElement("p");return t.className=Ve("redemption-subtitle"),t.textContent=e,t},at={activation(e){const t=e.host??{},n=t.name??"your app",r=[{brand:{name:n,...t.logoUrl&&{logoUrl:t.logoUrl}},name:n,...t.detail&&{detail:t.detail},status:{text:t.status??"Active",tone:"active"}},it(e)];return[Je(rt(e),{name:n,...t.logoUrl&&{logoUrl:t.logoUrl}}),ot((i=n,o=t.trialPeriod,o?`Congratulations! Your ${o} free trial is active.`:`Congratulations! Your ${i} plan is active.`)),st(q(n)),et(r)];var i,o},reward:e=>[ot("Congratulations!"),st(e.reward?`Now claim your ${e.reward}`:"Now claim your reward"),et([it(e)])]};class lt{#mt=null;#Ue;#n;constructor(e){this.#n=e,this.#Ue=new me}render(){const{advertiserName:e,buttonText:t}=this.#n,n=this.#n.variant??"reward",r=Object.prototype.hasOwnProperty.call(at,n)?n:"reward",i=document.createElement("div");i.className=Ve("redemption-container");for(const e of at[r](this.#n))i.appendChild(e);const o=document.createElement("p");o.className=Ve("redemption-note"),o.textContent=e?`You'll be sent to ${e}. No payment now, cancel anytime.`:"No payment now, cancel anytime.";const s=tt(t??"Claim your reward",Ve("redemption-cta"),()=>{h.debug("User tapped the redemption CTA"),this.#Ue.emit("continue",void 0)});return i.appendChild(o),i.appendChild(s),this.#mt=i,h.debug("Redemption screen rendered",{variant:r}),i}on(e,t){return this.#Ue.on(e,t)}destroy(){this.#mt&&(this.#mt.remove(),this.#mt=null),this.#Ue.removeAllListeners(),h.debug("Redemption screen destroyed")}}function ct(e){return"object"==typeof e&&null!==e&&(1===e.nodeType&&"string"==typeof e.nodeName&&"function"==typeof e.setAttribute&&"function"==typeof e.cloneNode&&"function"==typeof e.querySelectorAll)}function dt(e,t){return null==e?null:"function"==typeof e?function(e,t){try{const n=e(t);return null==n?null:ct(n)?n:(h.warn("[Encore SDK] Appearance renderer returned a non-element — using the default"),null)}catch(e){return h.warn("[Encore SDK] Appearance renderer threw — using the default",{error:e}),null}}(e,t):ct(e)?e:null}function ht(e){if(null!=e&&"function"!=typeof e&&!ct(e))return e}function ut(e,t,n){void 0!==n&&e.style.setProperty(t,n)}function pt(e,t){ut(e,"color",Ne(t.color)),ut(e,"font-family",Ue(t.fontFamily)),ut(e,"font-size",Le(t.fontSize)),ut(e,"font-weight",function(e){if(null==e)return;if("number"==typeof e)return Number.isInteger(e)&&e>=1&&e<=1e3?String(e):Te("font-weight",e);const t=Re(e);if(void 0===t)return;if(null===t)return Te("font-weight",e);if($e.test(t))return t;const n=Number(t);return Number.isInteger(n)&&n>=1&&n<=1e3?t:Te("font-weight",e)}(t.fontWeight)),ut(e,"letter-spacing",Le(t.letterSpacing)),ut(e,"text-align",function(e){const t=Re(e);if(void 0!==t)return null===t?Te("text-align",e):Se.has(t.toLowerCase())?t.toLowerCase():Te("text-align",e)}(t.textAlign))}function mt(e){return"string"==typeof e?.text?b(e.text):void 0}function ft(e,t,n,r){if(null==r)return e;const i=dt(r,{text:t,useCase:n,defaultElement:e});if(i)return i===e?e:vt(e,i,Ve("slot-custom"))?(!e.textContent?.trim()&&t&&e.setAttribute("aria-label",t),e):e;const o=ht(r);if(o){const t=mt(o);t&&(e.textContent=t),pt(e,o)}return e}function gt(e){return mt(ht(e))}function bt(e){const{className:t,label:n,onActivate:r,useCase:i,slot:o}=e,s=!1!==e.enabled,a=document.createElement("button");a.type="button",a.className=t,a.textContent=n;const l=()=>{const e=new AbortController;return s?a.addEventListener("click",r,{signal:e.signal}):(a.disabled=!0,a.setAttribute("aria-disabled","true")),{element:a,setAccessibleName:e=>yt(a,e),destroy:()=>e.abort()}},c=dt(o,{text:n,useCase:i,defaultElement:a});if(!c||c===a){const e=ht(o);if(e){const t=mt(e);t&&(a.textContent=t),function(e,t){pt(e,t),ut(e,"background-color",Ne(t.backgroundColor)),ut(e,"border-radius",Le(t.borderRadius));const n=Ne(t.borderColor);void 0!==n&&(e.style.setProperty("border-color",n),e.style.setProperty("border-style","solid"))}(a,e)}return l()}const d=document.createElement("div");if(d.className=`${t} ${Ve("slot-host")}`,d.setAttribute("role","button"),d.tabIndex=s?0:-1,s||d.setAttribute("aria-disabled","true"),function(e){try{e.style.setProperty("pointer-events","none");const t=[e,...Array.from(e.querySelectorAll(wt))];for(const e of t)e.setAttribute("tabindex","-1")}catch(e){h.warn("[Encore SDK] Could not neutralize a custom appearance element",{error:e})}}(c),!vt(d,c))return l();d.textContent?.trim()||d.setAttribute("aria-label",n);const u=new AbortController,p=e=>{e.preventDefault(),e.stopImmediatePropagation(),r()};return s&&(d.addEventListener("click",p,{capture:!0,signal:u.signal}),d.addEventListener("keydown",e=>{"Enter"!==e.key&&" "!==e.key&&"Spacebar"!==e.key||p(e)},{capture:!0,signal:u.signal})),{element:d,setAccessibleName:e=>yt(d,e,n),destroy:()=>{u.abort(),c.remove()}}}function vt(e,t,n){if(!0===t.parentElement?.classList.contains(Ve("slot-host")))return h.warn("[Encore SDK] The same element was supplied to more than one appearance slot — using the default for this one. Supply a separate element, or a renderer."),!1;const r=e.textContent;try{return e.textContent="",n&&e.classList.add(n),e.appendChild(t),!0}catch(t){return h.warn("[Encore SDK] Could not mount a custom appearance element",{error:t}),n&&e.classList.remove(n),e.textContent=r,!1}}const wt='a[href], button, input, select, textarea, iframe, [tabindex], [contenteditable="true"]';function yt(e,t,n){t?e.setAttribute("aria-label",t):n?e.setAttribute("aria-label",n):e.removeAttribute("aria-label")}const xt=Ve("thankyou-title"),It="Claim gift";class Ct{#ne;#yt=null;#An=null;#Tn=null;#Rn;constructor(e){this.#ne=e}render(){const e=document.createElement("div");e.className=Ve("reward-actions");const t=this.#ne.trustText?.trim(),n=document.createElement("p");n.className=Ve("reward-trust"),n.textContent=t&&t.length>0?t:"No charges until trial ends, cancel anytime.",e.appendChild(n);const r=document.createElement("div");r.className=Ve("reward-cta-stack");const i=this.#ne.useCase??"rewardUsers",o=bt({className:Ve("reward-cta-primary"),label:It,onActivate:()=>this.#ne.onClaim(),enabled:!1!==this.#ne.claimEnabled,useCase:i,...this.#ne.claimSlot&&{slot:this.#ne.claimSlot}});r.appendChild(o.element),this.#An=o,this.#Nn();const s=this.#ne.secondary??"decline";if("none"!==s){const e="next"===s,t=bt({className:Ve("reward-cta-secondary"),label:e?"Next offer":"No thanks",onActivate:()=>e?this.#ne.onNext?.():this.#ne.onDecline(),useCase:i,...!e&&this.#ne.declineSlot&&{slot:this.#ne.declineSlot}});r.appendChild(t.element),this.#Tn=t}return e.appendChild(r),this.#yt=e,e}setSelectedOffer(e){this.#Rn=e,this.#Nn()}#Nn(){if(!this.#An)return;const e=this.#Rn?.trim();this.#An.setAccessibleName(e?`${It} from ${e}`:void 0)}destroy(){this.#An?.destroy(),this.#Tn?.destroy(),this.#yt?.remove(),this.#yt=null,this.#An=null,this.#Tn=null}}const kt=["#B728F5","#6515ED","#FF9F2B","#22C55E","#38BDF8","#F43F5E"];function Et(e,t){return e+Math.random()*(t-e)}class $t{#Un=null;#Ln=null;#On=[];#_n=null;#Pn=0;#Mn=0;#xt=!1;static shouldSkip(){try{return window.matchMedia("(prefers-reduced-motion: reduce)").matches}catch{return!1}}start(e){if(!this.#xt&&!$t.shouldSkip())try{const t=e.getBoundingClientRect(),n=Math.round(t.width),r=Math.round(t.height);if(n<1||r<1)return;const i=document.createElement("canvas");i.className=Ve("reward-confetti"),i.setAttribute("aria-hidden","true");const o=i.getContext("2d");if(!o)return;e.appendChild(i),this.#Un=i,this.#Ln=o,this.#Dn(n,r),this.#zn(),this.#Pn=performance.now(),this.#Mn=this.#Pn,this.#_n=requestAnimationFrame(this.#Fn)}catch(e){h.debug("Confetti unavailable — rendering the sheet without it",e),this.destroy()}}#Dn(e,t){const n=this.#Un,r=this.#Ln;if(!n||!r)return;const i=Math.min(2,window.devicePixelRatio||1);n.width=e*i,n.height=t*i,r.scale(i,i)}#zn(){const e=this.#Un;if(!e)return;const t=Math.min(2,window.devicePixelRatio||1),n=e.width/t,r=e.height/t;this.#On=Array.from({length:22},()=>{const e=Et(6,11);return{x:Et(0,n)+Et(-46,46),y:0*r+Et(.15*-r,.3*r),vx:Et(-46,46),vy:Et(40,160),w:e,h:e*Et(.4,.7),rotation:Et(0,2*Math.PI),spin:Et(-4,4),color:kt[Math.floor(Et(0,kt.length))]??"#B728F5"}})}#Fn=e=>{if(this.#xt)return;const t=this.#Un,n=this.#Ln;if(!t||!n)return;const r=e-this.#Pn,i=Math.min(.05,(e-this.#Mn)/1e3);if(this.#Mn=e,r>=2e3)return void this.destroy();const o=Math.min(2,window.devicePixelRatio||1),s=t.height/o;n.clearRect(0,0,t.width/o,s);const a=r/2e3;n.globalAlpha=a<.66?1:Math.max(0,1-(a-.66)/.34);for(const e of this.#On)e.vy+=320*i,e.vx*=Math.pow(.86,i),e.x+=e.vx*i,e.y+=e.vy*i,e.rotation+=e.spin*i,e.y-e.h>s||(n.save(),n.translate(e.x,e.y),n.rotate(e.rotation),n.fillStyle=e.color,n.fillRect(-e.w/2,-e.h/2,e.w,e.h),n.restore());this.#_n=requestAnimationFrame(this.#Fn)};destroy(){this.#xt=!0,null!==this.#_n&&(cancelAnimationFrame(this.#_n),this.#_n=null),this.#Un?.remove(),this.#Un=null,this.#Ln=null,this.#On=[]}}class St{#Bn=null;#Hn=null;#Vn=!1;start(e){this.#Vn?h.warn("FocusDetector already active"):(this.#Bn=()=>{h.debug("Window focused"),e()},this.#Hn=()=>{"visible"===document.visibilityState&&(h.debug("Document became visible"),e())},window.addEventListener("focus",this.#Bn),document.addEventListener("visibilitychange",this.#Hn),this.#Vn=!0,h.debug("FocusDetector started"))}stop(){this.#Vn&&(this.#Bn&&(window.removeEventListener("focus",this.#Bn),this.#Bn=null),this.#Hn&&(document.removeEventListener("visibilitychange",this.#Hn),this.#Hn=null),this.#Vn=!1,h.debug("FocusDetector stopped"))}isActive(){return this.#Vn}}const At="user_id",Tt="user_attributes";function Rt(e){const t=e.useCase;if(void 0===t||a(t))return e;const n="string"==typeof t?o(t):void 0,{useCase:r,...i}=e;return n?{...i,useCase:n}:i}function Nt(e){const t=e?.values?.text;return!!t&&Object.keys(t).length>0}function Ut(e){return"reduceChurn"===(e??"reduceChurn")}const Lt=new class{#Kn;#p;#m=null;#k=null;#qn=null;#jn=null;#Wn=null;#Gn=null;#Qn=null;#Yn=new Set;#Ue;#Xn=null;#f=null;#Zn={};#Jn=!1;#er=!1;#gt=!0;#tr={};#nr;#rr={};#ir;#or={};#sr={};#ar=new Set;#lr=new Set;#cr=null;#dr=null;#hr;#ur;constructor(){var e;this.#Kn=new u,this.#p=new m,this.#hr=new V((e=this.#p,{read:()=>e.get(z),write:t=>e.set(z,t)})),this.#ur=new V(function(){let e=null;return{read:()=>e,write:t=>{e=t}}}()),this.#Ue=new me}configure(e){const t=this.#Kn.configure(e);if(t){this.#pr();const e=this.#Kn.getBaseURL(),t=this.#Kn.getAnalyticsBaseURL(),n=this.#Kn.getApiKey()??"";if(e){if(this.#m=new X(n,e),t){if(this.#k=new re(n,t,this.#p),!this.#Wn){const e=new ce(n,t,this.#p);this.#Wn=new ae(this.#p,()=>this.#f,e),e.flush()}this.#Xn||(this.#Xn=new de(n,t,this.#p),this.#Xn.flush())}this.#f&&(this.#qn=new g(this.#p,this.#m,this.#f),this.#Qn="strict"===this.#Kn.getUnlockMode()?new O(this.#p,this.#m,this.#f):null,this.#jn?.destroy(),this.#jn=new A(this.#m,this.#f,this.#k??void 0)),this.#Gn=new St}if(h.info("Encore SDK initialized successfully",{version:W}),this.#k&&this.#f){const e="undefined"!=typeof window?window.location.hostname:"unknown";this.#k.track(function(e,t,n){return{name:"sdk_initialized",distinctId:e,properties:{sdkVersion:W,appBundleId:n,platform:"web"}}}(this.#f,0,e))}this.#m&&this.#f&&this.#m.initUser(this.#f).catch(e=>{h.warn("Failed to init user on backend (non-blocking)",e),this.#mr("api_request",e)}),this.#fr(),this.#gr()}return t}#pr(){const e=this.#p.get(At);e?(this.#f=e,h.debug("Loaded existing user ID:",e)):(this.#f=S(),this.#p.set(At,this.#f),h.debug("Generated new user ID:",this.#f));const t=this.#p.get(Tt);t&&(this.#Zn=t,h.debug("Loaded user attributes"))}#br(){return!!this.#Kn.isConfigured()||(h.error("SDK not configured. Call Encore.configure() first."),!1)}identify(e,t){if(!this.#br())return;if(!e||"string"!=typeof e)return void h.error("identify() requires a valid user ID string");const n=this.#f;if(this.#f=e,this.#p.set(At,e),t&&this.setUserAttributes(t),n!==e&&(h.info("User identified:",e),this.#qn&&this.#qn.setUserId(e),this.#jn&&this.#jn.setUserId(e),this.#Qn?.setUserId(e),this.#m&&n&&this.#m.identifyUser(n,e,t?.email?{email:t.email}:void 0).catch(e=>{h.warn("Failed to identify user on backend (non-blocking)",e),this.#mr("api_request",e)}),this.#k)){const n="undefined"!=typeof window?window.location.hostname:"unknown";this.#k.track(function(e,t,n,r){return{name:"user_identified",distinctId:e,properties:{userId:t,appBundleId:n,...r&&{attributes:r}}}}(e,e,n,t))}}getCurrentUserId(){return this.#f}getAppAccountId(){return this.#f}reset(){this.#br()&&(h.info("Resetting SDK"),this.#p.clear(),this.#f=S(),this.#p.set(At,this.#f),this.#Zn={},this.#tr={},this.#or={},this.#rr={},this.#ir=void 0,this.#ur.clear(),this.#sr={},this.#ar.clear(),this.#cr=null,this.#qn&&(this.#qn.clearQueue(),this.#qn.destroy(),this.#m&&this.#f&&(this.#qn=new g(this.#p,this.#m,this.#f))),this.#f&&this.#Qn?.setUserId(this.#f),this.#jn&&(this.#jn.clearCache(),this.#jn.destroy(),this.#m&&this.#f&&(this.#jn=new A(this.#m,this.#f,this.#k??void 0))),this.#Gn?.isActive()&&this.#Gn.stop(),this.#gr(),this.#dr?.(),this.#dr=null,h.debug("SDK reset complete",{newUserId:this.#f}))}getVersion(){return W}get isClaimEnabled(){return this.#gt}set isClaimEnabled(e){this.#gt=e,h.debug("Claim enablement changed",{isClaimEnabled:e})}isConfigured(){return this.#Kn.isConfigured()}getConfiguration(){return this.#Kn.isConfigured()?{apiKey:this.#Kn.getApiKey()??"",environment:this.#Kn.getEnvironment()??"",baseURL:this.#Kn.getBaseURL()??"",analyticsBaseURL:this.#Kn.getAnalyticsBaseURL()??"",logLevel:this.#Kn.getConfig()?.logLevel??"none"}:null}async getExperimentState(){return this.#Kn.isConfigured()&&this.#Wn?this.#Wn.getState():null}setLogLevel(e){h.setLogLevel(e)}async revokeEntitlements(){if(!this.#br())return!1;if(!this.#m||!this.#f)return!1;try{return await this.#m.revokeEntitlements(this.#f)}catch(e){return h.error("Failed to revoke entitlements",e),!1}}setUserAttributes(e){this.#br()&&(e&&"object"==typeof e?(this.#Zn={...this.#Zn,...e,custom:{...this.#Zn.custom,...e.custom}},this.#p.set(Tt,this.#Zn),h.debug("User attributes updated",this.#Zn)):h.error("setUserAttributes() requires a valid UserAttributes object"))}getUserAttributes(){return{...this.#Zn}}async show(e,t,n){const{result:r,...i}=await this.#vr(e,t,n);return this.#wr(r,i,t,n),r}async#vr(t,n,i){const o=S(),l=(c=n?.useCase,a(c)?c:"reduceChurn");var c;if(this.#yr(o,l,i),!this.#br()){const n="notConfigured";return t?.onNotGranted?.(n),t?.onError?.({code:e.INITIALIZATION_ERROR,message:"SDK not configured"}),this.#xr("not_configured",o,l,i),{result:{status:"dismissed",reason:n},presentationId:o}}const d=function(t){return void 0===t||r.includes(t)?null:{code:e.INVALID_REQUEST,message:`useCase ${s(t)} is not a recognised Encore use case — nothing was presented. Supported values: ${r.map(e=>`'${e}'`).join(", ")}.`,details:{useCase:t}}}(n?.useCase);if(d){h.error(`[Encore SDK] Integration error: ${d.message}`),this.#mr("configuration",new Error(d.message));const e={type:"error",error:d};return t?.onNotGranted?.(e),t?.onError?.(d),{result:{status:"dismissed",reason:e},presentationId:o}}if(this.#er){h.warn("show() called while already presenting, ignoring duplicate request");const e="alreadyPresenting";return t?.onNotGranted?.(e),this.#xr("already_presenting",o,l,i),{result:{status:"dismissed",reason:e},presentationId:o}}this.#er=!0;try{const e=await this.#Ir(o,n,i),r=e.result;return"claimed"===r.status?t?.onGranted?.(void 0):"dismissed"===r.status&&r.reason&&t?.onNotGranted?.(r.reason),e}catch(n){h.error("Error during show",n),this.#mr("present_offer_initialization",n);const r={type:"error",error:{code:e.UNKNOWN_ERROR,message:n instanceof Error?n.message:"Unknown error"}};return t?.onError?.(r.error),t?.onNotGranted?.(r),{result:{status:"dismissed",reason:r},presentationId:o,override:{notPresentedReason:"error.unknown_error"}}}finally{this.#er=!1}}#yr(e,t,n){var r;this.#Xn&&this.#f&&this.#Xn.enqueue({name:"sdk_show_entered",distinctId:this.#f,properties:{layer:"web",presentationId:(r={presentationId:e,useCase:t,...void 0!==n&&{placementId:n}}).presentationId,use_case:i(r.useCase),...I(r.placementId)}},S())}#xr(e,t,n,r,o){var s;this.#Xn&&this.#f&&this.#Xn.enqueue({name:"sdk_show_aborted",distinctId:this.#f,properties:{layer:"web",reason:(s={reason:e,presentationId:t,useCase:n,...void 0!==r&&{placementId:r},...void 0!==o&&{variantId:o}}).reason,presentationId:s.presentationId,use_case:i(s.useCase),...I(s.placementId),...void 0!==s.variantId&&{variantId:s.variantId}}},S())}#wr(e,t,n,r){if(!this.#Xn||!this.#f)return;const o=t.presentationId,s={...void 0!==r&&{placementId:r},presentationId:o,useCase:i(n?.useCase??"reduceChurn"),unlockMode:this.#Kn.getUnlockMode(),...void 0!==t.variantId&&{variantId:t.variantId},...pe(e,t.override)};this.#Xn.enqueue(function(e,t){const{placementId:n,...r}=t,i=v(n);return{name:"sdk_placement_resolved",distinctId:e,properties:{...r,...i&&{placementId:i}}}}(this.#f,s),o)}async presentOffer(e,t){const n=await this.show(e,t);switch(n.status){case"unavailable":return{granted:!1,reason:"noOffersAvailable"};case"dismissed":return{granted:!1,...n.reason&&{reason:n.reason}};case"claimed":return{granted:!0}}}async redeem(t){if(!this.#br())return{status:"dismissed",reason:{type:"error",error:{code:e.INITIALIZATION_ERROR,message:"SDK not configured"}}};const n=this.#Cr(t?.placement);if(n&&"rewardUsers"!==n.transaction.useCase&&!t?.host?.name&&await this.#kr(),!n)return h.info("redeem(): nothing pending to redeem"),{status:"unavailable"};const{transaction:r,store:i}=n;let o=null;try{this.#Jn||(He({}),this.#Jn=!0),o=new Ke;const n=o;return await new Promise(o=>{let s=!1;const a=e=>{s||(s=!0,o(e))};n.on("close",()=>a({status:"dismissed"})),n.on("backdropClick",()=>{n.hide(),a({status:"dismissed"})}),n.on("hide",()=>a({status:"dismissed"})),n.show(),this.#Er(n,r,t?.host,()=>{const t=this.#$r(),o=this.#Sr(r.useCase),s=r.useCase??"reduceChurn";if(this.#Ar(e=>$(e,{...o&&{variantId:o},actionType:"claimOffer",presentationId:r.id,currentState:"redemption",useCase:s})),!this.#Tr(r.offer,r.id,s,t,{campaignId:r.offer.campaignId,...r.offer.advertiserName&&{advertiserName:r.offer.advertiserName},...o&&{variantId:o},useCase:s}))return a({status:"dismissed",reason:{type:"error",error:{code:e.UNKNOWN_ERROR,message:"The advertiser could not be opened (the browser blocked the popup). The claim is still pending — call redeem() again from a user gesture."}}}),void n.hide();i.markRedeemed(r.id),a({status:"redeemed"}),n.hide()})})}catch(t){return h.error("Error during redeem",t),this.#mr("present_offer_initialization",t),{status:"dismissed",reason:{type:"error",error:{code:e.UNKNOWN_ERROR,message:t instanceof Error?t.message:"Unknown error"}}}}finally{o?.destroy()}}getPendingTransaction(e){return this.#br()?this.#Cr(e)?.transaction??null:null}isActive(e,t){return h.error("isActive() has been removed. Entitlement validation must be done server-side. See: https://docs.encorekit.com/server-side-validation"),!1}didGrant(e,t){this.#br()&&(this.#qn?t&&"string"==typeof t?this.#qn.sendGrantSignal(t,e):h.error("didGrant() requires a valid transaction ID"):h.error("SignalManager not initialized"))}async waitForVerification(e,t){if(!this.#br())return h.error("SDK not configured"),"failed";if(!this.#m)return h.error("API client not initialized"),"failed";if(!e)return h.error("waitForVerification() requires a transaction ID"),"failed";try{h.debug("Starting verification wait",{transactionId:e,timeout:t});const n={transactionId:e};void 0!==t&&(n.timeout=t);const r=new U(this.#m,n);return await r.poll()}catch(t){return h.error("Error during verification wait",{transactionId:e,error:t}),"failed"}}on(e,t){return h.error("on() event listener has been removed. Entitlement validation must be done server-side. See: https://docs.encorekit.com/server-side-validation"),()=>{}}observeEntitlement(e,t){return h.error("observeEntitlement() has been removed. Entitlement validation must be done server-side. See: https://docs.encorekit.com/server-side-validation"),{subscribe:e=>()=>{}}}onStrictUnlockVerified(e){return this.#Ue.on("strictUnlockVerified",e)}placement(e,t){let n,r,i;return"string"==typeof e?(n=e,r=e,i=t):(n=`placement_${S().slice(0,8)}`,i=e),new _(n,async e=>this.show(void 0,e,r),i,async()=>this.redeem(r?{placement:r}:void 0))}#mr(t,n){if(!this.#m)return;const r=n instanceof Error?n.message:String(n),i=n instanceof Error?n.stack:void 0,o=N(n),s=function(t){if("object"!=typeof t||null===t)return{};const n=t,r=R(n,"code"),i=n.statusCode;return{...r&&r!==String(e.API_ERROR)?{serverCode:r}:{},..."number"==typeof i?{statusCode:String(i)}:{}}}(n);this.#m.reportError({errorType:o,message:r,context:t,severity:"error",...i&&{stackTrace:i},...this.#f&&{userId:this.#f},...Object.keys(s).length>0&&{metadata:s}}).catch(()=>{}),this.#k&&this.#f&&this.#k.track(function(e,t,n,r){return{name:"sdk_error",distinctId:e,properties:{errorType:t,errorDescription:n,...r&&{context:r}}}}(this.#f,o,r,t))}async#Rr(e,t,n){if("reduceChurn"!==t)return null;const r=this.#Wn?await this.#Wn.getCohort():"notEnrolled";return this.#Wn?.logExposure(r),"control"!==r?null:(this.#k&&this.#f&&this.#k.track(C(this.#f,"experiment_control",e,this.#nr,t,n)),this.#xr("experiment_control",e,t,n,this.#Sr(t)),h.debug("NCL control cohort — ghost trigger, no UI shown"),{result:{status:"unavailable"},override:{notPresentedReason:"experiment_control"}})}#Nr(e){if(e.ui?.values?.text){const t=e.ui.values.text;this.#tr={...t},h.debug("Remote config loaded",t)}this.#nr=e.ui?.variantId??void 0,this.#ir=e.ui?.values,this.#rr={...e.ui?.values?.text?.appName&&{appName:e.ui.values.text.appName},...e.ui?.values?.media?.appstoreIcon&&{appIconUrl:e.ui.values.media.appstoreIcon},...e.entitlements?.native&&{entitlementValue:e.entitlements.native.value,entitlementUnit:e.entitlements.native.unit,trialDurationDays:e.entitlements.native.durationDays}};const t=e.useCases??{},n={};for(const[e,r]of Object.entries(t)){const t=o(e);t&&(n[t]=r)}const r={};for(const e of Object.keys(this.#sr)){const t=this.#or[e];t&&(r[e]=t)}this.#or={...n,...r},this.#Wn?.setConfig(e.experiments?.ncl)}#Ur(e){if(this.#ar.has(e))return null;const t=this.#or[e];return t&&Nt(t)?{variantId:t.variantId??void 0,values:t.values}:null}async#Lr(e){this.#cr||this.#fr(),await this.#kr();return this.#Ur(e)||(await this.#Or(e),this.#Ur(e))}#Or(e){const t=this.#sr[e];if(t)return t;if(!this.#m||!this.#f)return Promise.resolve();this.#_r(e);const n=this.#f,r=this.#m.fetchConfig(n,W,e).then(t=>{if(this.#f!==n)return;const r=t.ui,o=r?.useCase===i(e),s=r?.values;o&&Nt({values:s})?(this.#ar.delete(e),this.#or[e]={variantId:r.variantId??null,variantName:r.variantName??null,template:r.template??null,values:s}):(this.#ar.add(e),delete this.#or[e])}).catch(t=>{h.warn(`Failed to fetch config for use case '${e}' (non-blocking)`,t),delete this.#sr[e]});return this.#sr[e]=r,r}#_r(e){this.#lr.has(e)||(this.#lr.add(e),h.warn(`[INTEGRATION] Use case '${e}' was not prefetched, so it is being fetched on demand — this first presentation will be slower, then it is cached. Nothing has failed. To make it instant, ask Encore to enable '${e}' for this app.`))}#Sr(e){return e&&"reduceChurn"!==e?this.#Ur(e)?.variantId:this.#nr}#fr(){if(!this.#m||!this.#f)return;const e=Date.now(),t=this.#f;this.#cr=this.#m.fetchConfig(t,W).then(n=>{this.#f===t&&(this.#Nr(n),this.#Pr("remote",Date.now()-e))}).catch(t=>{h.warn("Failed to fetch remote config (non-blocking)",t),this.#mr("configuration",t),this.#Pr("fallback",Date.now()-e),this.#cr=null})}#Pr(e,t){var n;this.#k&&this.#f&&this.#k.track({name:"sdk_sdui_config_loaded",distinctId:this.#f,properties:{...(n={...this.#nr&&{variantId:this.#nr},loadSource:e,loadDurationMs:t}).variantId&&{variantId:n.variantId},loadSource:n.loadSource,loadDurationMs:n.loadDurationMs,...n.presentationId&&{presentationId:n.presentationId}}})}async#kr(){if(!this.#cr)return;let e;await Promise.race([this.#cr,new Promise(t=>{e=setTimeout(t,2500)})]),clearTimeout(e)}async#Ir(t,n,r){const i=n?.useCase??"reduceChurn";let o=null;if("reduceChurn"!==i&&(o=await this.#Lr(i),!o))return h.info(`[Encore SDK] No template for use case '${i}' on this app — no-op`),this.#k&&this.#f&&this.#k.track(C(this.#f,"no_template",t,void 0,i,r)),{result:{status:"unavailable"},presentationId:t,override:{notPresentedReason:"use_case_unavailable"}};if(!this.#jn||!this.#m)return h.error("Managers not initialized"),{result:{status:"dismissed",reason:{type:"error",error:{code:e.INITIALIZATION_ERROR,message:"Managers not initialized"}}},presentationId:t};const s={title:b(n?.headline),subtitle:b(n?.subheadline)},a=this.#Sr(i);this.#k&&this.#f&&this.#k.track(function(e,t,n,r,i){return{name:"sdk_offer_presentation_triggered",distinctId:e,properties:{presentationId:t,...n&&{variantId:n},...x(r),...I(i)}}}(this.#f,t,a,i,r));const l=await this.#Rr(t,i,r);if(l)return{...l,presentationId:t,...void 0!==a&&{variantId:a}};const c=[],d=()=>{for(const e of c.splice(0))try{e()}catch{}};try{const l=n?.appearance,u={...l?.accentColor&&{primaryColor:l.accentColor},...l?.backgroundColor&&{backgroundColor:l.backgroundColor},...l?.textColor&&{textColor:l.textColor}};this.#Jn?l&&function(e){const t=document.documentElement,n=De(e);n.primaryColor&&t.style.setProperty("--encore-primary-color",n.primaryColor),n.backgroundColor&&t.style.setProperty("--encore-bg-color",n.backgroundColor),n.textColor&&t.style.setProperty("--encore-text-color",n.textColor),n.borderRadius&&t.style.setProperty("--encore-border-radius",n.borderRadius),n.fontFamily&&t.style.setProperty("--encore-font-family",n.fontFamily),h.debug("Theme variables updated",n)}(u):(He(u),this.#Jn=!0),h.debug("Fetching offers");const p="strict"===this.#Kn.getUnlockMode(),{offers:m}=await this.#jn.fetchOffers(this.#Zn,!0,r,p?15e3:void 0);if(0===m.length)return h.info("No offers available"),this.#k&&this.#f&&this.#k.track(C(this.#f,"no_offer_available",t,a,i,r)),{result:{status:"unavailable"},presentationId:t,...void 0!==a&&{variantId:a},override:{notPresentedReason:"no_offer_available"}};const f={...this.#tr,...s.title&&{titleText:s.title,customHeadline:s.title},...s.subtitle&&{subtitleText:s.subtitle,customSubheadline:s.subtitle}};this.#jn.beginPresentation(a,i,r,t);const g=new Map;m.forEach(e=>{g.set(e.id,S())});const v=e=>{let t=g.get(e);return t||(t=S(),g.set(e,t)),t};this.#k&&this.#f&&this.#k.track(function(e,t,n,r,i,o){return{name:"sdk_offer_presentation_success",distinctId:e,properties:{presentationId:t,offerCount:n,...r&&{variantId:r},...x(i),...I(o)}}}(this.#f,t,m.length,a,i,r));const w=e=>({campaignId:e.campaignId,...e.creativeId&&{creativeId:e.creativeId},...null!=e.merchantName&&{advertiserName:e.merchantName},impressionId:v(e.id),offerIndex:m.indexOf(e),totalOffers:m.length,presentationId:t,...a&&{variantId:a},...i&&{useCase:i},...r&&{placementId:r}}),y=new Ke({},{showCloseButton:"rewardUsers"!==i,...!1===n?.dismissible&&{dismissible:!1},...l?.modalBackgroundColor&&{backgroundColor:l.modalBackgroundColor}}),k={rewardActions:null,confetti:null},A=new Xe(m,f,"rewardUsers"===i?{mode:"paged",hideHeader:!0,selectable:!0,claimEnabled:this.#gt,...l?.dotColor&&{dotColor:l.dotColor},...l?.dotActiveColor&&{dotActiveColor:l.dotActiveColor}}:{claimEnabled:this.#gt});c.push(()=>y.destroy()),c.push(()=>A.destroy()),c.push(()=>k.rewardActions?.destroy()),c.push(()=>k.confetti?.destroy());const T=await new Promise(c=>{let d=!1;const u=(e,n)=>{d||(d=!0,c({result:e,presentationId:t,...void 0!==a&&{variantId:a},...n&&{override:n}}))};let p=null,f="carousel";A.on("offerClaim",n=>{const o=n.offer;h.debug("User claimed offer",{offerId:o.id});const s=w(o);this.#Ar(e=>function(e,t){return{name:"sdk_offer_claim_tapped",distinctId:e,properties:E(t)}}(e,s)),this.#Ar(e=>$(e,{...a&&{variantId:a},actionType:"claimOffer",presentationId:t,currentState:"carousel",useCase:i,...r&&{placementId:r}}));const l=this.#Mr(i),c=P(l)?null:this.#$r();(async()=>{try{const e=v(o.id),t=m.indexOf(o),n=await this.#Dr(o,e,t,m.length,i),a=this.#zr(o,n);if(p=a,P(l)){const e=this.#Fr(l,o,n,i,r,o.perk);return this.#jn?.endPresentation(void 0,i),f="primer",void this.#Br(y,e,()=>{u(a),y.hide()})}this.#Tr(o,n,i,c,s),this.#jn?.endPresentation(void 0,i),y.hide(),u(a)}catch(t){h.error("Error creating transaction",{offerId:o.id,error:t}),this.#mr("start_transaction",t),p||this.#Ar(e=>function(e,t,n){return{name:"sdk_offer_claim_failed",distinctId:e,properties:{...E(t),reason:n.reason,...n.errorDescription&&{errorDescription:n.errorDescription},...n.transactionId&&{transactionId:n.transactionId}}}}(e,s,{reason:this.#jn?"transaction_start_failed":"manager_unavailable",errorDescription:t instanceof Error?t.message:"Transaction failed"})),this.#Hr(c),this.#jn?.endPresentation("error",i),y.hide(),p?u(p):u({status:"dismissed",reason:{type:"error",error:{code:e.UNKNOWN_ERROR,message:t instanceof Error?t.message:"Transaction failed"}}},{advertiserOutcome:"failed",dismissal:"interrupted"})}})()}),A.on("complete",e=>{e.claimed||(h.debug("User declined last offer"),this.#jn?.endPresentation("userDeclinedLastOffer",i),A.destroy(),y.hide(),u({status:"dismissed",reason:"userDeclinedLastOffer"}))});const g=()=>{if(this.#Ar(e=>$(e,{...a&&{variantId:a},actionType:"close",presentationId:t,currentState:f,useCase:i,...r&&{placementId:r}})),p)return A.destroy(),void u(p);h.debug("User closed modal"),this.#jn?.endPresentation("userClosedModal",i),A.destroy(),u({status:"dismissed",reason:"userClosedModal"})};if(y.on("close",g),y.on("backdropClick",()=>{if(p)return A.destroy(),y.hide(),void u(p);h.debug("User clicked outside modal"),this.#jn?.endPresentation("userClickedOutside",i),A.destroy(),y.hide(),u({status:"dismissed",reason:"userClickedOutside"})}),A.on("offerView",e=>{const{offer:t}=e,n=v(t.id),r=m.indexOf(t);this.#jn&&this.#jn.trackOfferPresented(t,n,r,m.length,i)}),A.on("scroll",e=>{this.#Ar(n=>function(e,t){return{name:"sdk_sdui_scroll",distinctId:e,properties:{...t.variantId&&{variantId:t.variantId},scrollAxis:t.scrollAxis,scrollPosition:t.scrollPosition,presentationId:t.presentationId,...x(t.useCase),...I(t.placementId)}}}(n,{...a&&{variantId:a},scrollAxis:e.axis,scrollPosition:e.position,presentationId:t,useCase:i,...r&&{placementId:r}}))}),y.on("hide",()=>{u(p||{status:"dismissed",reason:"userClosedModal"})}),"rewardUsers"===i){const e=new Ct({onClaim:()=>A.claimSelected(),onDecline:()=>{g(),y.hide()},claimEnabled:this.#gt,useCase:i,...!1===n?.dismissible&&{secondary:A.getTotalOffers()>1?"next":"none",onNext:()=>A.getCurrentIndex()>=A.getTotalOffers()-1?A.selectOffer(0):A.next()},...l?.claimButton&&{claimSlot:l.claimButton},...l?.declineButton&&{declineSlot:l.declineButton}});k.rewardActions=e,A.on("offerSelect",t=>{e.setSelectedOffer(t.offer.merchantName)})}y.show();const C=A.render();let S;if("rewardUsers"===i&&o){const e=o.values?.text,t=b(gt(l?.headline),s.title,e?.rewardHeadline)??"Congrats! You’ve unlocked an exclusive gift",r=b(gt(l?.subheadline),s.subtitle,e?.rewardSubheadline)??"Choose one of our partner offers below";S=function(e,t={}){const{title:n,subtitle:r,statusIcon:i="none",actions:o,headlineSlot:s,subheadlineSlot:a,useCase:l="rewardUsers"}=t,c=document.createElement("div");c.className=`${Ve("thankyou")} ${Ve("thankyou--reward")}`;const d=document.createElement("div");if(d.className=Ve("thankyou-status"),"success"===i){const e=document.createElement("span");e.className=Ve("thankyou-check"),e.setAttribute("aria-hidden","true"),e.innerHTML='<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><path d="M5 12.5l4.5 4.5L19 7.5" /></svg>',d.appendChild(e)}if(n){const e=document.createElement("h2");e.className=Ve("thankyou-title"),e.id=xt,e.textContent=n,d.appendChild(ft(e,n,l,s))}else h.warn("Reward layout rendered without a headline — the dialog has no accessible name");if(r||a){const e=document.createElement("p");e.className=Ve("thankyou-subtitle"),e.textContent=r??"";const t=ft(e,r??"",l,a);(t.textContent?.trim()||t.childElementCount>0)&&d.appendChild(t)}return c.appendChild(d),c.appendChild(e),o&&c.appendChild(o),c}(C,{title:t,...r&&{subtitle:r},...n?.statusIcon&&{statusIcon:n.statusIcon},...k.rewardActions&&{actions:k.rewardActions.render()},useCase:i,...l?.headline&&{headlineSlot:l.headline},...l?.subheadline&&{subheadlineSlot:l.subheadline}}),y.setLabelledBy(xt)}else S=C;if(y.setContent(S),"rewardUsers"===i){const e=new $t;k.confetti=e;const t=S;requestAnimationFrame(()=>e.start(t))}});return d(),T}catch(n){return h.error("Error in offer flow",n),this.#mr("present_offer_initialization",n),d(),{result:{status:"dismissed",reason:{type:"error",error:{code:e.UNKNOWN_ERROR,message:n instanceof Error?n.message:"Unknown error"}}},presentationId:t,...void 0!==a&&{variantId:a},override:{advertiserOutcome:"not_attempted",dismissal:"interrupted"}}}}#zr(e,t){return t||h.warn("[Encore SDK] Claim resolved WITHOUT a transactionId — this conversion cannot be traced back to the user or app. The claim itself succeeded; the transaction record did not."),{status:"claimed",offerId:e.id,campaignId:e.campaignId,advertiserName:e.merchantName??"",...t&&{transactionId:t}}}async#Dr(e,t,n,r,i){if(!this.#jn)throw new Error("OfferManager not initialized");const o=await this.#jn.startTransaction(e.campaignId,i),s=this.#jn.placementId;return this.#Qn?.notePending(o,{grantsEntitlement:Ut(i),...void 0!==i&&{useCase:i},...void 0!==s&&{placementId:s}}),this.#jn.trackOfferClaimed(e,t,o,n,r,i),h.debug("Transaction created",{transactionId:o}),o}#Tr(e,t,n,r,i){const o=this.#Vr(e.advertiserUrl,e.trackingParameters,t),s=this.#Kr(o);i&&this.#Ar(e=>function(e,t,n){return{name:"sdk_offer_webview_attempting_open",distinctId:e,properties:{...E(t),url:n.url,urlHost:n.urlHost}}}(e,i,{url:o,urlHost:s}));const a=this.#qr(r,o);return a||h.warn("Failed to open advertiser URL (popup blocked?)"),i&&(a?(this.#Ar(e=>function(e,t,n){return{name:"sdk_offer_webview_opened",distinctId:e,properties:{...E(t),url:n.url,urlHost:n.urlHost,openedAt:n.openedAt}}}(e,i,{url:o,urlHost:s,openedAt:(new Date).toISOString()})),this.#jr(i,t)):this.#Ar(e=>function(e,t,n){return{name:"sdk_offer_webview_load_failed",distinctId:e,properties:{...E(t),url:n.url,urlHost:n.urlHost,loadSuccess:!1,reason:n.reason}}}(e,i,{url:o,urlHost:s,reason:"popup_blocked"}))),a&&this.#Wr(t,i),Ut(n)&&"strict"!==this.#Kn.getUnlockMode()&&this.didGrant("provisional",t),a}#gr(){this.#Qn&&(this.#Gn?.start(()=>{this.#Gr()}),this.#Gr())}async#Gr(){const e=this.#Qn;if(!e||this.#er)return;const t=e.getPending();if(t&&!this.#Yn.has(t.transactionId)){h.debug("Strict unlock: reconciling pending claim",{transactionId:t.transactionId}),this.#Yn.add(t.transactionId);try{"verified"===await e.verify(t.transactionId)&&this.#Qr(t.transactionId)}finally{this.#Yn.delete(t.transactionId)}}}#Wr(e,t){const n=this.#Qn;n&&!this.#Yn.has(e)&&(this.#Yn.add(e),(async()=>{try{const r=await n.verify(e);if("verified"!==r)return void h.debug("Strict unlock: not verified in session, left pending",{transactionId:e,status:r});this.#Qr(e,t)}finally{this.#Yn.delete(e)}})())}#Qr(e,t){const n=this.#Qn?.getPending();n?.transactionId===e?(this.#Qn?.clearPending(),n.grantsEntitlement&&this.didGrant("final",e),this.#Ar(r=>function(e,t,n){return{name:"sdk_offer_verified",distinctId:e,properties:{...n?E(n):{},transactionId:t.transactionId,...x(t.useCase),...I(t.placementId)}}}(r,{transactionId:e,...void 0!==n.useCase&&{useCase:n.useCase},...void 0!==n.placementId&&{placementId:n.placementId}},t)),this.#Ue.emit("strictUnlockVerified",e),h.debug("Strict unlock: claim verified",{transactionId:e})):h.debug("Strict unlock: verification superseded by a newer claim",{transactionId:e})}#Kr(e){try{return new URL(e).hostname}catch{return""}}#jr(e,t){if("undefined"==typeof window||"undefined"==typeof document)return;const n=this.#f;if(this.#k&&n)try{this.#dr?.();const r=Date.now();let i=!1;const o=()=>{window.removeEventListener("focus",s),document.removeEventListener("visibilitychange",s),this.#dr===o&&(this.#dr=null)},s=()=>{if(i||"visible"!==document.visibilityState)return;i=!0,o();const s=(Date.now()-r)/1e3;this.#k?.track(function(e,t,n){return{name:"sdk_offer_claim_returned",distinctId:e,properties:{...E(t),...n.transactionId&&{transactionId:n.transactionId}}}}(n,e,{transactionId:t})),this.#k?.track(function(e,t,n){return{name:"sdk_offer_webview_dismissed",distinctId:e,properties:{...E(t),timeSpentSeconds:n.timeSpentSeconds}}}(n,e,{timeSpentSeconds:s}))};window.addEventListener("focus",s),document.addEventListener("visibilitychange",s),this.#dr=o}catch{}}#Ar(e){const t=this.#f;this.#k&&t&&this.#k.track(e(t))}#Vr(e,t,n){try{const r=new URL(e);t&&Object.entries(t).forEach(([e,t])=>{r.searchParams.append(e,String(t))});let i=r.toString();return i=i.replace(/TRANSACTION_ID/g,n),h.debug("Built final advertiser URL",{original:e,final:i,transactionId:n}),i}catch(t){return h.error("Failed to build advertiser URL",{url:e,error:t}),e.replace(/TRANSACTION_ID/g,n)}}#$r(){try{return window.open("","_blank")}catch(e){return h.error("Failed to open blank advertiser window",{error:e}),null}}#qr(e,t){try{if(e)return e.location.href=t,e.focus(),!0;const n=window.open(t,"_blank","noopener,noreferrer");return!!n&&(n.focus(),!0)}catch(e){return h.error("Failed to navigate advertiser URL",{url:t,error:e}),!1}}#Hr(e){try{e?.close()}catch(e){h.error("Failed to close advertiser window",{error:e})}}#Cr(e){return[this.#hr,this.#ur].map(t=>{const n=e?t.getByPlacement(e):t.getLatest();return n?{transaction:Rt(n),store:t}:null}).filter(e=>null!==e).sort((e,t)=>F(t.transaction)-F(e.transaction))[0]??null}#Mr(e){return function(e,t){return function(e){if(!e||"object"!=typeof e)return;const t=e.claimBehavior;return D.includes(t)?t:void 0}(t)??M[e]}(e,"reduceChurn"===e?this.#ir:this.#or[e]?.values)}#Fr(e,t,n,r,i,o){const s=Date.now(),a={id:n,appAccountId:this.#f??"",...i&&{placementId:i},offer:{id:t.id,campaignId:t.campaignId,advertiserUrl:t.advertiserUrl,...t.trackingParameters&&{trackingParameters:t.trackingParameters},...t.merchantName&&{advertiserName:t.merchantName},...o&&{reward:o},...t.imageUrl&&{imageUrl:t.imageUrl},...t.logoUrl&&{logoUrl:t.logoUrl}},useCase:r,status:"claimed",createdAt:new Date(s).toISOString(),expiresAt:new Date(s+6048e5).toISOString()};return("deferredWhileAlive"===e?this.#ur:this.#hr).save(a),a}#Yr(){return function(e){const t=K(e.appName),n=function(e){const t=K(e.entitlementValue),n=K(e.entitlementUnit);if(!t||!n)return;const r=n.endsWith("s")?n.slice(0,-1):n;return`${t} ${1===Number(t)?r:`${r}s`}`}(e),r=K(e.appIconUrl);return{...t&&{appDisplayName:t},...n&&{trialPeriod:n},...r&&{logoUrl:r}}}(this.#rr)}#Br(e,t,n){const r=this.#Yr();try{const i=new nt({variant:r.appDisplayName?"activation":"holding",display:r,partner:{...t.offer.advertiserName&&{name:t.offer.advertiserName},...t.offer.logoUrl&&{logoUrl:t.offer.logoUrl},...t.offer.imageUrl&&{imageUrl:t.offer.imageUrl}}});i.on("continue",()=>{i.destroy(),n()}),e.setContent(i.render()),h.debug("Primer screen displayed",{transactionId:t.id})}catch(e){h.error("Failed to show the primer screen",e),n()}}#Er(e,t,n,r){try{const{reward:o,advertiserName:s,logoUrl:a,imageUrl:l}=t.offer,c=this.#Yr(),d=n?.name??c.appDisplayName;let u={};if("rewardUsers"!==t.useCase&&d){const e=this.#rr.trialDurationDays,t=e?(i=new Date(Date.now()+24*e*60*60*1e3),`Free until ${new Intl.DateTimeFormat(void 0,{month:"long",day:"numeric",year:"numeric"}).format(i)}`):void 0,r=n?.logoUrl??c.logoUrl;u={host:{name:d,...c.trialPeriod&&{trialPeriod:c.trialPeriod},...n?.status&&{status:n.status},...t&&{detail:t},...r&&{logoUrl:r}}}}const p=new lt({variant:u.host?"activation":"reward",...o&&{reward:o},...s&&{advertiserName:s},...a&&{logoUrl:a},...l&&{imageUrl:l},...u});p.on("continue",()=>{p.destroy(),r()}),e.setContent(p.render()),h.debug("Redemption screen displayed",{transactionId:t.id})}catch(e){h.error("Failed to show redemption screen",e),r()}var i}};exports.Encore=Lt,exports.default=Lt;
|
|
1
|
+
"use strict";var e;Object.defineProperty(exports,"__esModule",{value:!0}),function(e){e.NETWORK_ERROR="NETWORK_ERROR",e.API_ERROR="API_ERROR",e.CONFIGURATION_ERROR="CONFIGURATION_ERROR",e.INITIALIZATION_ERROR="INITIALIZATION_ERROR",e.STORAGE_ERROR="STORAGE_ERROR",e.INVALID_REQUEST="INVALID_REQUEST",e.UNAUTHORIZED="UNAUTHORIZED",e.NOT_FOUND="NOT_FOUND",e.TIMEOUT="TIMEOUT",e.UNKNOWN_ERROR="UNKNOWN_ERROR"}(e||(e={}));const t={reduceChurn:"churn-intervention",rewardUsers:"post-action-reward"},n=Object.fromEntries(Object.entries(t).map(([e,t])=>[t,e])),r=Object.keys(t);function i(e){return t[e]}function o(e){if(e)return n[e]}function s(e){return"string"==typeof e?`'${e.slice(0,64)}'`:typeof e}function a(e){return r.includes(e)}const l=["none","error","warn","info","debug"],c="[Encore SDK]",d=e=>l.indexOf(e),h=new class{#e="none";setLogLevel(e){this.#e=e}getLogLevel(){return this.#e}#t(e){return d(this.#e)>=d(e)}debug(...e){this.#t("debug")&&console.debug(c,...e)}info(...e){this.#t("info")&&console.info(c,...e)}warn(...e){this.#t("warn")&&console.warn(c,...e)}error(...e){this.#t("error")&&console.error(c,...e)}critical(...e){console.error(c,"[CRITICAL]",...e)}};class u{#n=null;#r=!1;configure(e){if(this.#r)return h.warn("SDK already configured. Ignoring subsequent configure() call."),!1;const t=this.#i(e);if(t)return h.error("Invalid configuration:",t),!1;const n=e.logLevel??"none",r=e.environment??"production";return this.#n={apiKey:e.apiKey,environment:r,baseURL:this.#o(r),analyticsBaseURL:this.#s(r),logLevel:n,unlockMode:e.unlockMode??"optimistic"},h.setLogLevel(n),this.#r=!0,h.debug("SDK configured successfully",this.#n),!0}#i(e){return e.apiKey&&"string"==typeof e.apiKey&&""!==e.apiKey.trim()?e.environment&&!["production","development","staging","localhost"].includes(e.environment)?"environment must be 'production', 'development', 'staging', or 'localhost'":e.logLevel&&!l.includes(e.logLevel)?`logLevel must be one of: ${l.join(", ")}`:e.unlockMode&&!["strict","optimistic"].includes(e.unlockMode)?"unlockMode must be 'strict' or 'optimistic'":null:"apiKey is required and must be a non-empty string"}#o(e){switch(e){case"localhost":return"http://localhost:4000/publisher/sdk/v1";case"development":return"https://api.dev.encorekit.com/encore/publisher/sdk/v1";case"staging":return"https://api.staging.encorekit.com/encore/publisher/sdk/v1";default:return"https://api.encorekit.com/encore/publisher/sdk/v1"}}#s(e){switch(e){case"localhost":return"http://localhost:8081/v1";case"development":return"https://api.dev.encorekit.com/analytics/v1";case"staging":return"https://api.staging.encorekit.com/analytics/v1";default:return"https://api.encorekit.com/analytics/v1"}}getConfig(){return this.#n}isConfigured(){return this.#r}getApiKey(){return this.#n?.apiKey??null}getBaseURL(){return this.#n?.baseURL??null}getAnalyticsBaseURL(){return this.#n?.analyticsBaseURL??null}getEnvironment(){return this.#n?.environment??null}getUnlockMode(){return this.#n?.unlockMode??"optimistic"}reset(){this.#n=null,this.#r=!1,h.debug("Configuration reset")}}const p="encore_";class m{#a;#l;constructor(){this.#l=new Map,this.#a=this.#c(),h.debug(`StorageManager initialized with ${this.#a}`)}#c(){return this.#d("localStorage")?"localStorage":this.#d("sessionStorage")?"sessionStorage":(h.warn("Neither localStorage nor sessionStorage available, using in-memory storage"),"memory")}#d(e){try{const t="localStorage"===e?localStorage:sessionStorage,n="__encore_test__";return t.setItem(n,"test"),t.removeItem(n),!0}catch{return!1}}#h(){return"localStorage"===this.#a?localStorage:"sessionStorage"===this.#a?sessionStorage:this.#l}#u(e){return`${p}${e}`}set(e,t){if(void 0===t)return void h.warn(`Attempted to store undefined value for key: ${e}`);const n=this.#u(e),r=JSON.stringify(t);try{const t=this.#h();t instanceof Map?t.set(n,r):t.setItem(n,r),h.debug(`Stored ${e} in ${this.#a}`)}catch(e){e instanceof Error&&"QuotaExceededError"===e.name?h.error("Storage quota exceeded:",e):h.error("Failed to store item:",e),"memory"!==this.#a&&(h.warn("Falling back to memory storage for this item"),this.#l.set(n,r))}}get(e){const t=this.#u(e);try{const n=this.#h();let r=null;return r=n instanceof Map?n.get(t)??null:n.getItem(t),null===r||"undefined"===r?("undefined"===r&&(h.warn(`Found corrupted value "undefined" for key: ${e}, cleaning up`),this.remove(e)),null):JSON.parse(r)}catch(t){return h.error(`Failed to retrieve ${e}:`,t),this.remove(e),null}}remove(e){const t=this.#u(e);try{const n=this.#h();n instanceof Map?n.delete(t):n.removeItem(t),h.debug(`Removed ${e} from ${this.#a}`)}catch(t){h.error(`Failed to remove ${e}:`,t)}}clear(){try{const e=this.#h();if(e instanceof Map)for(const t of e.keys())t.startsWith(p)&&e.delete(t);else{const t=[];for(let n=0;n<e.length;n++){const r=e.key(n);r?.startsWith(p)&&t.push(r)}t.forEach(t=>e.removeItem(t))}h.debug(`Cleared all Encore data from ${this.#a}`)}catch(e){h.error("Failed to clear storage:",e)}}getStorageType(){return this.#a}}const f="signal_queue";class g{#p;#m;#f;#g=[];#b=!1;#v;constructor(e,t,n){this.#p=e,this.#m=t,this.#f=n,this.#w(),this.#y(),this.processQueue()}setUserId(e){this.#f!==e&&(h.debug("SignalManager: User ID changed, clearing queue"),this.#f=e,this.#g=[],this.#w())}#w(){try{const e=`${this.#f}_${f}`,t=this.#p.get(e);t&&Array.isArray(t)&&(this.#g=t,h.debug("Loaded grant signal queue from storage",{count:t.length}))}catch(e){h.error("Failed to load grant signal queue from storage:",e)}}#x(){try{const e=`${this.#f}_${f}`;this.#p.set(e,this.#g),h.debug("Saved grant signal queue to storage",{count:this.#g.length})}catch(e){h.error("Failed to save grant signal queue to storage:",e)}}enqueue(e,t){const n=this.#g.some(n=>n.transactionId===e&&n.grantType===t);if(n)return void h.debug("Grant signal already in queue, skipping",{transactionId:e,grantType:t});const r={transactionId:e,grantType:t,timestamp:(new Date).toISOString(),attempts:0};this.#g.push(r),this.#x(),h.info("Grant signal added to queue",{transactionId:e,grantType:t})}dequeue(e){const t=this.#g.findIndex(t=>t.transactionId===e.transactionId&&t.grantType===e.grantType);-1!==t&&(this.#g.splice(t,1),this.#x(),h.debug("Grant signal removed from queue",{transactionId:e.transactionId,grantType:e.grantType}))}getQueue(){return[...this.#g]}clearQueue(){this.#g=[],this.#x(),h.debug("Grant signal queue cleared")}async sendGrantSignal(e,t){try{if(h.debug("Sending grant signal",{transactionId:e,grantType:t}),!await this.#m.sendGrantSignal(e,t))throw new Error("Grant signal failed (returned false)");h.info("Grant signal sent successfully",{transactionId:e,grantType:t})}catch{h.warn("Failed to send grant signal, adding to queue",{transactionId:e,grantType:t}),this.enqueue(e,t)}}async processQueue(){if(this.#b)h.debug("Queue processing already in progress, skipping");else if(0!==this.#g.length){this.#b=!0,h.info("Processing grant signal queue",{count:this.#g.length});try{for(const e of[...this.#g])await this.#I(e),this.#g.length>1&&await this.#C(100)}finally{this.#b=!1}}}async#I(e){if(e.attempts>=3)return h.error("Grant signal max attempts reached, removing from queue",{transactionId:e.transactionId,grantType:e.grantType,attempts:e.attempts}),void this.dequeue(e);if(e.lastAttemptAt){const t=new Date(e.lastAttemptAt).getTime(),n=Date.now(),r=1e3*Math.pow(2,e.attempts-1),i=n-t;if(i<r)return void h.debug("Skipping signal, waiting for backoff period",{transactionId:e.transactionId,remainingWait:r-i})}e.attempts++,e.lastAttemptAt=(new Date).toISOString(),this.#x();try{h.debug("Attempting to send queued grant signal",{transactionId:e.transactionId,grantType:e.grantType,attempt:e.attempts}),await this.#m.sendGrantSignal(e.transactionId,e.grantType)?(h.info("Queued grant signal sent successfully",{transactionId:e.transactionId,grantType:e.grantType}),this.dequeue(e)):h.warn("Grant signal failed, will retry",{transactionId:e.transactionId,attempt:e.attempts})}catch(t){h.warn("Failed to send queued grant signal, will retry",{transactionId:e.transactionId,attempt:e.attempts,error:t})}}#y(){this.#v=function(e){const t=()=>{h.debug("Network status: online"),e()};return window.addEventListener("online",t),()=>{window.removeEventListener("online",t)}}(()=>{h.debug("Network came online, processing grant signal queue"),this.processQueue()})}destroy(){this.#v&&(this.#v(),this.#v=void 0)}#C(e){return new Promise(t=>setTimeout(t,e))}}function b(...e){for(const t of e){const e=t?.trim();if(e)return e}}function v(e){const t=b(e);return t?.slice(0,64)}const w={userClosedModal:"close_button",userClickedOutside:"dismissed",userDeclinedLastOffer:"last_offer_declined",error:"interrupted",appBackgrounded:"app_backgrounded",appTerminated:"app_terminated"};function y(e){if(null!=e)return w[e]??e}function x(e){return e?{use_case:i(e)}:{}}function I(e){const t=v(e);return t?{placement_id:t}:{}}function C(e,t,n,r,i,o){return{name:"sdk_offer_presentation_failed",distinctId:e,properties:{reason:t,presentationId:n,...r&&{variantId:r},...x(i),...I(o)}}}function k(e,t){const{useCase:n,placementId:r,...i}=t;return{name:"sdk_offer_time_spent",distinctId:e,properties:{...i,...x(n),...I(r)}}}function E(e){const{useCase:t,placementId:n,...r}=e,i={};for(const e in r){const t=r[e];void 0!==t&&(i[e]=t)}return{...i,...x(t),...I(n)}}function $(e,t){return{name:"sdk_sdui_button_tapped",distinctId:e,properties:{...t.variantId&&{variantId:t.variantId},actionType:t.actionType,presentationId:t.presentationId,currentState:t.currentState,...x(t.useCase),...I(t.placementId)}}}function S(){return"undefined"!=typeof crypto&&crypto.randomUUID?crypto.randomUUID():"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,e=>{const t=15&(crypto.getRandomValues(new Uint8Array(1))[0]??0);return("x"===e?t:3&t|8).toString(16)})}class A{#m;#k;#f;#E=[];#$=null;#S=null;#A=null;#T=new Map;#R=0;#N;#U;#L;#O=null;#_=!1;#P=null;constructor(e,t,n){this.#m=e,this.#f=t,this.#k=n??null,this.#M()}async fetchOffers(e,t=!0,n,r){const i=void 0!==r;if(!i&&t&&this.#E.length>0&&this.#$)return h.debug("Using cached offers",{count:this.#E.length}),{offers:[...this.#E]};try{h.debug("Fetching offers from API",{userId:this.#f,maxPostbackTimeMs:r});const t=await this.#m.fetchOffers(this.#f,e,n,r);return 0===t.offers?.length?(h.info("No offers available for user"),i||(this.#E=[],this.#$=Date.now()),{offers:[]}):(i||(this.#E=t.offers,this.#$=Date.now()),h.info("Offers fetched successfully",{count:t.offers.length,offerIds:t.offers.map(e=>e.id)}),{offers:[...t.offers]})}catch(e){throw h.error("Failed to fetch offers",e),e}}beginPresentation(e,t,n,r){return this.#S=r??S(),this.#A=Date.now(),this.#T.clear(),this.#R=0,this.#O=null,this.#N=e,this.#U=t,this.#L=n,this.#_=!1,this.#S}get placementId(){return this.#L}get presentationId(){return this.#S}#D(){return this.#N?{variantId:this.#N}:{}}#z(){return this.#L?{placementId:this.#L}:{}}trackOfferPresented(e,t,n,r,i){if(!this.#k||!this.#S)return;this.#R++,this.#O&&this.#O!==e.id&&this.trackOfferViewEnd(this.#O),this.#O=e.id;const o=this.#T.get(e.id);o?(o.viewCount++,o.startTime=Date.now()):this.#T.set(e.id,{startTime:Date.now(),totalTime:0,viewCount:1,reported:!1}),this.#k.track(function(e,t){const{useCase:n,placementId:r,...i}=t;return{name:"sdk_offer_presented",distinctId:e,properties:{...i,...x(n),...I(r)}}}(this.#f,{campaignId:e.campaignId,creativeId:e.creativeId,...null!=e.merchantName&&{advertiserName:e.merchantName},impressionId:t,offerIndex:n,totalOffers:r,presentationId:this.#S,...this.#D(),...this.#z(),...i&&{useCase:i}}))}trackOfferViewEnd(e){const t=this.#T.get(e);t&&t.startTime>0&&(t.totalTime+=(Date.now()-t.startTime)/1e3,t.startTime=0)}trackOfferClaimed(e,t,n,r,i,o){this.#k&&this.#S&&this.#k.track(function(e,t){const{useCase:n,placementId:r,...i}=t;return{name:"sdk_offer_claimed",distinctId:e,properties:{...i,...x(n),...I(r)}}}(this.#f,{campaignId:e.campaignId,creativeId:e.creativeId,...null!=e.merchantName&&{advertiserName:e.merchantName},impressionId:t,transactionId:n,offerIndex:r,totalOffers:i,presentationId:this.#S,...this.#D(),...this.#z(),...o&&{useCase:o}}))}trackOfferDeclined(e,t,n,r,i,o){if(!this.#k||!this.#S)return;const s=y(i);this.#k.track(function(e,t){const{useCase:n,placementId:r,...i}=t;return{name:"sdk_offer_declined",distinctId:e,properties:{...i,...x(n),...I(r)}}}(this.#f,{campaignId:e.campaignId,creativeId:e.creativeId,...null!=e.merchantName&&{advertiserName:e.merchantName},impressionId:t,offerIndex:n,totalOffers:r,...null!=s&&{declineReason:s},presentationId:this.#S,...this.#D(),...this.#z(),...o&&{useCase:o}}))}endPresentation(e,t){this.#F(e,t,!1),this.#S=null,this.#A=null,this.#T.clear(),this.#R=0,this.#O=null,this.#N=void 0,this.#U=void 0,this.#L=void 0,this.#_=!1}#F(e,t,n,r=!0){if(!this.#k||!this.#S||!this.#A)return;const i=Date.now(),o=(i-this.#A)/1e3,s=n?{keepalive:!0}:void 0;for(const[e,n]of this.#T){let r=n.totalTime;if(n.startTime>0&&(r+=(i-n.startTime)/1e3),n.reported&&r<=0)continue;n.reported=!0;const o=this.#E.find(t=>t.id===e),a=o?this.#E.indexOf(o):0;this.#k.track(k(this.#f,{campaignId:o?.campaignId??"",offerIndex:a,timeSpentSeconds:r,viewCount:n.viewCount,totalOffers:this.#E.length,presentationId:this.#S,...this.#D(),...this.#z(),...t&&{useCase:t}}),s),n.totalTime=0,n.startTime>0&&(n.startTime=i)}if(!r||this.#_)return;this.#_=!0;const a=y(e);this.#k.track(function(e,t){const{useCase:n,placementId:r,...i}=t;return{name:"sdk_offer_sheet_dismissed",distinctId:e,properties:{...i,...x(n),...I(r)}}}(this.#f,{presentationId:this.#S,totalTimeSpentSeconds:o,totalOffers:this.#E.length,offersViewed:this.#R,...null!=a&&{declineReason:a},...this.#D(),...this.#z(),...t&&{useCase:t}}),s)}flushForPageLifecycle(e,t){try{this.#F(e?"appTerminated":"appBackgrounded",t,!0,e)}catch{}}#M(){if("undefined"!=typeof window&&"undefined"!=typeof document)try{const e=()=>this.flushForPageLifecycle(!0,this.#U),t=()=>{"hidden"===document.visibilityState&&this.flushForPageLifecycle(!1,this.#U)};window.addEventListener("pagehide",e),document.addEventListener("visibilitychange",t),this.#P=()=>{window.removeEventListener("pagehide",e),document.removeEventListener("visibilitychange",t)}}catch{}}destroy(){this.#P?.(),this.#P=null}async startTransaction(e,t){try{h.debug("Starting transaction",{campaignId:e,useCase:t});const n=await this.#m.startTransaction(e,this.#f,t);if(!n.transactionId)throw new Error(n.error??"No transactionId in response");return h.info("Transaction started",{transactionId:n.transactionId,campaignId:e}),n.transactionId}catch(t){throw h.error("Failed to start transaction",{campaignId:e,error:t}),t}}clearCache(){this.#E=[],this.#$=null,h.debug("Offer cache cleared")}setUserId(e){this.#f=e,this.clearCache(),h.debug("OfferManager user ID updated",{userId:e})}}const T={[e.NETWORK_ERROR]:"network_error",[e.TIMEOUT]:"network_error",[e.STORAGE_ERROR]:"persistence_error",[e.CONFIGURATION_ERROR]:"not_configured",[e.INITIALIZATION_ERROR]:"not_configured",[e.INVALID_REQUEST]:"api_error",[e.UNKNOWN_ERROR]:"domain_error"};function R(e,t){const n=e[t];return"string"==typeof n?n:void 0}function N(t){if("object"!=typeof t||null===t)return"domain_error";const n=t,r=R(n,"code"),i="number"==typeof n.statusCode;if(r){return T[r]||(r===String(e.API_ERROR)&&i?"http_error":"api_error")}return i?"http_error":t instanceof SyntaxError?"decoding_error":"domain_error"}class U{#m;#B;#H;#V=0;#K=1e3;#q=8e3;#j=null;#W=!1;#G=!1;constructor(e,t){this.#m=e,this.#B=t.transactionId,this.#H=t.timeout??3e4}async poll(){return this.#W?(h.warn("Verification polling already in progress",{transactionId:this.#B}),"pending"):(this.#W=!0,this.#V=Date.now(),h.debug("Starting verification polling",{transactionId:this.#B,timeout:this.#H}),this.#Q())}stop(){this.#W=!1,null!==this.#j&&(clearTimeout(this.#j),this.#j=null),h.debug("Verification polling stopped",{transactionId:this.#B})}async#Q(){for(;this.#W;){const e=Date.now()-this.#V;if(e>=this.#H)return h.warn("Verification polling timeout",{transactionId:this.#B,elapsed:e}),this.stop(),"pending";try{const e=await this.#m.checkVerificationStatus(this.#B);if(h.debug("Verification status checked",{transactionId:this.#B,status:e.status,rawStatus:e.raw}),"verified"===e.status)return h.info("Transaction verified",{transactionId:this.#B}),this.stop(),"verified";if("failed"===e.status)return h.warn("Transaction failed verification",{transactionId:this.#B}),this.stop(),"failed";await this.#C(this.#K),this.#K=Math.min(2*this.#K,this.#q)}catch(e){h.error("Error checking verification status",{transactionId:this.#B,error:e}),this.#G||(this.#G=!0,this.#m.reportError({errorType:N(e),message:e instanceof Error?e.message:String(e),context:"verify_transaction",...e instanceof Error&&e.stack?{stackTrace:e.stack}:{}})),await this.#C(this.#K)}}return"pending"}async#C(e){return new Promise(t=>{this.#j=window.setTimeout(()=>{this.#j=null,t()},e)})}}const L=/^[A-Za-z0-9_-]+$/;class O{#p;#m;#f;constructor(e,t,n){this.#p=e,this.#m=t,this.#f=n}setUserId(e){if(this.#f===e)return;const t=this.getPending();this.clearPending(),this.#f=e,t&&this.#p.set(this.#Y(),t)}notePending(e,t){const n={transactionId:e,recordedAt:(new Date).toISOString(),grantsEntitlement:t?.grantsEntitlement??!1,...void 0!==t?.placementId&&{placementId:t.placementId},...void 0!==t?.useCase&&{useCase:t.useCase}};this.#p.set(this.#Y(),n),h.debug("StrictUnlockReconciler: noted pending claim",{transactionId:e})}clearPending(){this.#p.remove(this.#Y()),h.debug("StrictUnlockReconciler: cleared pending claim")}getPending(){const e=this.#p.get(this.#Y());if(!e)return null;if("string"!=typeof e.transactionId||"string"!=typeof e.recordedAt||!L.test(e.transactionId))return h.warn("StrictUnlockReconciler: dropping malformed pending claim"),this.clearPending(),null;const t=Date.now()-new Date(e.recordedAt).getTime();return!(t>=0)||t>6048e5?(h.debug("StrictUnlockReconciler: dropping stale pending claim",{age:t}),this.clearPending(),null):(void 0!==e.placementId&&"string"!=typeof e.placementId&&delete e.placementId,void 0===e.useCase||a(e.useCase)||(h.warn("StrictUnlockReconciler: dropping an unrecognised use case from a pending claim"),delete e.useCase),e)}async verify(e,t=15e3){try{const n=new U(this.#m,{transactionId:e,timeout:t});return await n.poll()}catch(t){return h.warn("StrictUnlockReconciler: verification poll failed",{transactionId:e,error:t}),"pending"}}#Y(){return`${this.#f}_strict_pending`}}class _{#X=null;#Z=null;#J;#ee;#te;#ne;constructor(e,t,n,r){this.#te=e,this.#J=t,this.#ne=n,this.#ee=r}useCase(e){return this.#ne={...this.#ne,useCase:e},this}headline(e){return this.#ne={...this.#ne,headline:e},this}subheadline(e){return this.#ne={...this.#ne,subheadline:e},this}onNotGranted(e){return this.#X=e,this}onLoadingStateChange(e){return this.#Z=e,this}async show(){try{this.#Z&&this.#Z(!0),h.debug("PlacementBuilder: Executing presentation",{id:this.#te});const e=await this.#J(this.#ne);return this.#Z&&this.#Z(!1),"dismissed"===e.status&&e.reason&&this.#X&&this.#X(e.reason),e}catch(t){this.#Z&&this.#Z(!1),h.error("PlacementBuilder: Error during presentation",t);const n={type:"error",error:{code:e.UNKNOWN_ERROR,message:t instanceof Error?t.message:"Unknown error"}};return this.#X&&this.#X(n),{status:"dismissed",reason:n}}}async redeem(){return h.debug("PlacementBuilder: Redeeming",{id:this.#te}),this.#ee(this.#te)}}function P(e){return"immediate"!==e}const M={reduceChurn:"deferred",rewardUsers:"immediate"},D=["immediate","deferred","deferredWhileAlive"];const z="transactions";function F(e){const t=new Date(e.createdAt).getTime();return Number.isFinite(t)?t:0}function B(e){return"object"==typeof e&&null!==e&&!Array.isArray(e)}function H(e,t){if(!B(e))return{};const n={};for(const[r,i]of Object.entries(e))t(i)&&(n[r]=i);return n}class V{#re;constructor(e){this.#re=e}#ie(){const e=this.#re.read();return B(e)?{transactions:H(e.transactions,B),placements:H(e.placements,e=>"string"==typeof e),latest:"string"==typeof e.latest?e.latest:null}:{transactions:{},placements:{},latest:null}}#oe(e){this.#re.write(e)}#se(e){return!!e&&"claimed"===e.status&&!this.#ae(e)}#ae(e){const t=new Date(e.expiresAt).getTime();return!Number.isFinite(t)||t<=Date.now()}save(e){const t=this.#ie();t.transactions[e.id]=e,e.placementId&&(t.placements[e.placementId]=e.id),t.latest=e.id,this.#le(t),this.#oe(t),h.debug("TransactionStore: saved transaction",{transactionId:e.id,placement:e.placementId})}getByTransactionId(e){return this.#ie().transactions[e]??null}getByPlacement(e){const t=this.#ie(),n=t.placements[e];if(!n)return null;const r=t.transactions[n];return this.#se(r)?r:null}getLatest(){const e=this.#ie();if(e.latest){const t=e.transactions[e.latest];if(this.#se(t))return t}return Object.values(e.transactions).filter(e=>this.#se(e)).sort((e,t)=>F(t)-F(e))[0]??null}markRedeemed(e){const t=this.#ie(),n=t.transactions[e];n&&(n.status="redeemed",n.redeemedAt=(new Date).toISOString(),n.placementId&&t.placements[n.placementId]===e&&delete t.placements[n.placementId],t.latest===e&&(t.latest=null),this.#oe(t),h.debug("TransactionStore: marked redeemed",{transactionId:e}))}#le(e){for(const[t,n]of Object.entries(e.transactions))(this.#ae(n)||"redeemed"===n.status)&&delete e.transactions[t];for(const[t,n]of Object.entries(e.placements))e.transactions[n]||delete e.placements[t];e.latest&&!e.transactions[e.latest]&&(e.latest=null)}clear(){this.#oe({transactions:{},placements:{},latest:null})}}const K=e=>{const t=e?.trim();if(void 0!==t&&t.length>0)return t};const q=e=>`All ${e} features are now unlocked.`;function j(e,t){let n=e;for(const[e,r]of Object.entries(t))n=n.replace(`:${e}`,encodeURIComponent(r));return n}const W="2.0.7";function G(e,t){return e.length<=t?e:e.slice(0,t-15)+"... [truncated]"}function Q(e,t,n){return G(""===e.trim()?n:e,t)}function Y(e,t){return Object.assign(e,{code:t})}class X{#ce;#de;#he;constructor(e,t){this.#ce=e,this.#de=t,this.#he=new Map}setApiKey(e){this.#ce=e}setBaseURL(e){this.#de=e}async get(e,t){return this.#ue({url:`${this.#de}${e}`,options:{method:"GET",...t},apiKey:this.#ce})}async post(e,t,n){return this.#ue({url:`${this.#de}${e}`,options:{method:"POST",body:t,...n},apiKey:this.#ce})}async patch(e,t,n){return this.#ue({url:`${this.#de}${e}`,options:{method:"PATCH",body:t,...n},apiKey:this.#ce})}async#ue(e){const{url:t,options:n,apiKey:r}=e,i=this.#pe(t,n),o=this.#he.get(i);if(o)return h.debug("Deduplicating request:",t),o;const s=this.#me(t,n,r);this.#he.set(i,s);try{return await s}finally{this.#he.delete(i)}}async#me(e,t,n){const r=t.retries??3;let i=null;for(let o=0;o<=r;o++)try{if(o>0){const e=1e3*Math.pow(2,o-1);h.debug(`Retrying request (attempt ${o}/${r}) after ${e}ms`),await this.#C(e)}return await this.#fe(e,t,n)}catch(e){if(i=e,this.#ge(e))throw e;if(o===r)throw h.error(`Request failed after ${r} retries:`,e),e;h.warn("Request failed, will retry:",e)}throw i??new Error("Request failed")}async#fe(t,n,r){const i=n.timeout??3e4,o=new AbortController,s=setTimeout(()=>o.abort(),i);try{const e={"X-API-Key":r,"X-Platform":"web","Content-Type":"application/json","User-Agent":`Encore-Web-SDK/${W}`,...n.headers},i={method:n.method,headers:e,signal:o.signal};n.body&&(i.body=JSON.stringify(n.body)),h.debug(`${n.method} ${t}`);const s=await fetch(t,i);return s.ok||await this.#be(s),await s.json()}catch(t){if(t instanceof Error){if("AbortError"===t.name)throw Y(new Error("Request timeout"),e.TIMEOUT);if(this.#ve(t))throw Y(new Error(`Network error: ${t.message}`),e.NETWORK_ERROR)}if(t instanceof Error)throw t;throw Y(new Error(String(t)),e.UNKNOWN_ERROR)}finally{clearTimeout(s)}}async#be(t){let n,r=`HTTP ${t.status}: ${t.statusText}`;try{const e=await t.json();"object"==typeof e&&null!==e&&"string"==typeof e.error&&(r=e.error,n="string"==typeof e.code?e.code:void 0)}catch{}const i=n?{code:n,message:r}:{code:e.API_ERROR,statusCode:t.status,message:r},o=new Error(r);throw Object.assign(o,i),o}#ge(e){if("object"==typeof e&&null!==e&&"statusCode"in e&&void 0!==e.statusCode){const t=e.statusCode;return t>=400&&t<500}return!1}#ve(e){return e.message.includes("fetch")||e.message.includes("network")||e.message.includes("ECONNREFUSED")||e.message.includes("ETIMEDOUT")}#pe(e,t){const n=t.body?JSON.stringify(t.body):"";return`${t.method}:${e}:${n}`}#C(e){return new Promise(t=>setTimeout(t,e))}#we(e){switch(e){case"pending_conversion":case"provisional_granted":default:return"pending";case"verified":case"final_granted":return"verified";case"expired":case"failed":return"failed"}}async fetchOffers(e,t,n,r){try{const i=v(n),o=await this.post("/offers/search",{userId:e,attributes:t,platform:"web",sdkVersion:W,...i&&{placementId:i},...void 0!==r&&{maxPostbackTimeMs:r}}),s=[];for(const e of o.offers){const t=e.creatives??[];for(const n of t){const t={id:n.id,title:n.title,description:n.quickInstructions??n.subtitle??n.description??"",imageUrl:n.primaryImageUrl,ctaText:n.ctaText,advertiserUrl:n.destinationUrl??e.destinationUrl??"",campaignId:e.id,creativeId:n.id,quickInstructions:n.quickInstructions??"",instructions:(n.instructions??[]).map(e=>({title:e.title,subtitle:e.subtitle,...null!=e.ctaButtonText&&{ctaButtonText:e.ctaButtonText}})),tooltipText:n.tooltipText??"",...e.organization?.name&&{merchantName:e.organization.name},...e.perk&&{perk:e.perk},...n.logoUrl&&{logoUrl:n.logoUrl},...n.trackingParameters&&{trackingParameters:Object.fromEntries(Object.entries(n.trackingParameters).filter(([,e])=>"string"==typeof e||"number"==typeof e||"boolean"==typeof e).map(([e,t])=>[e,String(t)]))}};s.push(t)}}return{offers:s}}catch(e){throw h.error("Failed to fetch offers:",e),e}}async startTransaction(e,t,n){try{return await this.post("/transactions",{campaignId:e,userId:t,...n&&"reduceChurn"!==n&&{useCase:i(n)}})}catch(e){throw h.error("Failed to start transaction:",e),e}}async sendGrantSignal(e,t){try{const n=function(e){return j("/transactions/:transactionId/signals",{transactionId:e})}(e);return(await this.post(n,{grantType:t})).success}catch(e){throw h.error("Failed to send grant signal:",e),e}}async fetchEntitlements(e){try{const t=await this.get(`/entitlements?userId=${encodeURIComponent(e)}`),n=[],r=[{details:t.provisional,scope:"provisional"},{details:t.verified,scope:"verified"}];for(const{details:e,scope:t}of r)if(e){if(e.freeTrial&&n.push({type:"freeTrial",transactionId:"",scope:t,grantedAt:e.freeTrial.startedAt??"",expiresAt:e.freeTrial.expiresAt??""}),e.discounts)for(const r of e.discounts)n.push({type:"discount",value:r.value,unit:r.unit,transactionId:"",scope:t,grantedAt:"",expiresAt:r.expiresAt??""});e.credits&&n.push({type:"credit",value:e.credits.totalAmount,unit:"dollars",transactionId:"",scope:t,grantedAt:"",expiresAt:e.credits.expiresAt??""})}return h.debug("Transformed entitlements response",{totalCount:n.length}),n}catch(e){throw h.error("Failed to fetch entitlements:",e),e}}async checkVerificationStatus(e){try{const t=function(e){return j("/transactions/:transactionId/status",{transactionId:e})}(e),n=await this.get(t);return{status:this.#we(n.status),raw:n.status}}catch(e){throw h.error("Failed to check verification status:",e),e}}async initUser(e,t){try{return await this.post("/users",{userId:e,...t&&{attributes:t}})}catch(e){throw h.error("Failed to init user:",e),e}}async identifyUser(e,t,n){try{return await this.patch("/users/identify",{currentUserId:e,newUserId:t,...n&&{attributes:n}})}catch(e){throw h.error("Failed to identify user:",e),e}}async fetchConfig(e,t,n){try{const r=`/config?userId=${encodeURIComponent(e)}&sdkVersion=${encodeURIComponent(t)}`+(n&&"reduceChurn"!==n?`&useCase=${encodeURIComponent(i(n))}`:"");return await this.get(r)}catch(e){throw h.error("Failed to fetch config:",e),e}}async reportError(e){try{const n="undefined"!=typeof window?window.location.hostname:"unknown";await this.post("/errors",{errorType:G(e.errorType,100),message:Q(e.message,2e3,"Unknown error"),context:G(e.context,200),severity:e.severity??"error",timestamp:(new Date).toISOString(),platform:"web",sdkVersion:W,appBundleId:Q(n,200,"unknown"),...e.stackTrace&&{stackTrace:G(e.stackTrace,1e4)},...e.userId&&{userId:G(e.userId,200)},...e.metadata&&{metadata:(t=e.metadata,Object.fromEntries(Object.entries(t).map(([e,t])=>[e,G(t,500)])))}},{retries:0})}catch(e){h.error("Failed to report error (non-blocking):",e)}var t}async revokeEntitlements(e){try{return(await this.post("/entitlements/revoke",{userId:e})).success}catch(e){throw h.error("Failed to revoke entitlements:",e),e}}}function Z(e){return e.replace(/([a-z0-9])([A-Z])/g,"$1_$2").toLowerCase()}function J(e){const t={};for(const[n,r]of Object.entries(e))t[Z(n)]=r;return t}function ee(e,t=S()){const n="undefined"!=typeof window?window.location.hostname:"unknown";return{event_id:t,event_name:e.name,event_timestamp:(new Date).toISOString(),distinct_id:e.distinctId,properties:{...J(e.properties),platform:"web",sdk_version:W,app_bundle_id:n}}}function te(e,t,n,r){return fetch(`${e}/events`,{method:"POST",...r?.keepalive&&{keepalive:!0},headers:{"X-Analytics-Key":t,"X-Platform":"web","Content-Type":"application/json"},body:JSON.stringify(n)})}const ne=new Set(["user_identified"]);class re{#ce;#ye;#p;constructor(e,t,n){this.#ce=e,this.#ye=t,this.#p=n??null}track(e,t){try{if(this.#xe(e))return;const n=ee(e);te(this.#ye,this.#ce,n,t).catch(t=>{h.warn("Analytics event dispatch failed",{eventName:e.name,error:t})})}catch{}}#xe(e){if(!this.#p||!ne.has(e.name))return!1;const t=`analytics_dedup_${e.name}_${e.distinctId}`;try{const e=this.#p.get(t),n=Date.now();return"number"==typeof e&&n-e<864e5||(this.#p.set(t,n),!1)}catch{return!1}}}async function ie(e,t){const n=`${e}:${t}`,r=(new TextEncoder).encode(n),i=new Uint8Array(await crypto.subtle.digest("SHA-256",r));let o=0n;for(let e=0;e<8;e++)o=o<<8n|BigInt(i[e]??0);return Number(o%100n)}const oe="ncl_assignment",se="ncl_exposure_marker";class ae{#p;#Ie;#Ce;#n=null;constructor(e,t,n){this.#p=e,this.#Ie=t,this.#Ce=n}setConfig(e){this.#n=e??null}async getCohort(){try{return await this.#ke()}catch(e){return h.warn("[Experiment] getCohort failed — treating as notEnrolled",e),"notEnrolled"}}async#ke(){const e=this.#Ie();if(!e)return"notEnrolled";const t=this.#n;if(!t?.enabled)return"notEnrolled";const n=this.#p.get(oe);if(n?.appAccountId===e&&n?.assignmentVersion===t.assignmentVersion)return n.cohort;if("undefined"==typeof crypto||!crypto.subtle)return h.warn("[Experiment] NCL disabled — crypto.subtle unavailable (page is not a secure context: serve over HTTPS)"),"notEnrolled";const r=await ie(e,t.assignmentVersion),i=function(e,t){return e<t?"treatment":"control"}(r,t.rolloutPct);return this.#p.set(oe,{cohort:i,appAccountId:e,assignmentVersion:t.assignmentVersion}),h.debug("[Experiment] Assigned NCL cohort",{cohort:i,version:t.assignmentVersion,rolloutPct:t.rolloutPct,bucket:r}),i}logExposure(e){if("notEnrolled"===e)return;const t=this.#n,n=this.#Ie();if(!t||!n)return;const r=`${n}:${t.assignmentVersion}`;if(this.#p.get(se)===r)return;const i=function(e,t){return{name:"sdk_experiment_exposure",distinctId:e,properties:{experiment:t.experiment,cohort:t.cohort,assignment_version:t.assignmentVersion,app_account_id:e}}}(n,{experiment:"ncl",cohort:e,assignmentVersion:t.assignmentVersion}),o=S();this.#Ce.enqueue(i,o)&&this.#p.set(se,r)}async getState(){const e=this.#Ie(),t=this.#n,n=await this.getCohort();let r=null;if(e&&t?.enabled&&"undefined"!=typeof crypto&&crypto.subtle)try{r=await ie(e,t.assignmentVersion)}catch{r=null}const i=!!e&&!!t&&this.#p.get(se)===`${e}:${t.assignmentVersion}`;return{experiment:"ncl",enabled:t?.enabled??!1,rolloutPct:t?.rolloutPct??null,assignmentVersion:t?.assignmentVersion??null,appAccountId:e,bucket:r,cohort:n,exposureLogged:i}}}class le{#ce;#ye;#p;#Ee;#$e=new Set;constructor(e,t,n,r){this.#ce=e,this.#ye=t,this.#p=n,this.#Ee=r,this.#M()}enqueue(e,t){const n=ee(e,t),r=this.#Se();r.some(e=>e.event_id===t)||(r.push(n),this.#Ae(r));const i=this.#Se().some(e=>e.event_id===t);return this.#Te(n),i}flush(){for(const e of this.#Se())this.#Te(e)}async#Te(e){if(!this.#$e.has(e.event_id)){this.#$e.add(e.event_id);try{const t=await te(this.#ye,this.#ce,e,{keepalive:!0});t.ok?this.#Re(e.event_id):h.warn("Reliable delivery non-OK, will retry",{status:t.status})}catch(e){h.warn("Reliable delivery failed, will retry",{error:e})}finally{this.#$e.delete(e.event_id)}}}#Re(e){const t=this.#Se().filter(t=>t.event_id!==e);this.#Ae(t)}#Se(){return this.#p.get(this.#Ee)??[]}#Ae(e){this.#p.set(this.#Ee,e)}#M(){"undefined"!=typeof window&&"undefined"!=typeof document&&(window.addEventListener("pagehide",()=>this.flush()),document.addEventListener("visibilitychange",()=>{"hidden"===document.visibilityState&&this.flush()}))}}class ce extends le{constructor(e,t,n){super(e,t,n,"ncl_exposure_outbox")}}class de extends le{constructor(e,t,n){super(e,t,n,"diagnostics_outbox")}}const he={userClosedModal:"close_button",userClickedOutside:"dismissed",userDeclinedLastOffer:"last_offer_declined"},ue={advertiserOutcome:"not_attempted",publisherOutcome:"not_attempted",dismissal:"dismissed"};function pe(e,t){if("claimed"===e.status)return{resolution:"presented",...ue,advertiserOutcome:t?.advertiserOutcome??"claimed",dismissal:t?.dismissal??"flow_completed",campaignId:e.campaignId,offerId:e.offerId,...void 0!==e.transactionId&&{transactionId:e.transactionId}};if("unavailable"===e.status)return{resolution:"not_presented",notPresentedReason:t?.notPresentedReason??"error.unknown_error"};const n=e.reason;return t?void 0!==t.notPresentedReason?{resolution:"not_presented",notPresentedReason:t.notPresentedReason}:{resolution:"presented",...ue,...void 0!==t.advertiserOutcome&&{advertiserOutcome:t.advertiserOutcome},...void 0!==t.dismissal&&{dismissal:t.dismissal}}:n?"string"==typeof n?"alreadyPresenting"===n?{resolution:"not_presented",notPresentedReason:"already_presenting"}:"notConfigured"===n?{resolution:"not_presented",notPresentedReason:"not_configured"}:{resolution:"presented",...ue,...void 0!==he[n]&&{dismissal:he[n]}}:{resolution:"not_presented",notPresentedReason:(r=n.error.code,`error.${r.toLowerCase()}`)}:{resolution:"presented",...ue};var r}class me{#Ne;constructor(){this.#Ne=new Map}on(e,t){this.#Ne.has(e)||this.#Ne.set(e,new Set);const n=this.#Ne.get(e);if(!n)throw new Error(`Failed to get handlers for event '${String(e)}'`);return n.add(t),h.debug(`Event listener added for '${String(e)}'`),()=>{this.off(e,t)}}off(e,t){const n=this.#Ne.get(e);n&&(n.delete(t),h.debug(`Event listener removed for '${String(e)}'`),0===n.size&&this.#Ne.delete(e))}emit(e,t){const n=this.#Ne.get(e);if(n&&0!==n.size){h.debug(`Emitting event '${String(e)}'`,{listenerCount:n.size});for(const r of n)try{r(t)}catch(t){h.error(`Error in event handler for '${String(e)}':`,t)}}}removeAllListeners(e){e?(this.#Ne.delete(e),h.debug(`All listeners removed for '${String(e)}'`)):(this.#Ne.clear(),h.debug("All event listeners removed"))}listenerCount(e){return this.#Ne.get(e)?.size??0}hasListeners(e){const t=this.#Ne.get(e);return void 0!==t&&t.size>0}}const fe=16;function ge(e,t,n){return Math.min(n,Math.max(t,e))}function be(e,t,n){return(.2126*e+.7152*t+.0722*n)/255}function ve(e,t,n){const r=e/255,i=t/255,o=n/255,s=Math.max(r,i,o),a=Math.min(r,i,o),l=(s+a)/2,c=s-a;return 0===c?{h:0,s:0,l:l}:{h:((s===r?(i-o)/c%6*60:s===i?60*((o-r)/c+2):60*((r-i)/c+4))%360+360)%360,s:c/(1-Math.abs(2*l-1)),l:l}}function we(e,t,n){return function(e,t,n){const r=(1-Math.abs(2*n-1))*t,i=(e%360+360)%360/60,o=r*(1-Math.abs(i%2-1)),[s,a,l]=i<1?[r,o,0]:i<2?[o,r,0]:i<3?[0,r,o]:i<4?[0,o,r]:i<5?[o,0,r]:[r,0,o],c=n-r/2,d=e=>Math.round(ge(255*(e+c),0,255)).toString(16).padStart(2,"0");return`#${d(s)}${d(a)}${d(l)}`}(e,ge(t,.45,.95),ge(n,.45,.62))}const ye=/^#(?:[0-9a-f]{3,4}|[0-9a-f]{6}|[0-9a-f]{8})$/i,xe=/^(?:rgb|rgba|hsl|hsla|hwb|lab|lch|oklab|oklch|color|color-mix)\(\s*[0-9a-z.,%\s/+-]{1,80}\)$/i,Ie=/^[a-z]{3,24}$/i,Ce=/^var\(\s*--[a-z0-9_-]{1,60}\s*(?:,[a-z0-9#%.,\s-]{0,60})?\)$/i,ke=/^[a-z0-9\s,'"_\-\u00C0-\u024F\u1E00-\u1EFF]{1,128}$/i,Ee=/^(?:0|-?(?:\d{1,5}|\d{0,5}\.\d{1,3})(?:px|rem|em|%|pt|vh|vw|ch|ex))$/i,$e=/^(?:normal|bold|lighter|bolder)$/i,Se=new Set(["left","center","right","start","end"]),Ae=/\/\*|\*\/|[;{}<>\\]/;function Te(e,t){h.warn(`[Encore SDK] Ignoring unsupported ${e} appearance value`,{value:t})}function Re(e){if(null==e)return;if("string"!=typeof e)return null;const t=e.trim();return 0!==t.length?t.length>128||Ae.test(t)?null:t:void 0}function Ne(e){const t=Re(e);if(void 0!==t)return null===t?Te("colour",e):ye.test(t)||xe.test(t)||Ie.test(t)||Ce.test(t)?t:Te("colour",e)}function Ue(e){const t=Re(e);if(void 0!==t)return null===t?Te("font-family",e):ke.test(t)?t:Te("font-family",e)}function Le(e){const t=Re(e);if(void 0!==t)return null===t?Te("length",e):Ee.test(t)?t:Te("length",e)}const Oe="encore-sdk-styles",_e="encore-",Pe="767px",Me="#B728F5";function De(e){const t={},n=Ne(e.primaryColor),r=Ne(e.backgroundColor),i=Ne(e.textColor),o=Le(e.borderRadius),s=Ue(e.fontFamily);return n&&(t.primaryColor=n),r&&(t.backgroundColor=r),i&&(t.textColor=i),o&&(t.borderRadius=o),s&&(t.fontFamily=s),t}const ze="12px",Fe="20px",Be="40px";function He(e={}){if(document.getElementById(Oe))h.debug("Encore styles already injected");else try{const t=document.createElement("style");t.id=Oe,t.textContent=function(e={}){const t=De(e),n=function(e){const t=[];return e.primaryColor&&t.push(`--encore-primary-color: ${e.primaryColor};`),e.backgroundColor&&t.push(`--encore-bg-color: ${e.backgroundColor};`),e.textColor&&t.push(`--encore-text-color: ${e.textColor};`),e.borderRadius&&t.push(`--encore-border-radius: ${e.borderRadius};`),e.fontFamily&&t.push(`--encore-font-family: ${e.fontFamily};`),t.join("\n ")}(t);return`\n /* CSS Custom Properties (Theme Variables) */\n :root {\n ${n||"/* No custom theme variables */"}\n --encore-primary-color: ${t.primaryColor??"#4F46E5"};\n --encore-bg-color: ${t.backgroundColor??"#ffffff"};\n --encore-text-color: ${t.textColor??"#1F2937"};\n --encore-text-muted: color-mix(in srgb, var(--encore-text-color) 60%, transparent);\n /* One step darker than muted, lighter than full text — lead-in copy that must\n read above captions without competing with the page title. */\n --encore-text-secondary: color-mix(in srgb, var(--encore-text-color) 78%, transparent);\n --encore-surface-color: color-mix(in srgb, var(--encore-text-color) 5%, var(--encore-bg-color));\n --encore-border-color: color-mix(in srgb, var(--encore-text-color) 10%, var(--encore-bg-color));\n --encore-border-radius: ${t.borderRadius??"12px"};\n /* Semantic success hue (the reward sheet's status check). Deliberately independent of the\n accent color: the check states a payment fact; the accent sells the offer CTA. */\n --encore-success-color: #159a5b;\n --encore-font-family: ${t.fontFamily??'-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif'};\n }\n\n /* Backdrop */\n .${_e}backdrop {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background-color: rgba(0, 0, 0, 0.55);\n backdrop-filter: blur(2px);\n z-index: 9998;\n opacity: 0;\n transition: opacity 250ms cubic-bezier(0.4, 0, 0.2, 1);\n }\n\n .${_e}backdrop.${_e}visible {\n opacity: 1;\n }\n\n /* Box-sizing reset scoped to the SDK modal so padding/borders never cause\n horizontal overflow on host pages that don't set border-box globally. */\n .${_e}modal,\n .${_e}modal *,\n .${_e}backdrop {\n box-sizing: border-box;\n }\n\n /* Modal Container */\n .${_e}modal {\n position: fixed;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n z-index: 9999;\n background-color: var(--encore-bg-color);\n border-radius: 20px;\n box-shadow: 0 24px 48px -12px rgba(0, 0, 0, 0.18), 0 12px 24px -8px rgba(0, 0, 0, 0.08);\n max-width: 800px;\n max-height: 90vh;\n width: calc(100% - 32px);\n overflow-x: hidden;\n overflow-y: auto;\n opacity: 0;\n transform: translate(-50%, -50%) scale(0.96);\n transition: opacity 250ms cubic-bezier(0.4, 0, 0.2, 1), transform 250ms cubic-bezier(0.4, 0, 0.2, 1);\n font-family: var(--encore-font-family);\n color: var(--encore-text-color);\n /* Anchor the inherited typographic properties at the modal root so host\n page styles can't cascade in. Children inherit OUR values, not the\n host's. Interim guard until Shadow DOM — see web-sdk-style-isolation.md. */\n font-size: 16px;\n font-weight: 400;\n font-style: normal;\n line-height: 1.5;\n letter-spacing: normal;\n word-spacing: normal;\n text-align: left;\n text-transform: none;\n text-indent: 0;\n white-space: normal;\n text-shadow: none;\n }\n\n .${_e}modal.${_e}visible {\n opacity: 1;\n transform: translate(-50%, -50%) scale(1);\n }\n\n /* Close Button */\n .${_e}close-button {\n position: absolute;\n top: 20px;\n right: 20px;\n width: 40px;\n height: 40px;\n border: none;\n background-color: var(--encore-surface-color);\n cursor: pointer;\n border-radius: 50%;\n display: flex;\n align-items: center;\n justify-content: center;\n color: var(--encore-text-muted);\n transition: all 200ms cubic-bezier(0.4, 0, 0.2, 1);\n padding: 0;\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);\n z-index: 10;\n }\n\n .${_e}close-button:hover {\n background-color: var(--encore-bg-color);\n color: var(--encore-text-color);\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.12);\n transform: scale(1.05);\n }\n\n .${_e}close-button:active {\n transform: scale(0.98);\n }\n\n .${_e}close-button:hover {\n outline: 2px solid var(--encore-primary-color);\n outline-offset: 2px;\n }\n\n .${_e}close-button svg {\n width: 18px;\n height: 18px;\n }\n\n /* Body scroll lock */\n body.${_e}no-scroll {\n overflow: hidden;\n }\n\n /* Modal Header */\n .${_e}modal-header {\n padding: 24px 24px 16px;\n border-bottom: 1px solid var(--encore-border-color);\n }\n\n .${_e}modal-title {\n margin: 0;\n font-size: 24px;\n font-weight: 700;\n line-height: 1.25;\n color: var(--encore-text-color);\n }\n\n .${_e}modal-subtitle {\n margin: 8px 0 0;\n font-size: 14px;\n color: var(--encore-text-muted);\n line-height: 1.5;\n }\n\n /* Modal Body */\n .${_e}modal-body {\n padding: 0;\n position: relative;\n isolation: isolate;\n }\n\n /* Carousel Container */\n .${_e}carousel {\n display: flex;\n flex-direction: column;\n overflow: visible;\n }\n\n /* Carousel Header */\n .${_e}carousel-header {\n padding: 40px 68px 28px;\n text-align: center;\n }\n\n .${_e}carousel-title {\n font-size: 32px;\n font-weight: 510;\n line-height: 1.1;\n color: var(--encore-text-color);\n margin: 0 0 8px 0;\n letter-spacing: -0.3px;\n }\n\n .${_e}carousel-subtitle {\n font-size: 16px;\n line-height: 1.2;\n color: var(--encore-text-color);\n margin: 0;\n font-weight: 400;\n }\n\n /* Carousel Cards Container - Horizontal Scroll */\n .${_e}carousel-cards {\n display: flex;\n flex-direction: row;\n overflow-x: auto;\n overflow-y: hidden;\n scroll-behavior: smooth;\n scroll-snap-type: x mandatory;\n -webkit-overflow-scrolling: touch;\n scrollbar-width: none;\n -ms-overflow-style: none;\n gap: 24px;\n padding: 24px 78px;\n position: relative;\n }\n\n .${_e}carousel-cards::-webkit-scrollbar {\n display: none;\n }\n\n /* Carousel Item Wrapper. Only opacity ever animates (active-card dimming) — a\n short 200ms so the highlight reads as tracking the swipe, not trailing it. */\n .${_e}carousel-item {\n flex: 0 0 426px;\n width: 426px;\n scroll-snap-align: center;\n scroll-snap-stop: always;\n opacity: 0.5;\n transition: opacity 200ms cubic-bezier(0.4, 0, 0.2, 1);\n pointer-events: auto;\n }\n\n /* Active carousel item */\n .${_e}carousel-item.${_e}active {\n opacity: 1;\n z-index: 1;\n }\n\n /* Offer Card */\n .${_e}offer-card {\n display: flex;\n flex-direction: column;\n background: var(--encore-bg-color);\n border-radius: 16px;\n box-shadow: 0 2px 12px rgba(116, 112, 133, 0.16);\n overflow: hidden;\n }\n\n /* Offer Banner */\n .${_e}offer-banner {\n width: 100%;\n background-color: transparent;\n position: relative;\n padding: 0;\n height: 180px;\n overflow: hidden;\n border-radius: 16px 16px 0 0;\n }\n\n .${_e}offer-banner-image {\n width: 100%;\n height: 100%;\n display: block;\n object-fit: cover;\n background-color: var(--encore-surface-color);\n opacity: 0;\n transition: opacity 200ms ease-out;\n }\n\n .${_e}offer-banner-image.${_e}loaded {\n opacity: 1;\n }\n\n /* Info button on banner */\n .${_e}banner-info-button {\n position: absolute;\n top: 20px;\n right: 20px;\n width: 24px;\n height: 24px;\n border-radius: 50%;\n background-color: var(--encore-surface-color);\n backdrop-filter: blur(6px);\n border: none;\n display: flex;\n align-items: center;\n justify-content: center;\n cursor: pointer;\n transition: all 150ms ease;\n z-index: 3;\n padding: 0;\n }\n\n .${_e}banner-info-button:hover {\n background-color: var(--encore-border-color);\n transform: scale(1.05);\n }\n\n .${_e}banner-info-button:focus {\n outline: 2px solid var(--encore-primary-color);\n outline-offset: 2px;\n }\n\n .${_e}banner-info-button svg {\n width: 14px;\n height: 14px;\n color: var(--encore-text-color);\n stroke-width: 2;\n }\n\n /* Tooltip */\n .${_e}tooltip {\n position: fixed;\n background-color: rgba(28, 28, 32, 0.95);\n color: #ffffff;\n padding: 8px 12px;\n border-radius: 8px;\n font-size: 12px;\n line-height: 1.4;\n font-weight: 500;\n z-index: 10000;\n pointer-events: none;\n opacity: 0;\n transform: translateY(4px);\n transition: opacity 200ms cubic-bezier(0.4, 0, 0.2, 1), transform 200ms cubic-bezier(0.4, 0, 0.2, 1);\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);\n white-space: normal;\n word-wrap: break-word;\n }\n\n .${_e}tooltip-visible {\n opacity: 1;\n transform: translateY(0);\n }\n\n /* Tooltip arrow (optional - using pseudo-element) */\n .${_e}tooltip::after {\n content: '';\n position: absolute;\n width: 0;\n height: 0;\n border-style: solid;\n }\n\n .${_e}tooltip-top::after {\n bottom: -4px;\n left: 50%;\n transform: translateX(-50%);\n border-width: 4px 4px 0 4px;\n border-color: rgba(28, 28, 32, 0.95) transparent transparent transparent;\n }\n\n .${_e}tooltip-bottom::after {\n top: -4px;\n left: 50%;\n transform: translateX(-50%);\n border-width: 0 4px 4px 4px;\n border-color: transparent transparent rgba(28, 28, 32, 0.95) transparent;\n }\n\n .${_e}tooltip-left::after {\n right: -4px;\n top: 50%;\n transform: translateY(-50%);\n border-width: 4px 0 4px 4px;\n border-color: transparent transparent transparent rgba(28, 28, 32, 0.95);\n }\n\n .${_e}tooltip-right::after {\n left: -4px;\n top: 50%;\n transform: translateY(-50%);\n border-width: 4px 4px 4px 0;\n border-color: transparent rgba(28, 28, 32, 0.95) transparent transparent;\n }\n\n /* Offer Footer */\n .${_e}offer-footer {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 16px 20px;\n border-top: 1px solid var(--encore-border-color);\n gap: 12px;\n min-height: 74px;\n }\n\n /* Offer Merchant */\n .${_e}offer-merchant {\n display: flex;\n align-items: center;\n gap: 8px;\n flex: 1;\n min-width: 0;\n }\n\n .${_e}offer-logo {\n width: 42px;\n height: 42px;\n border-radius: 8px;\n object-fit: contain;\n background-color: var(--encore-surface-color);\n flex-shrink: 0;\n opacity: 0;\n transition: opacity 200ms ease-out;\n }\n\n .${_e}offer-logo.${_e}loaded {\n opacity: 1;\n }\n\n .${_e}offer-merchant-text {\n display: flex;\n flex-direction: column;\n gap: 2px;\n flex: 1;\n min-width: 0;\n }\n\n .${_e}offer-merchant-name {\n font-size: 16px;\n font-weight: 590;\n color: var(--encore-text-color);\n line-height: 1.1;\n letter-spacing: -1px;\n }\n\n .${_e}offer-merchant-desc {\n font-size: 14px;\n color: var(--encore-text-muted);\n line-height: 1.2;\n letter-spacing: -1px;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n }\n\n /* Claim Button */\n .${_e}button-claim {\n padding: 10px 16px;\n height: 34px;\n min-width: 78px;\n font-size: 14px;\n font-weight: 590;\n border-radius: 999px;\n border: none;\n background: var(--encore-primary-color);\n color: white;\n cursor: pointer;\n transition: all 200ms cubic-bezier(0.4, 0, 0.2, 1);\n font-family: var(--encore-font-family);\n white-space: nowrap;\n line-height: 1.2;\n display: flex;\n align-items: center;\n justify-content: center;\n }\n\n .${_e}button-claim:hover:not(:disabled) {\n background: color-mix(in srgb, var(--encore-primary-color) 85%, black);\n transform: translateY(-1px);\n box-shadow: 0 2px 8px color-mix(in srgb, var(--encore-primary-color) 30%, transparent);\n }\n\n .${_e}button-claim:active {\n transform: translateY(0);\n background: color-mix(in srgb, var(--encore-primary-color) 75%, black);\n }\n\n .${_e}button-claim:focus {\n outline: 2px solid var(--encore-primary-color);\n outline-offset: 2px;\n }\n\n .${_e}button-claim:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n transform: none;\n }\n\n /* Carousel Navigation */\n .${_e}carousel-navigation {\n display: flex;\n justify-content: center;\n align-items: center;\n gap: 40px;\n padding: 28px 32px 32px;\n }\n\n .${_e}nav-button {\n width: 32px;\n height: 32px;\n border-radius: 50%;\n border: 1px solid var(--encore-text-muted);\n background-color: var(--encore-bg-color);\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n color: var(--encore-text-muted);\n transition: all 200ms cubic-bezier(0.4, 0, 0.2, 1);\n padding: 0;\n }\n\n .${_e}nav-button:hover:not(:disabled) {\n border-color: var(--encore-primary-color);\n color: var(--encore-primary-color);\n transform: scale(1.05);\n }\n\n .${_e}nav-button:active:not(:disabled) {\n transform: scale(0.95);\n }\n\n .${_e}nav-button:focus {\n outline: 2px solid var(--encore-primary-color);\n outline-offset: 2px;\n }\n\n .${_e}nav-button svg {\n width: 20px;\n height: 20px;\n stroke-width: 2;\n }\n\n .${_e}nav-button:not(:disabled) {\n border-color: var(--encore-primary-color);\n color: var(--encore-primary-color);\n }\n\n .${_e}nav-button:disabled,\n .${_e}nav-button.${_e}disabled {\n opacity: 1;\n cursor: not-allowed;\n border-color: var(--encore-text-muted);\n color: var(--encore-text-muted);\n }\n\n .${_e}nav-button:disabled:hover,\n .${_e}nav-button.${_e}disabled:hover {\n border-color: var(--encore-text-muted);\n color: var(--encore-text-muted);\n transform: none;\n }\n\n /* Loading State */\n .${_e}loading {\n display: flex;\n align-items: center;\n justify-content: center;\n padding: 48px;\n }\n\n .${_e}spinner {\n width: 40px;\n height: 40px;\n border: 3px solid var(--encore-border-color);\n border-top-color: var(--encore-primary-color);\n border-radius: 50%;\n animation: ${_e}spin 0.8s linear infinite;\n }\n\n @keyframes ${_e}spin {\n to { transform: rotate(360deg); }\n }\n\n /* Responsive: Mobile (0-767px) — full-screen vertical sheet */\n @media (max-width: ${Pe}) {\n /* Modal becomes a full-screen sheet. dvh fallback so mobile browser URL\n bars don't clip the bottom. It is a flex column so the height\n propagates down to the scrollable cards region. */\n .${_e}modal {\n display: flex;\n flex-direction: column;\n inset: 0;\n top: 0;\n left: 0;\n transform: none;\n width: 100%;\n height: 100vh;\n height: 100dvh;\n max-width: none;\n max-height: none;\n border-radius: 0;\n margin: 0;\n overflow: hidden;\n }\n\n /* Fade only — override the desktop scale/translate transition. */\n .${_e}modal.${_e}visible {\n transform: none;\n }\n\n /* Body fills the sheet and forwards the height to the carousel.\n min-height:0 lets the inner scroll container actually overflow. */\n .${_e}modal-body {\n display: flex;\n flex: 1 1 auto;\n min-height: 0;\n flex-direction: column;\n }\n\n /* Carousel fills the body so the cards region can flex to fill height. */\n .${_e}carousel {\n flex: 1 1 auto;\n min-height: 0;\n overflow: hidden;\n }\n\n /* Sticky header pinned while the list scrolls; respect the notch. 64px side\n The close button is an absolute overlay (top 16 + 40px tall), so the\n header reserves that band VERTICALLY: the title starts below the X and\n spans the full sheet width with slim symmetric side padding — no dead\n 64px gutters squeezing the headline into the X's row. */\n .${_e}carousel-header {\n position: sticky;\n top: 0;\n z-index: 2;\n background: var(--encore-bg-color);\n padding: calc(64px + env(safe-area-inset-top)) 24px 20px;\n }\n\n .${_e}carousel-title {\n font-size: 22px;\n }\n\n .${_e}carousel-subtitle {\n font-size: 14px;\n }\n\n /* Vertical, full-height scrollable feed. */\n .${_e}carousel-cards {\n flex: 1 1 auto;\n min-height: 0;\n flex-direction: column;\n overflow-x: hidden;\n overflow-y: auto;\n scroll-snap-type: none;\n overscroll-behavior: contain;\n gap: 16px;\n padding: 16px 16px calc(16px + env(safe-area-inset-bottom));\n }\n\n /* Full-width stacked cards, no carousel dimming or snapping.\n overflow:visible so each card's shadow isn't clipped by the item box. */\n .${_e}carousel-item {\n flex: 0 0 auto;\n width: 100%;\n opacity: 1;\n scroll-snap-align: none;\n overflow: visible;\n }\n\n /* Keep the rounded card + visible shadow on mobile (matches design). */\n .${_e}offer-card {\n width: 100%;\n max-width: 100%;\n border-radius: 16px;\n box-shadow: 0 4px 16px rgba(116, 112, 133, 0.22);\n border: 1px solid var(--encore-border-color);\n }\n\n /* Image fills the card edge-to-edge with rounded top corners\n (no inset padding, banner already clips to the card radius). */\n .${_e}offer-banner {\n height: auto;\n padding: 0;\n border-radius: 16px 16px 0 0;\n }\n\n .${_e}offer-banner-image {\n width: 100%;\n height: auto;\n display: block;\n }\n\n /* Logo + name + description on the left, small claim button pinned far\n right on a single row (no wrap / no full-width stacking). */\n .${_e}offer-footer {\n flex-wrap: nowrap;\n align-items: center;\n justify-content: space-between;\n gap: 12px;\n padding: 14px 16px;\n }\n\n .${_e}offer-merchant {\n flex: 1 1 auto;\n min-width: 0;\n }\n\n /* Small button hugging its label, to the far right. */\n .${_e}button-claim {\n flex: 0 0 auto;\n width: auto;\n }\n\n /* No nav arrows in vertical mode. */\n .${_e}carousel-navigation {\n display: none;\n }\n\n /* Keep the close button reachable inside the sticky header / below the notch. */\n .${_e}close-button {\n top: calc(16px + env(safe-area-inset-top));\n right: 16px;\n }\n\n /* Paged carousel keeps its nav bubbles on mobile (the display:none above is\n the responsive/'list' vertical mode only). */\n .${_e}carousel-paged .${_e}carousel-navigation {\n display: flex;\n }\n\n /* NOTE: the reward sheet's own mobile overrides live in a dedicated media\n block AFTER the base reward-sheet section (source order matters at equal\n specificity — a media query adds none). */\n }\n\n /* Responsive: Tablet (768-1023px) */\n @media (min-width: 768px) and (max-width: 1023px) {\n .${_e}modal {\n max-width: 600px;\n }\n }\n\n /* Responsive: Desktop (1024px+) */\n @media (min-width: 1024px) {\n .${_e}modal {\n max-width: 600px;\n }\n }\n\n /* Accessibility: High Contrast Mode */\n @media (prefers-contrast: high) {\n .${_e}button {\n border: 2px solid currentColor;\n }\n }\n\n /* Accessibility: Reduced Motion */\n @media (prefers-reduced-motion: reduce) {\n .${_e}backdrop,\n .${_e}modal,\n .${_e}button,\n .${_e}close-button {\n transition: none;\n }\n\n .${_e}spinner {\n animation: none;\n }\n }\n\n /* Focus Visible (for keyboard navigation) */\n .${_e}button:focus-visible,\n .${_e}close-button:focus-visible {\n outline: 2px solid var(--encore-primary-color);\n outline-offset: 2px;\n }\n\n\n /* ===== Paged carousel (the reward sheet) ===== */\n /* Always-horizontal, one-card-per-view, scroll-snap paged — at every breakpoint.\n Scoped under carousel-paged so the responsive ('list') carousel rules are\n untouched. Each page is slightly narrower than the viewport so the neighboring\n cards PEEK in at the edges at reduced opacity — the same visual grammar as the\n list carousel: "there are more offers, swipe". Desktop caps the page width so\n the peek survives wide modals (no 426px hardcode). */\n .${_e}carousel-paged .${_e}carousel-cards {\n flex-direction: row;\n align-items: center;\n overflow-x: auto;\n overflow-y: hidden;\n scroll-snap-type: x mandatory;\n /* auto, NOT the base 'smooth': smooth scroll-behavior makes the browser ANIMATE\n its own snap re-alignments (e.g. when an async banner image loads and reflows\n the row mid-gesture), which reads as a laggy post-swipe snap. Native gesture\n snapping is untouched, and programmatic paging still requests smooth\n explicitly via scrollIntoView's behavior option. */\n scroll-behavior: auto;\n gap: 12px;\n /* Horizontal padding is 0 — the symmetric first/last-item gutters below own\n the side spacing so the ACTIVE card is always centered. Vertical padding is\n shadow room: overflow-y:hidden would clip the card shadows without it. */\n padding: ${Fe} 0;\n /* One "page" = the card slot. 64px total side allowance → 32px gutter each\n side (a ~20px neighbor-peek after the 12px gap at the 375px design width);\n the 480px cap keeps the peek alive in wide modals. Declared once here and\n shared by the item basis and the centering gutters so they can never drift. */\n --encore-page-size: min(100% - 64px, 480px);\n }\n\n .${_e}carousel-paged .${_e}carousel-item {\n /* Size via width (flex-basis:auto → width), NOT a math function inside the\n flex shorthand: engines that choke on functions in the shorthand drop the\n whole declaration and fall back to the base 426px item — which is exactly a\n clipped, overflowing card on a 375px phone. width + the max-width guard\n make overflow impossible at any breakpoint. */\n flex: 0 0 auto;\n width: var(--encore-page-size);\n max-width: 100%;\n /* Peek legibility: light creatives on the white sheet disappear below ~0.5,\n killing the "more offers" affordance. 0.65 keeps the active card clearly\n dominant while the neighbors stay readable. */\n opacity: 0.65;\n scroll-snap-align: center;\n scroll-snap-stop: always;\n overflow: visible;\n }\n\n /* Symmetric centering gutters: first/last pages get margins of exactly\n (container − page) / 2, so card 0 RESTS CENTERED at scrollLeft 0 (empty gutter\n left, peek right), mid-cards show symmetric peeks, and the last card can reach\n center too. Both the margin percentage and the flex-basis percentage resolve against the same\n container content width, so the math is exact at any size — the natural resting\n position IS the snap position and mount needs no scroll correction. */\n .${_e}carousel-paged .${_e}carousel-item:first-child {\n margin-inline-start: calc((100% - var(--encore-page-size)) / 2);\n }\n\n .${_e}carousel-paged .${_e}carousel-item:last-child {\n margin-inline-end: calc((100% - var(--encore-page-size)) / 2);\n }\n\n .${_e}carousel-paged .${_e}carousel-item.${_e}active {\n opacity: 1;\n }\n\n .${_e}carousel-paged .${_e}offer-card {\n max-width: 460px;\n margin: 0 auto;\n border: 1px solid var(--encore-border-color);\n box-shadow: 0 4px 16px rgba(116, 112, 133, 0.18);\n }\n\n /* Fluid banner: natural aspect, scales with the card. */\n .${_e}carousel-paged .${_e}offer-banner {\n height: auto;\n }\n\n .${_e}carousel-paged .${_e}offer-banner-image {\n width: 100%;\n height: auto;\n display: block;\n }\n\n /* Nav row: centered DIRECTLY beneath the cards — these chevrons are carousel\n controls and must read as part of the carousel unit, so they hug it (never\n bottom-anchored away from it). Comfortable 48px circular tap targets in normal\n flow — no overlay, no z-index games. Rhythm: cards→nav gap = the cards' bottom\n shadow gutter + 4px here (16px total inside the sheet); the 20px bottom padding\n is the nav→footer gap (and the sheet's bottom inset when no trust footer is\n configured). */\n .${_e}carousel-paged .${_e}carousel-navigation {\n display: flex;\n justify-content: center;\n align-items: center;\n gap: 24px;\n padding: 4px 20px ${Fe};\n }\n\n .${_e}carousel-paged .${_e}nav-button {\n width: 48px;\n height: 48px;\n background-color: var(--encore-bg-color);\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);\n }\n\n /* Neutral idle bubble (the accent belongs to the Claim CTA); accent only on hover. */\n .${_e}carousel-paged .${_e}nav-button:not(:disabled) {\n border-color: var(--encore-border-color);\n color: var(--encore-text-color);\n }\n\n .${_e}carousel-paged .${_e}nav-button:hover:not(:disabled) {\n border-color: var(--encore-primary-color);\n color: var(--encore-primary-color);\n box-shadow: 0 4px 14px rgba(0, 0, 0, 0.16);\n }\n\n .${_e}carousel-paged .${_e}nav-button svg {\n width: 22px;\n height: 22px;\n }\n\n .${_e}carousel-paged .${_e}nav-button:disabled,\n .${_e}carousel-paged .${_e}nav-button.${_e}disabled {\n opacity: 0.35;\n box-shadow: none;\n border-color: var(--encore-border-color);\n color: var(--encore-text-muted);\n }\n\n /* ===== Reward sheet chrome (useCase: 'rewardUsers') =====\n The encore-thankyou class names predate the 3.0.0 rename — they are internal\n style hooks, kept so the whole visual system (including the --reward parity\n block below) did not have to churn. See ui/RewardLayout.ts. */\n /* Pure chrome around the unchanged carousel: status block above, trust footer\n below. Desktop: normal flow inside the content-sized modal (the stack is\n inherently tight there). Mobile: joins the sheet's flex chain — the content\n stack is optically centered while the trust footer stays bottom-pinned. */\n .${_e}thankyou {\n display: flex;\n flex-direction: column;\n }\n\n /* SUCCESS UNIT — check → title → receipt as ONE tight visual group. Internal\n gaps are deliberately tight (proximity = grouping); the heading below is the\n sheet's single focal point. No bottom padding: the 32px section break lives\n on the intro header so it is owned in exactly one place. */\n .${_e}thankyou-status {\n display: flex;\n flex-direction: column;\n align-items: center;\n text-align: center;\n padding: ${Be} 24px 0;\n }\n\n /* "Receipt stamp" check: deep-green disc in a soft halo. Calm by design — no\n pulse, no gradient (a payment fact, stated quietly). Margin-bottom is the\n 12px halo ring + the 12px check→title step of the ladder. */\n .${_e}thankyou-check {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 48px;\n height: 48px;\n border-radius: 50%;\n background: var(--encore-success-color);\n color: #ffffff;\n box-shadow: 0 0 0 12px color-mix(in srgb, var(--encore-success-color) 14%, var(--encore-bg-color));\n margin: 0 0 calc(12px + ${ze});\n }\n\n .${_e}thankyou-check svg {\n width: 24px;\n height: 24px;\n }\n\n /* The ONLY large/heavy type on the sheet — everything else defers to it. */\n .${_e}thankyou-title {\n margin: 0;\n font-size: 20px;\n font-weight: 600;\n line-height: 1.25;\n letter-spacing: -0.2px;\n color: var(--encore-text-color);\n overflow-wrap: anywhere;\n }\n\n /* Subheadline — sits tight under the title (same statement, quieter voice). */\n .${_e}thankyou-subtitle {\n margin: 4px 0 0;\n font-size: 14px;\n line-height: 1.5;\n color: var(--encore-text-muted);\n overflow-wrap: anywhere;\n }\n\n /* Context → cards 16px, cards → nav 16px (12px shadow gutter + the nav row's 4px\n top padding): the carousel unit is bound tight to its lead-in above and its\n controls below. The 12px bottom gutter still clears the visible card shadow. */\n .${_e}thankyou .${_e}carousel-cards {\n padding-top: 16px;\n padding-bottom: ${ze};\n }\n\n;\n font-size: 12px;\n line-height: 1.5;\n text-align: center;\n color: var(--encore-text-muted);\n overflow-wrap: anywhere;\n display: -webkit-box;\n -webkit-line-clamp: 2;\n -webkit-box-orient: vertical;\n overflow: hidden;\n }\n\n /* The reward sheet on mobile full-screen: join the sheet's flex chain — the\n content stack floats optically centered above the bottom-pinned trust footer,\n and the carousel keeps its internal scroll. Type + rhythm come from the base\n system above (375px IS its design target) — only sheet-specific bits\n are overridden. This block must stay AFTER the base rules: it wins by\n source order, not specificity. */\n @media (max-width: ${Pe}) {\n .${_e}thankyou {\n flex: 1 1 auto;\n min-height: 0;\n }\n\n /* Full-height composition: everything except the trust footer is ONE tight,\n internally-rigid stack (success unit → context pair → cards → nav row),\n OPTICALLY CENTERED in the space above the bottom-pinned footer. Two\n zero-basis flex spaces own ALL the slack — this ::before above the stack\n (grow 1) and the carousel's ::after below it (grow 1.35, via the carousel's\n own grow factor) — an above:below ratio of 1:1.35 so the stack rests\n slightly high of true center. The stack's internal ladder gaps never\n stretch, so the composition compresses as a unit on short sheets and\n floats as a unit on tall ones. */\n .${_e}thankyou::before {\n content: '';\n flex: 1 1 0;\n min-height: 0;\n }\n\n .${_e}thankyou-status {\n flex: 0 0 auto;\n /* Real fixed margin above the check — the floor when the flex space above\n has fully compressed; the notch inset always survives. */\n padding-top: calc(${Be} + env(safe-area-inset-top));\n }\n\n .${_e}thankyou-check {\n width: 44px;\n height: 44px;\n }\n\n /* The carousel's grow factor IS the below-stack share: its extra height is\n absorbed entirely by the ::after spacer under the nav row, giving the\n 1:1.35 above:below split against the ::before above. Shrinks like before\n (basis auto, min-height 0) so short sheets compress the cards region. */\n .${_e}thankyou .${_e}carousel {\n flex: 1.35 1 auto;\n min-height: 0;\n }\n\n .${_e}thankyou .${_e}carousel::after {\n content: '';\n flex: 1 1 0;\n min-height: 0;\n }\n\n /* Nav hugs the cards (rigid ladder gap) — the old auto-margin bottom-anchor\n is gone: the arrows are carousel controls and read as part of the carousel\n unit, not footer furniture. */\n .${_e}thankyou .${_e}carousel-cards {\n flex: 0 1 auto;\n min-height: 0;\n }\n\n }\n\n /* ===== Reward parity with the native SDUI variant =====\n Tracks streaksCarousel.json — the SAME screen iOS and Android render — so a\n publisher running reward on more than one platform sees one design rather\n than three. Values are read off that file, not eyeballed from a screenshot:\n\n headline 28 / semibold, centered\n subheadline 16 / regular, centered\n offer card cornerRadius 24\n primary CTA cornerRadius 12 (deliberately NOT the pill the churn\n carousel uses — the variant is explicit)\n gutters 20 leading/trailing\n\n Scoped entirely to the --reward modifier, which the chrome always sets: the\n base rules keep a tighter 20/14 scale, and these override it with the\n celebration scale. Placed AFTER the mobile block so it wins on source\n order, matching the convention that block already documents. */\n .${_e}thankyou--reward .${_e}thankyou-title {\n font-size: 28px;\n font-weight: 600;\n line-height: 1.2;\n letter-spacing: -0.4px;\n text-align: center;\n }\n\n .${_e}thankyou--reward .${_e}thankyou-subtitle {\n font-size: 16px;\n font-weight: 400;\n line-height: 1.35;\n text-align: center;\n }\n\n .${_e}thankyou--reward .${_e}thankyou-status {\n padding-left: 20px;\n padding-right: 20px;\n }\n\n /* On the mobile full-screen sheet the variant is edge-to-edge (fullScreenCover,\n detent 1.0, no drag indicator) with 20px gutters. */\n @media (max-width: ${Pe}) {\n .${_e}thankyou--reward .${_e}carousel-cards {\n padding-left: 20px;\n padding-right: 20px;\n }\n }\n\n /* ===== Reward interaction model — tracks streaksCarousel.json's browse state.\n Reward DOM only: either --reward-scoped, or a class (page-indicator / dot /\n reward-*) the reward composition alone renders. See RewardActions.ts and\n OfferCarousel's \`selectable\` option for the per-value rationale. ===== */\n .${_e}thankyou--reward .${_e}carousel-item[aria-selected] {\n cursor: pointer;\n }\n\n /* The listbox is one tab stop, so it needs its own ring. Inset — an outset one\n is clipped by the container's horizontal overflow.\n \n KEYBOARD DEVICES ONLY, and :focus-visible alone is not enough to say so.\n This is a div with tabindex="0", and Safari focuses one on TAP and then\n matches :focus-visible on it — so an iOS user tapping a card to browse\n got a 2px ring around the whole carousel, on a sheet where there is no\n Tab key and so nothing the ring could be telling them. Chrome on desktop\n does not do this, which is why it survived review.\n\n Gated on a fine pointer rather than on :focus-visible being smarter:\n a device with no keyboard has no use for a focus ring, and a device with\n one keeps it exactly as before. */\n .${_e}carousel-select:focus {\n outline: none;\n }\n\n @media (hover: hover) and (pointer: fine) {\n .${_e}carousel-select:focus-visible {\n outline: 2px solid var(--encore-primary-color);\n outline-offset: -2px;\n border-radius: 16px;\n }\n }\n\n /* compactPageIndicator: position feedback only, never a control. */\n .${_e}page-indicator {\n display: flex;\n justify-content: center;\n align-items: center;\n gap: 8px;\n padding: 19px 20px 0;\n }\n\n /* Figma 18304:3071 — four ellipses, inactive 6px, active 10px, 8px edge gaps\n (52px total for four). The size change IS the state change here, so both\n dimensions animate alongside the fill. */\n .${_e}dot {\n flex: 0 0 auto;\n width: 6px;\n height: 6px;\n border-radius: 50%;\n /* var() fallback = today's value, so an unset override is byte-identical. */\n background: var(\n --encore-dot-color,\n color-mix(in srgb, #6A6D81 30%, transparent)\n );\n transition:\n background 200ms cubic-bezier(0.4, 0, 0.2, 1),\n width 200ms cubic-bezier(0.4, 0, 0.2, 1),\n height 200ms cubic-bezier(0.4, 0, 0.2, 1);\n }\n\n .${_e}dot.${_e}active {\n width: 10px;\n height: 10px;\n background: var(--encore-dot-active-color, var(--encore-reward-brand));\n }\n\n /* Trust line + CTA stack, 12px apart, 20px gutters. 31px bottom inset is the\n variant's browse-state padding; env() is ADDED so the 31 always survives. */\n .${_e}reward-actions {\n display: flex;\n flex-direction: column;\n gap: 12px;\n /* max(), not addition. The 31px is the variant's browse-state padding\n and the inset is the hardware's; adding them stacked a full\n home-indicator gap ON TOP of a padding that was already clear of it,\n which is the space under the CTAs in a tall-phone screenshot. Taking\n the larger of the two keeps the 31 as the floor and lets the inset win\n only where it is genuinely bigger.\n\n A mobile browser's own bottom bar is NOT covered by this: it shrinks\n the viewport, which 100dvh on the sheet already tracks. */\n padding: 20px 20px max(31px, env(safe-area-inset-bottom));\n }\n\n .${_e}reward-trust {\n margin: 0;\n font-size: 14px;\n font-weight: 400;\n line-height: 1.2;\n text-align: center;\n color: color-mix(in srgb, var(--encore-text-color) 55%, transparent);\n overflow-wrap: anywhere;\n display: -webkit-box;\n -webkit-line-clamp: 2;\n -webkit-box-orient: vertical;\n overflow: hidden;\n }\n\n .${_e}reward-cta-stack {\n display: flex;\n flex-direction: column;\n gap: 8px;\n }\n\n /* Both buttons are full pills (Figma radius 100), not the variant's 12 — see\n REWARD_BRAND. Heights are the Figma's: primary 51, secondary 48. */\n .${_e}reward-cta-primary,\n .${_e}reward-cta-secondary {\n width: 100%;\n box-sizing: border-box;\n border-radius: 100px;\n font-family: var(--encore-font-family);\n font-size: 16px;\n line-height: 1.2;\n text-align: center;\n cursor: pointer;\n transition: all 200ms cubic-bezier(0.4, 0, 0.2, 1);\n }\n\n /*\n * Claiming switched off (Encore.isClaimEnabled). Matches the carousel's own\n * disabled Claim button: without this the reward CTA is unclickable but still\n * looks and feels live, which reads as a broken button rather than an\n * unavailable one.\n *\n * TWO selectors because there are two elements. The default CTA is a button and\n * carries the native disabled property. A publisher-supplied claim slot is mounted\n * in a div[role=button] host, where disabled is meaningless and :disabled never\n * matches it — that one carries aria-disabled instead. Dropping either selector\n * leaves one of the two paths looking live while it is inert.\n *\n * No backticks in this comment: the whole stylesheet is a template literal, and a\n * backtick here closes it.\n */\n .${_e}reward-cta-primary:disabled,\n .${_e}reward-cta-primary[aria-disabled='true'] {\n opacity: 0.5;\n cursor: not-allowed;\n }\n\n .${_e}reward-cta-primary {\n height: 51px;\n padding: 0 12px;\n border: none;\n font-weight: 700;\n background-image: linear-gradient(\n 98.22deg,\n var(--encore-reward-brand) 0%,\n var(--encore-reward-brand-deep) 100%\n );\n color: #ffffff;\n }\n\n /* Darken via an overlay rather than swapping the background: \`background-image\`\n cannot be color-mixed, and re-declaring the whole gradient per state would put\n the stops in four places. */\n .${_e}reward-cta-primary:hover {\n box-shadow: inset 0 0 0 999px rgba(0, 0, 0, 0.12);\n }\n\n .${_e}reward-cta-primary:active {\n box-shadow: inset 0 0 0 999px rgba(0, 0, 0, 0.2);\n }\n\n .${_e}reward-cta-secondary {\n height: 48px;\n padding: 0 12px;\n border: 1px solid rgba(0, 0, 0, 0.1);\n font-weight: 500;\n background: transparent;\n color: #9c9c9c;\n }\n\n .${_e}reward-cta-secondary:hover {\n border-color: rgba(0, 0, 0, 0.22);\n color: var(--encore-text-color);\n }\n\n .${_e}reward-cta-primary:focus-visible,\n .${_e}reward-cta-secondary:focus-visible {\n outline: 2px solid var(--encore-primary-color);\n outline-offset: 2px;\n }\n\n /* Publisher appearance slots — see APPEARANCE_SLOT_NOTES. */\n .${_e}slot-custom {\n font: inherit;\n color: inherit;\n letter-spacing: normal;\n margin: 0;\n }\n\n .${_e}slot-host {\n display: flex;\n align-items: center;\n justify-content: center;\n height: auto;\n padding: 0;\n border: none;\n background: none;\n background-image: none;\n box-shadow: none;\n color: inherit;\n cursor: pointer;\n }\n\n .${_e}slot-host:hover,\n .${_e}slot-host:active {\n box-shadow: none;\n border-color: transparent;\n color: inherit;\n }\n\n /* Rigid furniture on the sheet: never absorbs slack, never compresses. The\n carousel's ::after owns the elastic space that floats it to the bottom. */\n @media (max-width: ${Pe}) {\n .${_e}thankyou--reward .${_e}reward-actions {\n flex: 0 0 auto;\n /* Pinned to the bottom of the sheet rather than left wherever the\n space split above it happened to end. auto absorbs ALL remaining\n slack, so the CTAs sit against the bottom inset at every height\n instead of floating with a gap under them on a tall phone.\n\n It does not fight the carousel's 1.35:1 share above: that split\n governs the space the carousel and its ::after divide between them,\n and this only claims what is left after the whole column is laid\n out — which on a short sheet is nothing. */\n margin-top: auto;\n }\n }\n\n /* ===== Reward visual parity — Figma 18304:2399. Reward-only selectors.\n Rationale lives in REWARD_VISUAL_NOTES (JS, stripped from the bundle). ===== */\n\n /* Flat: declares NO background, so the sheet inherits the modal's colour like\n every other composition. position stays as the confetti canvas's positioning\n context — it is not background. */\n .${_e}thankyou--reward {\n --encore-reward-brand: ${Me};\n --encore-reward-brand-deep: #6515ED;\n position: relative;\n }\n\n /* Content column holds the 393 design width and centres.\n z-index 1 lifts content over the confetti, per the zStack order. */\n .${_e}thankyou--reward > .${_e}thankyou-status,\n .${_e}thankyou--reward > .${_e}carousel,\n .${_e}thankyou--reward > .${_e}reward-actions {\n position: relative;\n z-index: 1;\n width: 100%;\n max-width: 393px;\n margin-left: auto;\n margin-right: auto;\n }\n\n /* Header (Figma 18304:3391). Text colours stay THEME TOKENS, never the Figma\n hexes — the variant's dark-mode rule (backend #426/#427). */\n .${_e}thankyou--reward .${_e}thankyou-title {\n margin: 0;\n font-size: 28px;\n font-weight: 600;\n line-height: 1.1;\n letter-spacing: -0.28px;\n text-align: center;\n text-wrap: balance;\n }\n\n .${_e}thankyou--reward .${_e}thankyou-subtitle {\n margin: 12px 0 0;\n font-size: 16px;\n font-weight: 400;\n line-height: 1.3;\n text-align: center;\n /* 0.55, not the Figma's 0.50: the variant's WCAG AA figure wins on contrast. */\n color: color-mix(in srgb, var(--encore-text-color) 55%, transparent);\n }\n\n /* Hero carousel. Neighbour = opacity .55 + scale .95 + translateY(11px),\n MEASURED off the render; no filter (opacity composites on the GPU). */\n .${_e}thankyou--reward .${_e}carousel {\n position: relative;\n }\n\n .${_e}thankyou--reward .${_e}carousel-cards {\n gap: 10px;\n /* Half container minus half card — lets the first/last card reach centre. */\n padding: 26px calc(50% - 105px);\n align-items: center;\n }\n\n .${_e}thankyou--reward .${_e}carousel-item {\n flex: 0 0 210px;\n width: 210px;\n opacity: 0.55;\n transform: translateY(11px) scale(0.95);\n transform-origin: center center;\n transition:\n opacity 260ms cubic-bezier(0.4, 0, 0.2, 1),\n transform 260ms cubic-bezier(0.4, 0, 0.2, 1);\n }\n\n /* \`.active\` (geometric, tracks the drag), not \`[aria-selected]\` (commits on\n settle). One index, so they converge at rest. */\n .${_e}thankyou--reward .${_e}carousel-item.${_e}active {\n opacity: 1;\n transform: none;\n z-index: 1;\n }\n\n /* Registering the tint makes it an ANIMATABLE colour rather than an opaque\n token, so the tier-1 -> tier-2 upgrade eases instead of popping. Measured at\n 69-156ms cold against production logos — inside the modal's 250ms fade, so the\n swap is normally masked — but that is a property of a fast connection, not a\n guarantee, and a slow one would land the swap on a fully-visible sheet.\n Browsers without @property ignore this and swap instantly, exactly as before. */\n @property --encore-card-tint {\n syntax: '<color>';\n inherits: false;\n initial-value: ${Me};\n }\n\n /* ---- The card itself (Figma 18304:3383) ---- */\n .${_e}reward-card {\n --encore-card-tint: ${Me};\n position: relative;\n box-sizing: border-box;\n width: 210px;\n height: 260px;\n /* 43 to the pill, then the ladder below is gap-driven. */\n padding: 43px 15px 0;\n display: flex;\n flex-direction: column;\n align-items: center;\n border-radius: 24px;\n overflow: hidden;\n background-color: #ffffff;\n /* Body = tint@10% over white (measured). The radials add the Figma's deeper\n right/bottom wash, derived from the same tint so any brand colour works. */\n background-image:\n radial-gradient(\n 120% 85% at 100% 0%,\n color-mix(in srgb, var(--encore-card-tint) 22%, transparent) 0%,\n transparent 68%\n ),\n radial-gradient(\n 140% 60% at 62% 112%,\n color-mix(in srgb, var(--encore-card-tint) 20%, transparent) 0%,\n transparent 74%\n ),\n linear-gradient(\n 0deg,\n color-mix(in srgb, var(--encore-card-tint) ${Math.round(10)}%, transparent) 0%,\n color-mix(in srgb, var(--encore-card-tint) ${Math.round(10)}%, transparent) 100%\n );\n box-shadow:\n 0 4px 12px rgba(0, 0, 0, 0.09),\n 0 4px 12px rgba(0, 0, 0, 0.02),\n 0 4px 74px rgba(0, 0, 0, 0.06),\n inset -8px 1px 13px color-mix(in srgb, var(--encore-card-tint) 13%, transparent);\n transition: --encore-card-tint 320ms cubic-bezier(0.4, 0, 0.2, 1);\n }\n\n .${_e}reward-card-badge {\n flex: 0 0 auto;\n max-width: 100%;\n box-sizing: border-box;\n padding: 4px 10px;\n border-radius: 16px;\n background: #ffffff;\n box-shadow: 0 2.769px 5.538px rgba(56, 30, 0, 0.03);\n font-size: 14px;\n font-weight: 500;\n line-height: 1.2;\n letter-spacing: -0.3px;\n color: var(--encore-text-color);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n }\n\n /* 84 from the card top = 43 (pad) + 25 (pill) + 16. */\n .${_e}reward-card-icon {\n flex: 0 0 auto;\n margin-top: 16px;\n width: 72px;\n height: 72px;\n border-radius: 18px;\n overflow: hidden;\n display: flex;\n align-items: center;\n justify-content: center;\n background: color-mix(in srgb, var(--encore-card-tint) 92%, #ffffff);\n box-shadow: 0 2.769px 5.538px rgba(56, 30, 0, 0.15);\n }\n\n .${_e}reward-card-icon-image {\n width: 100%;\n height: 100%;\n object-fit: cover;\n display: block;\n }\n\n /* No logo, or a failed load. Ordinary rendering — logoUrl is optional. */\n .${_e}reward-card-monogram {\n font-size: 32px;\n font-weight: 700;\n line-height: 1;\n color: #ffffff;\n }\n\n /* 176 from the card top = 84 + 72 (icon) + 20. */\n .${_e}reward-card-text {\n margin-top: 20px;\n width: 100%;\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 4px;\n min-width: 0;\n }\n\n /* One line: a long name must not push the offer line out of a fixed card. */\n .${_e}reward-card-name {\n max-width: 100%;\n font-size: 18px;\n font-weight: 600;\n line-height: 1.2;\n letter-spacing: -0.18px;\n text-align: center;\n color: var(--encore-text-color);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n }\n\n /* Two lines then clamp — remote perk copy runs longer than the Figma's one. */\n .${_e}reward-card-offer {\n max-width: 100%;\n font-size: 14px;\n font-weight: 400;\n line-height: 1.2;\n letter-spacing: -0.28px;\n text-align: center;\n color: color-mix(in srgb, var(--encore-text-color) 75%, transparent);\n overflow-wrap: anywhere;\n display: -webkit-box;\n -webkit-line-clamp: 2;\n -webkit-box-orient: vertical;\n overflow: hidden;\n }\n\n /* Desktop arrows (mobile has swipe). Rendered only above the breakpoint —\n see OfferCarousel.#createRewardArrows. Centred on padY + half the card. */\n .${_e}reward-arrow {\n position: absolute;\n top: 156px;\n margin-top: -20px;\n z-index: 2;\n width: 40px;\n height: 40px;\n display: flex;\n align-items: center;\n justify-content: center;\n padding: 0;\n border: 1px solid rgba(0, 0, 0, 0.06);\n border-radius: 50%;\n background: rgba(255, 255, 255, 0.92);\n color: var(--encore-text-color);\n box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);\n cursor: pointer;\n transition:\n opacity 200ms cubic-bezier(0.4, 0, 0.2, 1),\n background 200ms cubic-bezier(0.4, 0, 0.2, 1);\n }\n\n .${_e}reward-arrow svg {\n width: 20px;\n height: 20px;\n display: block;\n }\n\n .${_e}reward-arrow-prev {\n left: 12px;\n }\n\n .${_e}reward-arrow-next {\n right: 12px;\n }\n\n .${_e}reward-arrow:hover {\n background: #ffffff;\n }\n\n .${_e}reward-arrow:focus-visible {\n outline: 2px solid var(--encore-reward-brand);\n outline-offset: 2px;\n }\n\n /* Stays in place and in the tab order: vanishing would shift layout. */\n .${_e}reward-arrow:disabled {\n opacity: 0.35;\n cursor: default;\n }\n\n /* The variant's confetti: full-bleed, inert, self-removing after 2s. */\n .${_e}reward-confetti {\n position: absolute;\n inset: 0;\n z-index: 0;\n width: 100%;\n height: 100%;\n pointer-events: none;\n }\n\n /* Reduced motion: confetti is skipped in JS; the hero becomes an instant\n state change. Selection is unaffected. */\n @media (prefers-reduced-motion: reduce) {\n .${_e}thankyou--reward .${_e}carousel-item,\n .${_e}reward-card,\n .${_e}dot,\n .${_e}reward-arrow {\n transition: none;\n }\n }\n\n /* ===== Success Screen ===== */\n .${_e}success-container {\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n padding: 3rem 2rem;\n text-align: center;\n min-height: 400px;\n animation: ${_e}fade-in 0.3s ease-out;\n }\n\n .${_e}success-icon {\n width: 80px;\n height: 80px;\n background: var(--encore-primary-color);\n border-radius: 50%;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 48px;\n color: white;\n margin-bottom: 1.5rem;\n animation: ${_e}scale-in 0.5s ease-out;\n }\n\n .${_e}success-title {\n font-size: 1.75rem;\n font-weight: 700;\n color: var(--encore-text-color);\n margin: 0 0 0.75rem 0;\n }\n\n .${_e}success-subtitle {\n font-size: 1.125rem;\n color: var(--encore-text-muted);\n margin: 0 0 2rem 0;\n line-height: 1.6;\n }\n\n .${_e}success-details {\n background: color-mix(in srgb, var(--encore-primary-color) 5%, transparent);\n border-radius: 12px;\n padding: 1.5rem;\n margin-bottom: 2rem;\n min-width: 280px;\n }\n\n .${_e}success-detail {\n display: flex;\n justify-content: space-between;\n align-items: center;\n padding: 0.5rem 0;\n }\n\n .${_e}success-detail:not(:last-child) {\n border-bottom: 1px solid rgba(0, 0, 0, 0.05);\n }\n\n .${_e}success-detail-label {\n font-size: 0.875rem;\n color: var(--encore-text-muted);\n font-weight: 500;\n }\n\n .${_e}success-detail-value {\n font-size: 1rem;\n color: var(--encore-text-color);\n font-weight: 600;\n }\n\n .${_e}success-button {\n background: var(--encore-primary-color);\n color: white;\n border: none;\n border-radius: var(--encore-border-radius);\n padding: 0.875rem 2.5rem;\n font-size: 1rem;\n font-weight: 600;\n cursor: pointer;\n transition: all 0.2s ease;\n box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1);\n }\n\n .${_e}success-button:hover {\n transform: translateY(-2px);\n box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1);\n }\n\n .${_e}success-button:active {\n transform: translateY(0);\n }\n\n .${_e}success-button:focus-visible {\n outline: 2px solid var(--encore-primary-color);\n outline-offset: 2px;\n }\n\n @keyframes ${_e}scale-in {\n from {\n transform: scale(0);\n opacity: 0;\n }\n to {\n transform: scale(1);\n opacity: 1;\n }\n }\n\n /* Referenced by the reward chrome above as well as both deferred screens. */\n @keyframes ${_e}fade-in {\n from { opacity: 0; }\n to { opacity: 1; }\n }\n\n /* ==========================================================================\n Deferred flow: primer (the hold) + redemption (the ready state), and the\n brand components both share.\n ========================================================================== */\n\n /* Shared monogram tile — the guaranteed first paint for every brand logo. */\n .${_e}brand-tile-placeholder {\n display: flex;\n align-items: center;\n justify-content: center;\n background: color-mix(in srgb, var(--encore-primary-color) 12%, var(--encore-bg-color));\n color: var(--encore-primary-color);\n font-weight: 700;\n font-size: 1.2rem;\n }\n\n /* Dual-brand lockup — two tiles settling together ("two brands, one deal"). */\n .${_e}lockup {\n display: flex;\n justify-content: center;\n align-items: center;\n margin: 0.5rem 0 1.5rem 0;\n }\n\n .${_e}lockup-tile {\n width: 56px;\n height: 56px;\n border-radius: 14px;\n object-fit: cover;\n box-shadow: 0 2px 8px color-mix(in srgb, var(--encore-text-color) 14%, transparent);\n background: var(--encore-bg-color);\n }\n\n .${_e}lockup-tile-partner {\n transform: rotate(-4deg);\n animation: ${_e}lockup-settle-left 250ms cubic-bezier(0.4, 0, 0.2, 1) forwards;\n z-index: 1;\n }\n\n .${_e}lockup-tile-host {\n margin-left: -10px;\n transform: rotate(4deg);\n animation: ${_e}lockup-settle-right 250ms cubic-bezier(0.4, 0, 0.2, 1) forwards;\n z-index: 2;\n }\n\n @keyframes ${_e}lockup-settle-left {\n from { transform: rotate(-6deg) translateX(-4px); }\n to { transform: rotate(-4deg) translateX(0); }\n }\n\n @keyframes ${_e}lockup-settle-right {\n from { transform: rotate(6deg) translateX(4px); }\n to { transform: rotate(4deg) translateX(0); }\n }\n\n /* Deal ledger — the claim state machine, rendered. */\n .${_e}ledger {\n display: flex;\n flex-direction: column;\n border: 1px solid var(--encore-border-color);\n border-radius: 16px;\n background: var(--encore-bg-color);\n box-shadow: 0 1px 3px color-mix(in srgb, var(--encore-text-color) 6%, transparent);\n text-align: left;\n overflow: hidden;\n }\n\n .${_e}ledger-row {\n display: flex;\n align-items: center;\n gap: 12px;\n padding: 14px 16px;\n }\n\n .${_e}ledger-row + .${_e}ledger-row {\n border-top: 1px solid var(--encore-border-color);\n }\n\n /* The size class is worn by BOTH forms of the tile — the monogram div and the\n image that replaces it — so it must not set a display. It is emitted after\n .brand-tile-placeholder at equal specificity, so a block display here would\n beat that rule's flex centering and un-center every monogram in a ledger\n row. Scoped to the element that actually needs it, below. */\n .${_e}ledger-logo {\n width: 44px;\n height: 44px;\n border-radius: 11px;\n object-fit: cover;\n flex-shrink: 0;\n }\n\n img.${_e}ledger-logo {\n display: block;\n }\n\n .${_e}ledger-text {\n display: flex;\n flex-direction: column;\n gap: 2px;\n flex: 1 1 auto;\n min-width: 0;\n }\n\n .${_e}ledger-name {\n font-size: 0.95rem;\n font-weight: 600;\n color: var(--encore-text-color);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n }\n\n .${_e}ledger-detail {\n font-size: 0.8rem;\n color: var(--encore-text-muted);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n }\n\n .${_e}ledger-status {\n font-size: 0.85rem;\n font-weight: 600;\n flex-shrink: 0;\n }\n\n .${_e}ledger-status-active {\n color: var(--encore-success-color);\n }\n\n .${_e}ledger-status-pending {\n color: var(--encore-text-muted);\n }\n\n /* Primer screen — centered column, one forward CTA. */\n .${_e}primer-container {\n display: flex;\n flex-direction: column;\n justify-content: center;\n max-width: 440px;\n margin: 0 auto;\n padding: 2.5rem 1.75rem 2rem;\n text-align: center;\n animation: ${_e}fade-in 0.3s ease-out;\n }\n\n .${_e}primer-title {\n font-size: 1.6rem;\n font-weight: 700;\n color: var(--encore-text-color);\n margin: 0 0 0.5rem 0;\n line-height: 1.2;\n }\n\n .${_e}primer-subtitle {\n font-size: 1.05rem;\n color: var(--encore-text-muted);\n margin: 0 0 2rem 0;\n line-height: 1.5;\n }\n\n /* Reuses .encore-button-claim (the clean pill) — full-width + prominent. */\n .${_e}primer-cta {\n width: 100%;\n height: auto;\n min-height: 50px;\n padding: 14px 24px;\n font-size: 1rem;\n font-weight: 600;\n }\n\n /* Redemption screen — the ready state shown by redeem(). */\n .${_e}redemption-container {\n display: flex;\n flex-direction: column;\n max-width: 440px;\n margin: 0 auto;\n padding: 2rem 1.75rem;\n text-align: center;\n animation: ${_e}fade-in 0.3s ease-out;\n }\n\n .${_e}redemption-title {\n font-size: 1.6rem;\n font-weight: 700;\n color: var(--encore-text-color);\n margin: 0 0 0.5rem 0;\n line-height: 1.2;\n }\n\n .${_e}redemption-subtitle {\n font-size: 1.05rem;\n color: var(--encore-text-muted);\n margin: 0 0 1.75rem 0;\n line-height: 1.5;\n }\n\n .${_e}redemption-note {\n font-size: 0.8rem;\n color: var(--encore-text-muted);\n line-height: 1.5;\n margin: 1.25rem 0;\n }\n\n .${_e}redemption-cta {\n width: 100%;\n height: auto;\n min-height: 50px;\n padding: 14px 24px;\n font-size: 1rem;\n font-weight: 600;\n }\n\n /* Mobile sheet composition for both screens. MUST stay AFTER the rules above:\n it overrides their paddings and margins, and the cascade is source order at\n equal specificity. */\n @media (max-width: ${Pe}) {\n /* Both fill the full-height sheet (modal-body is a flex column). Top padding\n clears the close button's overlay band; bottom clears the home indicator. */\n .${_e}primer-container,\n .${_e}redemption-container {\n flex: 1 1 auto;\n max-width: none;\n width: 100%;\n box-sizing: border-box;\n padding: calc(64px + env(safe-area-inset-top)) 24px\n calc(24px + env(safe-area-inset-bottom));\n }\n\n /* The content block floats centered between two flexible spaces (auto margins\n above the lockup and above the CTA); the CTA sits on the bottom edge. */\n .${_e}primer-container .${_e}lockup {\n margin-top: auto;\n }\n\n .${_e}primer-cta {\n margin-top: auto;\n }\n\n .${_e}redemption-container > :first-child {\n margin-top: auto;\n }\n\n .${_e}redemption-cta {\n margin-top: auto;\n }\n }\n `}(e),document.head.appendChild(t),h.debug("Encore styles injected successfully")}catch(e){h.error("Failed to inject Encore styles:",e)}}function Ve(e){return`${_e}${e}`}class Ke{#Ue;#Le=null;#Oe=null;#_e=null;#Pe=null;#Me=!1;#De=null;#ze=[];#Fe=null;#Be=null;#He;#Ve;#Ke;constructor(e={},t={}){this.#Ue=new me,this.#Ve=t.dismissible??!0,this.#He=(t.showCloseButton??!0)&&this.#Ve,this.#Ke=Ne(t.backgroundColor),He(e)}show(){this.#Me?h.warn("Modal is already visible"):(this.#De=document.activeElement,this.#qe(),this.#Le&&document.body.appendChild(this.#Le),this.#Oe&&document.body.appendChild(this.#Oe),document.body.classList.add(Ve("no-scroll")),requestAnimationFrame(()=>{this.#Le?.classList.add(Ve("visible")),this.#Oe?.classList.add(Ve("visible"))}),this.#je(),this.#We(),this.#Ge(),this.#Me=!0,this.#Ue.emit("show",void 0),h.debug("Modal shown"))}hide(){this.#Me&&(this.#Le?.classList.remove(Ve("visible")),this.#Oe?.classList.remove(Ve("visible")),this.#Qe(),this.#Be=setTimeout(()=>{this.#Be=null,this.#Ye()},200))}#Ye(){this.#Xe(),document.body.classList.remove(Ve("no-scroll")),this.#De instanceof HTMLElement&&this.#De.focus(),this.#Me=!1,this.#Ue.emit("hide",void 0),h.debug("Modal hidden")}#Qe(){null!==this.#Be&&(clearTimeout(this.#Be),this.#Be=null)}isVisible(){return this.#Me}setLabelledBy(e){this.#Oe?.setAttribute("aria-labelledby",e)}setContent(e){this.#Pe?(this.#Pe.innerHTML="",this.#Pe.appendChild(e),this.#We(),this.#Oe?.contains(document.activeElement)||this.#Ge()):h.error("Modal body not initialized")}on(e,t){return this.#Ue.on(e,t)}#qe(){this.#Le=document.createElement("div"),this.#Le.className=Ve("backdrop"),this.#Le.setAttribute("aria-hidden","true"),this.#Oe=document.createElement("div"),this.#Oe.className=Ve("modal"),this.#Oe.setAttribute("role","dialog"),this.#Oe.setAttribute("aria-modal","true"),this.#Oe.setAttribute("aria-labelledby",Ve("modal-title")),this.#Ke&&this.#Oe.style.setProperty("background-color",this.#Ke),this.#He&&(this.#_e=document.createElement("button"),this.#_e.className=Ve("close-button"),this.#_e.setAttribute("aria-label","Close modal"),this.#_e.innerHTML='\n <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor">\n <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />\n </svg>\n '),this.#Pe=document.createElement("div"),this.#Pe.className=Ve("modal-body"),this.#_e&&this.#Oe.appendChild(this.#_e),this.#Oe.appendChild(this.#Pe)}#Xe(){this.#Le?.remove(),this.#Oe?.remove(),this.#Le=null,this.#Oe=null,this.#_e=null,this.#Pe=null}#je(){this.#_e?.addEventListener("click",()=>{this.#Ue.emit("close",void 0),this.hide()}),this.#Ve&&this.#Le?.addEventListener("click",()=>{this.#Ue.emit("backdropClick",void 0),this.hide()}),this.#Fe=this.#Ze.bind(this),document.addEventListener("keydown",this.#Fe)}#Ze(e){if(this.#Me)switch(e.key){case"Escape":if(e.preventDefault(),!this.#Ve)break;this.#Ue.emit("close",void 0),this.hide();break;case"Tab":e.preventDefault(),this.#Je(e.shiftKey)}}#Je(e){if(0===this.#ze.length)return;const t=this.#ze.findIndex(e=>e===document.activeElement);let n;n=e?t<=0?this.#ze.length-1:t-1:t>=this.#ze.length-1?0:t+1,this.#ze[n]?.focus()}#We(){if(!this.#Oe)return;const e=['button:not([disabled]):not([tabindex="-1"])','a[href]:not([tabindex="-1"])','input:not([disabled]):not([tabindex="-1"])','select:not([disabled]):not([tabindex="-1"])','textarea:not([disabled]):not([tabindex="-1"])','[tabindex]:not([tabindex="-1"])'].join(", ");this.#ze=Array.from(this.#Oe.querySelectorAll(e))}#Ge(){this.#ze.length>0&&this.#ze[0]?.focus()}destroy(){this.#Fe&&document.removeEventListener("keydown",this.#Fe),this.#Ue.removeAllListeners(),this.#Qe(),this.#Me&&this.#Ye()}}const qe=new Set(["localhost","127.0.0.1","[::1]"]);function je(e){if(!e)return;let t;try{t=new URL(e)}catch{return}return"https:"===t.protocol||"http:"===t.protocol&&qe.has(t.hostname)?e:void 0}class We{#et=null;#tt;#ne;#Me=!1;#nt=null;#rt=null;#it=null;#ot=null;#st=null;constructor(e,t){this.#tt=e,this.#ne={position:"top",maxWidth:200,...t},this.#at()}#at(){this.#it=this.#lt.bind(this),this.#ot=this.#ct.bind(this),this.#st=this.#dt.bind(this),this.#tt.addEventListener("mouseenter",this.#it),this.#tt.addEventListener("mouseleave",this.#ot)}#lt(){this.#rt&&(clearTimeout(this.#rt),this.#rt=null),this.#nt=window.setTimeout(()=>{this.#ht()},50)}#ct(){this.#nt&&(clearTimeout(this.#nt),this.#nt=null),this.#rt=window.setTimeout(()=>{this.#ut()},100)}#ht(){if(this.#Me)return;this.#et=document.createElement("div"),this.#et.className=Ve("tooltip"),this.#et.setAttribute("role","tooltip"),this.#et.textContent=this.#ne.content,this.#ne.maxWidth&&(this.#et.style.maxWidth=`${this.#ne.maxWidth}px`),this.#ne.position&&this.#et.classList.add(Ve(`tooltip-${this.#ne.position}`));const e=this.#tt.getBoundingClientRect();this.#et.style.top=`${e.top}px`,this.#et.style.left=`${e.left}px`,document.body.appendChild(this.#et),this.#st&&(window.addEventListener("scroll",this.#st,!0),window.addEventListener("resize",this.#st)),requestAnimationFrame(()=>{requestAnimationFrame(()=>{this.#et&&(this.#dt(),this.#et.classList.add(Ve("tooltip-visible")))})}),this.#Me=!0}#ut(){this.#Me&&this.#et&&(this.#st&&(window.removeEventListener("scroll",this.#st,!0),window.removeEventListener("resize",this.#st)),this.#et.classList.remove(Ve("tooltip-visible")),setTimeout(()=>{this.#et&&this.#et.parentNode&&this.#et.parentNode.removeChild(this.#et),this.#et=null},200),this.#Me=!1)}#dt(){if(!this.#et||!this.#Me)return;const e=this.#tt.getBoundingClientRect(),t=this.#et.getBoundingClientRect();let n=0,r=0;switch(this.#ne.position??"top"){case"top":n=e.top-t.height-8,r=e.left+e.width/2-t.width/2;break;case"bottom":n=e.bottom+8,r=e.left+e.width/2-t.width/2;break;case"left":n=e.top+e.height/2-t.height/2,r=e.left-t.width-8;break;case"right":n=e.top+e.height/2-t.height/2,r=e.right+8}r=Math.max(8,Math.min(r,window.innerWidth-t.width-8)),n=Math.max(8,Math.min(n,window.innerHeight-t.height-8)),this.#et.style.top=`${n}px`,this.#et.style.left=`${r}px`}updateContent(e){this.#ne.content=e,this.#et&&(this.#et.textContent=e,this.#dt())}destroy(){this.#nt&&(clearTimeout(this.#nt),this.#nt=null),this.#rt&&(clearTimeout(this.#rt),this.#rt=null),this.#Me&&this.#ut(),this.#it&&this.#tt.removeEventListener("mouseenter",this.#it),this.#ot&&this.#tt.removeEventListener("mouseleave",this.#ot),this.#st&&(window.removeEventListener("scroll",this.#st,!0),window.removeEventListener("resize",this.#st))}}class Ge{#Ue;#pt=null;#mt=null;#ft=null;#gt=!0;constructor(e){this.#Ue=new me,this.#gt=e?.claimEnabled??!0}render(e){this.#pt=e,this.#mt=document.createElement("div"),this.#mt.className=Ve("offer-card");const t=this.#bt(e.imageUrl,e.title,e.tooltipText);this.#mt.appendChild(t);const n=this.#vt(e);return this.#mt.appendChild(n),this.#mt}on(e,t){return this.#Ue.on(e,t)}#bt(e,t,n){const r=document.createElement("div");r.className=Ve("offer-banner");const i=document.createElement("img");i.className=Ve("offer-banner-image"),i.alt=t??"Offer image";const o=je(e);o?(i.src=o,i.complete?i.classList.add(Ve("loaded")):i.onload=()=>{i.classList.add(Ve("loaded"))},i.onerror=()=>{h.warn("Failed to load offer image, using fallback"),i.src=this.#wt(),i.classList.add(Ve("loaded"))}):(i.src=this.#wt(),i.classList.add(Ve("loaded"))),r.appendChild(i);const s=document.createElement("button");return s.className=Ve("banner-info-button"),s.setAttribute("aria-label","More information"),s.innerHTML='\n <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor">\n <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" />\n </svg>\n ',s.addEventListener("click",e=>{e.preventDefault(),e.stopPropagation(),h.debug("Info button clicked for offer",{title:t,tooltipText:n})}),n&&(this.#ft=new We(s,{content:n,position:"bottom",maxWidth:200}),r.appendChild(s)),r}#wt(){return`data:image/svg+xml;base64,${btoa('\n <svg xmlns="http://www.w3.org/2000/svg" width="600" height="240" viewBox="0 0 600 240">\n <rect width="600" height="240" fill="#E5E7EB"/>\n <text x="50%" y="50%" text-anchor="middle" dy=".3em" fill="#9CA3AF" font-family="sans-serif" font-size="18">\n Offer Image\n </text>\n </svg>\n ')}`}#vt(e){const t=document.createElement("div");t.className=Ve("offer-footer");const n=document.createElement("div");n.className=Ve("offer-merchant");const r=je(e.logoUrl);if(r){const t=document.createElement("img");t.className=Ve("offer-logo"),t.src=r,t.alt=`${e.merchantName??"Merchant"} logo`,t.complete?t.classList.add(Ve("loaded")):t.onload=()=>{t.classList.add(Ve("loaded"))},t.onerror=()=>{h.warn("Failed to load merchant logo",{merchantName:e.merchantName}),t.style.display="none"},n.appendChild(t)}const i=document.createElement("div");if(i.className=Ve("offer-merchant-text"),e.merchantName){const t=document.createElement("div");t.className=Ve("offer-merchant-name"),t.textContent=e.merchantName,i.appendChild(t)}if(e.description){const t=document.createElement("div");t.className=Ve("offer-merchant-desc"),t.textContent=e.description,i.appendChild(t)}n.appendChild(i);const o=document.createElement("button");return o.className=`${Ve("button")} ${Ve("button-claim")}`,o.textContent=e.ctaText??"Claim",o.setAttribute("aria-label",`Claim offer: ${e.title??"offer"}`),this.#gt?o.addEventListener("click",()=>{this.#pt&&this.#Ue.emit("claim",{offer:this.#pt})}):(o.disabled=!0,o.setAttribute("aria-disabled","true")),t.appendChild(n),t.appendChild(o),t}destroy(){this.#ft&&(this.#ft.destroy(),this.#ft=null),this.#Ue.removeAllListeners(),this.#mt=null,this.#pt=null}}class Qe{#ne;#yt=null;#xt=!1;constructor(e={}){this.#ne=e}render(e){const t=document.createElement("div");t.className=Ve("reward-card"),this.#yt=t;const n=b(e.merchantName,e.title)??e.id;t.style.setProperty("--encore-card-tint",function(e){return we(function(e){let t=2166136261;for(let n=0;n<e.length;n+=1)t^=e.charCodeAt(n),t=Math.imul(t,16777619)>>>0;return t>>>0}(e||"encore")%360,.72,.55)}(n)),this.#It(e);const r=b(this.#ne.badgeText)??"Free trial",i=document.createElement("span");i.className=Ve("reward-card-badge"),i.textContent=r,t.appendChild(i),t.appendChild(this.#Ct(e));const o=document.createElement("div");o.className=Ve("reward-card-text");const s=document.createElement("div");s.className=Ve("reward-card-name"),s.textContent=b(e.merchantName,e.title)??"",o.appendChild(s);const a=b(e.perk,e.description);if(a){const e=document.createElement("div");e.className=Ve("reward-card-offer"),e.textContent=a,o.appendChild(e)}return t.appendChild(o),t}#Ct(e){const t=document.createElement("div");t.className=Ve("reward-card-icon");const n=b(e.merchantName,e.title)??"",r=je(e.logoUrl);if(!r)return t.appendChild(this.#kt(n)),t;const i=document.createElement("img");return i.className=Ve("reward-card-icon-image"),i.alt="",i.setAttribute("aria-hidden","true"),i.src=r,i.onerror=()=>{i.remove(),t.appendChild(this.#kt(n))},t.appendChild(i),t}#kt(e){const t=document.createElement("span");return t.className=Ve("reward-card-monogram"),t.setAttribute("aria-hidden","true"),t.textContent=(Array.from(e)[0]??"★").toUpperCase(),t}#It(e){const t=je(e.logoUrl);var n;t&&(n=t,n?new Promise(e=>{let t=!1;const r=n=>{t||(t=!0,window.clearTimeout(i),e(n))},i=window.setTimeout(()=>r(null),4e3);try{const e=new Image;e.crossOrigin="anonymous",e.onload=()=>{try{r(function(e){const t=document.createElement("canvas");t.width=fe,t.height=fe;const n=t.getContext("2d");if(!n)return null;n.drawImage(e,0,0,fe,fe);try{return function(e){let t=0,n=0,r=0,i=0;for(let o=0;o<e.length;o+=4){if((e[o+3]??0)<200)continue;const s=e[o]??0,a=e[o+1]??0,l=e[o+2]??0,c=be(s,a,l);if(c>.92||c<.1)continue;const{s:d}=ve(s,a,l);if(d<.18)continue;const h=d*d;t+=h,n+=s*h,r+=a*h,i+=l*h}if(0===t)return null;const{h:o,s:s,l:a}=ve(n/t,r/t,i/t);return we(o,s,a)}(n.getImageData(0,0,fe,fe).data)}catch{return null}}(e))}catch(e){h.debug("Brand tint sampling failed — keeping the fallback tint",e),r(null)}},e.onerror=()=>r(null),e.src=n}catch(e){h.debug("Brand tint sampling unavailable — keeping the fallback tint",e),r(null)}}):Promise.resolve(null)).then(e=>{e&&!this.#xt&&this.#yt&&this.#yt.style.setProperty("--encore-card-tint",e)})}destroy(){this.#xt=!0,this.#yt?.remove(),this.#yt=null}}let Ye=0;class Xe{#Ue;#Et;#$t=0;#mt=null;#St=null;#At=null;#Tt=null;#Rt=[];#Nt=null;#Ut=null;#Lt=null;#Ot=null;#_t=null;#Pt=0;#Mt=null;#Dt=-1;#zt=-1;#Ft;#Bt=window.matchMedia(`(max-width: ${Pe})`);#Ht=!1;#Vt=null;#Kt=null;#qt=-1;#jt=!1;#Wt=!1;#Gt=!1;#gt=!0;#Qt=[];#Yt=[];#Xt=[];#Zt="";#Jt=null;#en;#tn;constructor(e,t,n){if(this.#Ue=new me,this.#Et=e,this.#Ft=t,this.#jt="paged"===n?.mode,this.#Wt=n?.hideHeader??!1,this.#Gt=n?.selectable??!1,this.#gt=n?.claimEnabled??!0,this.#en=Ne(n?.dotColor),this.#tn=Ne(n?.dotActiveColor),this.#Zt=`${Ve("offer-option")}-${Ye+=1}-`,0===e.length)throw new Error("OfferCarousel requires at least one offer");this.#nn()}render(){if(this.#mt=document.createElement("div"),this.#mt.className=this.#jt?`${Ve("carousel")} ${Ve("carousel-paged")}`:Ve("carousel"),this.#Nt=document.createElement("div"),this.#Nt.setAttribute("role","status"),this.#Nt.setAttribute("aria-live","polite"),this.#Nt.setAttribute("aria-atomic","true"),this.#Nt.className="sr-only",this.#Nt.style.position="absolute",this.#Nt.style.width="1px",this.#Nt.style.height="1px",this.#Nt.style.padding="0",this.#Nt.style.margin="-1px",this.#Nt.style.overflow="hidden",this.#Nt.style.clip="rect(0, 0, 0, 0)",this.#Nt.style.whiteSpace="nowrap",this.#Nt.style.border="0",!this.#Wt){const e=this.#rn();this.#mt.appendChild(e)}if(this.#St=document.createElement("div"),this.#St.className=Ve("carousel-cards"),this.#Gt&&(this.#St.setAttribute("role","listbox"),this.#St.setAttribute("tabindex","0"),this.#St.setAttribute("aria-label","Choose an offer"),this.#St.classList.add(Ve("carousel-select"))),this.#mt.appendChild(this.#Nt),this.#mt.appendChild(this.#St),this.#Et.length>1){const e=this.#Gt?this.#in():this.#on();if(this.#mt.appendChild(e),this.#Gt&&!this.#Bt.matches)for(const e of this.#sn())this.#mt.appendChild(e)}return this.#an(),this.#Ht=!this.#jt&&this.#Bt.matches,this.#ln(),this.#jt||(this.#Vt=this.#cn.bind(this),this.#Bt.addEventListener("change",this.#Vt)),this.#mt}#ln(){if(this.#dn(),this.#zt=this.#$t,this.#Ht)this.#hn();else{this.#Gt?this.#un():this.#pn(),this.#mn(),this.#fn(0,!1),this.#gn(this.#$t),this.#bn(this.#$t);const e=this.#Et[this.#$t];e&&this.#Dt!==this.#$t&&(this.#Dt=this.#$t,this.#Ue.emit("offerView",{offer:e,index:this.#$t}))}}#cn(){const e=this.#Bt.matches;e!==this.#Ht&&(this.#Ht=e,this.#ln())}#dn(){this.#Ut&&(document.removeEventListener("keydown",this.#Ut),this.#Ut=null),this.#St&&this.#Jt&&(this.#St.removeEventListener("keydown",this.#Jt),this.#Jt=null),this.#St&&this.#Lt&&(this.#St.removeEventListener("scroll",this.#Lt),this.#Lt=null),this.#St&&this.#Ot&&(this.#St.removeEventListener("scrollend",this.#Ot),this.#Ot=null),null!==this.#_t&&(cancelAnimationFrame(this.#_t),this.#_t=null),this.#Mt&&(clearTimeout(this.#Mt),this.#Mt=null),this.#Kt&&(this.#Kt.disconnect(),this.#Kt=null)}#hn(){this.#St&&(this.#Kt=new IntersectionObserver(e=>{let t=null;for(const n of e){if(!n.isIntersecting)continue;const e=n.target.getAttribute("data-index");if(null===e)continue;const r=Number(e);(!t||n.intersectionRatio>t.ratio)&&(t={index:r,ratio:n.intersectionRatio})}if(!t)return;const{index:n}=t;if(n===this.#qt)return;this.#qt=n,this.#$t=n,n!==this.#zt&&(this.#zt=n,this.#Ue.emit("scroll",{axis:"vertical",position:n}));const r=this.#Et[n];r&&(this.#Ue.emit("offerView",{offer:r,index:n}),h.debug(`Offer ${n+1} entered view`))},{root:this.#St,threshold:.5}),this.#St.querySelectorAll(`.${Ve("carousel-item")}`).forEach(e=>this.#Kt?.observe(e)))}on(e,t){return this.#Ue.on(e,t)}getCurrentIndex(){return this.#$t}getTotalOffers(){return this.#Et.length}next(){const e=Math.min(this.#$t+1,this.#Et.length-1);e!==this.#$t&&(this.#$t=e,this.#gn(e),this.#fn(e),this.#vn(`Showing offer ${e+1} of ${this.#Et.length}`),h.debug(`Navigated to offer ${e+1}`))}getSelectedOffer(){return this.#Et[this.#$t]}claimSelected(){const e=this.getSelectedOffer();e?this.#Ue.emit("offerClaim",{offer:e,index:this.#$t}):h.warn("Claim requested with no selected offer — ignoring")}selectOffer(e){e<0||e>=this.#Et.length||e===this.#$t||(this.#$t=e,this.#gn(e),this.#fn(e),this.#vn(`Selected offer ${e+1} of ${this.#Et.length}`),e!==this.#zt&&(this.#zt=e,this.#Ue.emit("scroll",{axis:"horizontal",position:e})))}previous(){const e=Math.max(this.#$t-1,0);e!==this.#$t&&(this.#$t=e,this.#gn(e),this.#fn(e),this.#vn(`Showing offer ${e+1} of ${this.#Et.length}`),h.debug(`Navigated to offer ${e+1}`))}#an(){if(!this.#St)return;const e=this.#St;this.#Et.forEach((t,n)=>{let r;if(this.#Gt){const e=new Qe;r=e.render(t),this.#Yt.push(e)}else{const e=new Ge({claimEnabled:this.#gt});r=e.render(t),this.#Rt.push(e),e.on("claim",()=>{this.#Ue.emit("offerClaim",{offer:t,index:n})})}const i=document.createElement("div");i.className=Ve("carousel-item"),i.setAttribute("data-index",n.toString()),i.appendChild(r),this.#Gt&&(i.id=`${this.#Zt}${n}`,i.setAttribute("role","option"),i.setAttribute("aria-selected",String(n===this.#$t)),i.addEventListener("click",()=>this.selectOffer(n))),e.appendChild(i)}),requestAnimationFrame(()=>{e.classList.add(Ve("cards-ready"))})}#fn(e,t=!0){if(!this.#St)return;const n=this.#St.querySelectorAll(`.${Ve("carousel-item")}`)[e];if(n){if(this.#Gt){const e=this.#St,r=n.getBoundingClientRect(),i=e.getBoundingClientRect(),o=e.scrollLeft+(r.left+r.width/2-(i.left+i.width/2));return void("function"==typeof e.scrollTo?e.scrollTo({left:o,behavior:t?"smooth":"auto"}):e.scrollLeft=o)}n.scrollIntoView({behavior:t?"smooth":"auto",block:"nearest",inline:"center"})}}#gn(e){this.#wn(),this.#yn(e),this.#xn(e)}#xn(e){if(!this.#Gt||!this.#St)return;const t=this.#St.querySelectorAll(`.${Ve("carousel-item")}`);t.forEach((t,n)=>t.setAttribute("aria-selected",String(n===e)));const n=t[e]?.id;n?this.#St.setAttribute("aria-activedescendant",n):this.#St.removeAttribute("aria-activedescendant"),this.#Qt.forEach((t,n)=>t.classList.toggle(Ve("active"),n===e)),this.#In(e);const r=this.#Et[e];r&&this.#Ue.emit("offerSelect",{offer:r,index:e})}#in(){const e=document.createElement("div");return e.className=Ve("page-indicator"),e.setAttribute("aria-hidden","true"),this.#en&&e.style.setProperty("--encore-dot-color",this.#en),this.#tn&&e.style.setProperty("--encore-dot-active-color",this.#tn),this.#Qt=this.#Et.map((t,n)=>{const r=document.createElement("span");return r.className=n===this.#$t?`${Ve("dot")} ${Ve("active")}`:Ve("dot"),e.appendChild(r),r}),e}#sn(){const e=(e,t,n,r)=>{const i=document.createElement("button");return i.type="button",i.className=`${Ve("reward-arrow")} ${Ve(`reward-arrow-${e}`)}`,i.setAttribute("aria-label",t),i.innerHTML=`<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.25" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="${n}" /></svg>`,i.addEventListener("click",r),i};return this.#Xt=[e("prev","Previous offer","M14.5 5.5L8 12l6.5 6.5",()=>this.selectOffer(this.#$t-1)),e("next","Next offer","M9.5 5.5L16 12l-6.5 6.5",()=>this.selectOffer(this.#$t+1))],this.#In(this.#$t),this.#Xt}#In(e){const[t,n]=this.#Xt;t&&(t.disabled=0===e,t.classList.toggle(Ve("disabled"),t.disabled)),n&&(n.disabled=e===this.#Et.length-1,n.classList.toggle(Ve("disabled"),n.disabled))}#un(){this.#St&&(this.#Jt=e=>{let t=null;switch(e.key){case"ArrowLeft":case"ArrowUp":t=this.#$t-1;break;case"ArrowRight":case"ArrowDown":t=this.#$t+1;break;case"Home":t=0;break;case"End":t=this.#Et.length-1;break;default:return}e.preventDefault(),this.selectOffer(Math.max(0,Math.min(t,this.#Et.length-1)))},this.#St.addEventListener("keydown",this.#Jt))}#bn(e){this.#St&&(this.#Pt=e,this.#St.querySelectorAll(`.${Ve("carousel-item")}`).forEach((t,n)=>{n===e?t.classList.add(Ve("active")):t.classList.remove(Ve("active"))}))}#rn(){const e=document.createElement("div");e.className=Ve("carousel-header");const t=document.createElement("h2");t.className=Ve("carousel-title"),t.id=Ve("modal-title"),t.textContent=this.#Ft?.customHeadline??this.#Ft?.titleText??"Unlock 10 free articles – choose an offer below";const n=document.createElement("p");return n.className=Ve("carousel-subtitle"),n.textContent=this.#Cn(this.#$t),this.#At=n,e.appendChild(t),e.appendChild(n),e}#Cn(e){const t=this.#Ft?.customSubheadline??this.#Ft?.subtitleText??"";if(!this.#jt)return t;const n=this.#Et[e]?.perk?.trim();return n||t}#yn(e){if(!this.#jt||!this.#At)return;const t=this.#Cn(e);this.#At.textContent!==t&&(this.#At.textContent=t)}#on(){const e=document.createElement("div");e.className=Ve("carousel-navigation");const t=document.createElement("button");t.className=Ve("nav-button"),t.setAttribute("aria-label","Previous offer"),t.innerHTML=this.#jt?'\n <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.25" stroke-linecap="round" stroke-linejoin="round">\n <path d="M14.5 5.5L8 12l6.5 6.5" />\n </svg>\n ':'\n <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor" style="transform: rotate(90deg);">\n <path stroke-linecap="round" stroke-linejoin="round" d="M19 9l-7 7-7-7" />\n </svg>\n ',t.addEventListener("click",()=>this.previous());const n=document.createElement("button");return n.className=Ve("nav-button"),n.setAttribute("aria-label","Next offer"),n.innerHTML=this.#jt?'\n <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.25" stroke-linecap="round" stroke-linejoin="round">\n <path d="M9.5 5.5L16 12l-6.5 6.5" />\n </svg>\n ':'\n <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor" style="transform: rotate(270deg);">\n <path stroke-linecap="round" stroke-linejoin="round" d="M19 9l-7 7-7-7" />\n </svg>\n ',n.addEventListener("click",()=>this.next()),e.appendChild(t),e.appendChild(n),this.#Tt=e,this.#wn(t,n),e}#wn(e,t){if(!this.#Tt)return;const n=this.#Tt.querySelectorAll(`.${Ve("nav-button")}`),r=e??n[0],i=t??n[1];r&&(r.disabled=0===this.#$t,r.classList.toggle(Ve("disabled"),0===this.#$t)),i&&(i.disabled=this.#$t===this.#Et.length-1,i.classList.toggle(Ve("disabled"),this.#$t===this.#Et.length-1))}#pn(){this.#Ut=this.#kn.bind(this),document.addEventListener("keydown",this.#Ut)}#kn(e){if(this.#mt)switch(e.key){case"ArrowLeft":e.preventDefault(),this.previous();break;case"ArrowRight":e.preventDefault(),this.next()}}#mn(){if(!this.#St)return;const e=this.#St,t="onscrollend"in e;this.#Lt=()=>{null===this.#_t&&(this.#_t=window.requestAnimationFrame(()=>{this.#_t=null,this.#En()})),t||(this.#Mt&&clearTimeout(this.#Mt),this.#Mt=window.setTimeout(()=>this.#$n(),120))},e.addEventListener("scroll",this.#Lt),t&&(this.#Ot=()=>this.#$n(),e.addEventListener("scrollend",this.#Ot))}#Sn(){if(!this.#St)return this.#$t;const e=this.#St,t=e.querySelectorAll(`.${Ve("carousel-item")}`),n=e.getBoundingClientRect(),r=n.left+n.width/2;let i=0,o=1/0;return t.forEach((e,t)=>{const n=e.getBoundingClientRect(),s=Math.abs(r-(n.left+n.width/2));s<o&&(o=s,i=t)}),i}#En(){if(!this.#St)return;const e=this.#Sn();e!==this.#Pt&&this.#bn(e)}#$n(){this.#Mt&&(clearTimeout(this.#Mt),this.#Mt=null);const e=this.#Sn();e!==this.#$t&&(this.#$t=e,this.#gn(e),h.debug(`Gesture settled on offer ${e+1}`)),this.#bn(e),e!==this.#zt&&(this.#zt=e,this.#Ue.emit("scroll",{axis:"horizontal",position:e}));const t=this.#$t;if(t===this.#Dt)return;const n=this.#Et[t];n&&(this.#Dt=t,this.#Ue.emit("offerView",{offer:n,index:t}))}#vn(e){this.#Nt&&(this.#Nt.textContent=e)}#nn(){this.#Et.forEach(e=>{e.imageUrl&&((new Image).src=e.imageUrl,h.debug("Preloading offer image",{offerId:e.id,url:e.imageUrl})),e.logoUrl&&((new Image).src=e.logoUrl,h.debug("Preloading merchant logo",{offerId:e.id,url:e.logoUrl}))})}destroy(){this.#dn(),this.#Vt&&(this.#Bt.removeEventListener("change",this.#Vt),this.#Vt=null),this.#Rt.forEach(e=>e.destroy()),this.#Rt=[],this.#Yt.forEach(e=>e.destroy()),this.#Yt=[],this.#Xt=[],this.#Ue.removeAllListeners(),this.#mt=null,this.#St=null,this.#At=null,this.#Tt=null,this.#Nt=null,this.#Qt=[]}}function Ze(e,t,n,r=!1){const i=document.createElement("div");i.className=`${t} ${Ve("brand-tile-placeholder")}`;const o=e.name?.trim().charAt(0);i.textContent=o?o.toUpperCase():"★",r&&i.setAttribute("aria-hidden","true");const s=je(e.logoUrl);if(s){const o=document.createElement("img");o.className=t,o.alt=r?"":e.name?`${e.name} logo`:"Brand logo",r&&o.setAttribute("aria-hidden","true"),o.width=n,o.height=n,o.decoding="async",o.addEventListener("load",()=>i.replaceWith(o)),o.src=s}return i}function Je(e,t){const n=document.createElement("div");n.className=Ve("lockup"),n.setAttribute("aria-hidden","true");const r=Ze(e,`${Ve("lockup-tile")} ${Ve("lockup-tile-partner")}`,56);return n.appendChild(r),(t.name||t.logoUrl)&&n.appendChild(Ze(t,`${Ve("lockup-tile")} ${Ve("lockup-tile-host")}`,56)),n}function et(e){const t=document.createElement("div");return t.className=Ve("ledger"),e.forEach(e=>t.appendChild(function(e){const t=document.createElement("div");t.className=Ve("ledger-row");const n=Ze(e.brand,Ve("ledger-logo"),44,!0),r=document.createElement("div");r.className=Ve("ledger-text");const i=document.createElement("div");if(i.className=Ve("ledger-name"),i.textContent=e.name,r.appendChild(i),e.detail){const t=document.createElement("div");t.className=Ve("ledger-detail"),t.textContent=e.detail,r.appendChild(t)}const o=document.createElement("div");return o.className=`${Ve("ledger-status")} ${Ve(`ledger-status-${e.status.tone}`)}`,o.textContent=e.status.text,t.appendChild(n),t.appendChild(r),t.appendChild(o),t}(e))),t}function tt(e,t,n){const r=document.createElement("button");return r.className=`encore-button-claim ${t}`,r.setAttribute("type","button"),r.textContent=e,r.addEventListener("click",n),r}class nt{#mt=null;#Ue;#n;constructor(e){this.#n=e,this.#Ue=new me}render(){const{display:e,partner:t}=this.#n,n=e.appDisplayName,r="activation"===this.#n.variant&&n?"activation":"holding",i=document.createElement("div");i.className=Ve("primer-container");const o=t.logoUrl??t.imageUrl,s=Je({...t.name&&{name:t.name},...o&&{logoUrl:o}},{...n&&{name:n},...e.logoUrl&&{logoUrl:e.logoUrl}}),a=document.createElement("h2");var l,c;a.className=Ve("primer-title"),a.id=Ve("modal-title"),a.textContent="activation"===r&&n?(l=n,(c=e.trialPeriod)?`Amazing! Your ${c} free trial of ${l} is ready`:`Amazing! Your ${l} reward is ready`):"Your reward is saved";const d=document.createElement("p");var u;d.className=Ve("primer-subtitle"),d.textContent="activation"===r&&n?(e=>`Next you'll see the ${e} activation screen. No charge today.`)(n):(u=t.name)?`Come back any time to claim it from ${u}. No charge today.`:"Come back any time to claim it. No charge today.";const p=tt("activation"===r&&n?((e,t)=>t?`Activate ${e} trial`:`Continue to ${e}`)(n,e.trialPeriod):"Continue",Ve("primer-cta"),()=>{h.debug("User tapped the primer CTA"),this.#Ue.emit("continue",void 0)});return i.appendChild(s),i.appendChild(a),i.appendChild(d),i.appendChild(p),this.#mt=i,h.debug("Primer screen rendered",{variant:r}),i}on(e,t){return this.#Ue.on(e,t)}destroy(){this.#mt&&(this.#mt.remove(),this.#mt=null),this.#Ue.removeAllListeners(),h.debug("Primer screen destroyed")}}const rt=e=>({...e.advertiserName&&{name:e.advertiserName},...(e.logoUrl??e.imageUrl)&&{logoUrl:e.logoUrl??e.imageUrl}}),it=e=>({brand:rt(e),name:e.advertiserName??"Your reward",...e.reward&&{detail:e.reward},status:{text:"Pending",tone:"pending"}}),ot=e=>{const t=document.createElement("h2");return t.className=Ve("redemption-title"),t.id=Ve("modal-title"),t.textContent=e,t},st=e=>{const t=document.createElement("p");return t.className=Ve("redemption-subtitle"),t.textContent=e,t},at={activation(e){const t=e.host??{},n=t.name??"your app",r=[{brand:{name:n,...t.logoUrl&&{logoUrl:t.logoUrl}},name:n,...t.detail&&{detail:t.detail},status:{text:t.status??"Active",tone:"active"}},it(e)];return[Je(rt(e),{name:n,...t.logoUrl&&{logoUrl:t.logoUrl}}),ot((i=n,o=t.trialPeriod,o?`Congratulations! Your ${o} free trial is active.`:`Congratulations! Your ${i} plan is active.`)),st(q(n)),et(r)];var i,o},reward:e=>[ot("Congratulations!"),st(e.reward?`Now claim your ${e.reward}`:"Now claim your reward"),et([it(e)])]};class lt{#mt=null;#Ue;#n;constructor(e){this.#n=e,this.#Ue=new me}render(){const{advertiserName:e,buttonText:t}=this.#n,n=this.#n.variant??"reward",r=Object.prototype.hasOwnProperty.call(at,n)?n:"reward",i=document.createElement("div");i.className=Ve("redemption-container");for(const e of at[r](this.#n))i.appendChild(e);const o=document.createElement("p");o.className=Ve("redemption-note"),o.textContent=e?`You'll be sent to ${e}. No payment now, cancel anytime.`:"No payment now, cancel anytime.";const s=tt(t??"Claim your reward",Ve("redemption-cta"),()=>{h.debug("User tapped the redemption CTA"),this.#Ue.emit("continue",void 0)});return i.appendChild(o),i.appendChild(s),this.#mt=i,h.debug("Redemption screen rendered",{variant:r}),i}on(e,t){return this.#Ue.on(e,t)}destroy(){this.#mt&&(this.#mt.remove(),this.#mt=null),this.#Ue.removeAllListeners(),h.debug("Redemption screen destroyed")}}function ct(e){return"object"==typeof e&&null!==e&&(1===e.nodeType&&"string"==typeof e.nodeName&&"function"==typeof e.setAttribute&&"function"==typeof e.cloneNode&&"function"==typeof e.querySelectorAll)}function dt(e,t){return null==e?null:"function"==typeof e?function(e,t){try{const n=e(t);return null==n?null:ct(n)?n:(h.warn("[Encore SDK] Appearance renderer returned a non-element — using the default"),null)}catch(e){return h.warn("[Encore SDK] Appearance renderer threw — using the default",{error:e}),null}}(e,t):ct(e)?e:null}function ht(e){if(null!=e&&"function"!=typeof e&&!ct(e))return e}function ut(e,t,n){void 0!==n&&e.style.setProperty(t,n)}function pt(e,t){ut(e,"color",Ne(t.color)),ut(e,"font-family",Ue(t.fontFamily)),ut(e,"font-size",Le(t.fontSize)),ut(e,"font-weight",function(e){if(null==e)return;if("number"==typeof e)return Number.isInteger(e)&&e>=1&&e<=1e3?String(e):Te("font-weight",e);const t=Re(e);if(void 0===t)return;if(null===t)return Te("font-weight",e);if($e.test(t))return t;const n=Number(t);return Number.isInteger(n)&&n>=1&&n<=1e3?t:Te("font-weight",e)}(t.fontWeight)),ut(e,"letter-spacing",Le(t.letterSpacing)),ut(e,"text-align",function(e){const t=Re(e);if(void 0!==t)return null===t?Te("text-align",e):Se.has(t.toLowerCase())?t.toLowerCase():Te("text-align",e)}(t.textAlign))}function mt(e){return"string"==typeof e?.text?b(e.text):void 0}function ft(e,t,n,r){if(null==r)return e;const i=dt(r,{text:t,useCase:n,defaultElement:e});if(i)return i===e?e:vt(e,i,Ve("slot-custom"))?(!e.textContent?.trim()&&t&&e.setAttribute("aria-label",t),e):e;const o=ht(r);if(o){const t=mt(o);t&&(e.textContent=t),pt(e,o)}return e}function gt(e){return mt(ht(e))}function bt(e){const{className:t,label:n,onActivate:r,useCase:i,slot:o}=e,s=!1!==e.enabled,a=document.createElement("button");a.type="button",a.className=t,a.textContent=n;const l=()=>{const e=new AbortController;return s?a.addEventListener("click",r,{signal:e.signal}):(a.disabled=!0,a.setAttribute("aria-disabled","true")),{element:a,setAccessibleName:e=>yt(a,e),destroy:()=>e.abort()}},c=dt(o,{text:n,useCase:i,defaultElement:a});if(!c||c===a){const e=ht(o);if(e){const t=mt(e);t&&(a.textContent=t),function(e,t){pt(e,t),ut(e,"background-color",Ne(t.backgroundColor)),ut(e,"border-radius",Le(t.borderRadius));const n=Ne(t.borderColor);void 0!==n&&(e.style.setProperty("border-color",n),e.style.setProperty("border-style","solid"))}(a,e)}return l()}const d=document.createElement("div");if(d.className=`${t} ${Ve("slot-host")}`,d.setAttribute("role","button"),d.tabIndex=s?0:-1,s||d.setAttribute("aria-disabled","true"),function(e){try{e.style.setProperty("pointer-events","none");const t=[e,...Array.from(e.querySelectorAll(wt))];for(const e of t)e.setAttribute("tabindex","-1")}catch(e){h.warn("[Encore SDK] Could not neutralize a custom appearance element",{error:e})}}(c),!vt(d,c))return l();d.textContent?.trim()||d.setAttribute("aria-label",n);const u=new AbortController,p=e=>{e.preventDefault(),e.stopImmediatePropagation(),r()};return s&&(d.addEventListener("click",p,{capture:!0,signal:u.signal}),d.addEventListener("keydown",e=>{"Enter"!==e.key&&" "!==e.key&&"Spacebar"!==e.key||p(e)},{capture:!0,signal:u.signal})),{element:d,setAccessibleName:e=>yt(d,e,n),destroy:()=>{u.abort(),c.remove()}}}function vt(e,t,n){if(!0===t.parentElement?.classList.contains(Ve("slot-host")))return h.warn("[Encore SDK] The same element was supplied to more than one appearance slot — using the default for this one. Supply a separate element, or a renderer."),!1;const r=e.textContent;try{return e.textContent="",n&&e.classList.add(n),e.appendChild(t),!0}catch(t){return h.warn("[Encore SDK] Could not mount a custom appearance element",{error:t}),n&&e.classList.remove(n),e.textContent=r,!1}}const wt='a[href], button, input, select, textarea, iframe, [tabindex], [contenteditable="true"]';function yt(e,t,n){t?e.setAttribute("aria-label",t):n?e.setAttribute("aria-label",n):e.removeAttribute("aria-label")}const xt=Ve("thankyou-title"),It="Claim gift";class Ct{#ne;#yt=null;#An=null;#Tn=null;#Rn;constructor(e){this.#ne=e}render(){const e=document.createElement("div");e.className=Ve("reward-actions");const t=this.#ne.trustText?.trim(),n=document.createElement("p");n.className=Ve("reward-trust"),n.textContent=t&&t.length>0?t:"No charges until trial ends, cancel anytime.",e.appendChild(n);const r=document.createElement("div");r.className=Ve("reward-cta-stack");const i=this.#ne.useCase??"rewardUsers",o=bt({className:Ve("reward-cta-primary"),label:It,onActivate:()=>this.#ne.onClaim(),enabled:!1!==this.#ne.claimEnabled,useCase:i,...this.#ne.claimSlot&&{slot:this.#ne.claimSlot}});r.appendChild(o.element),this.#An=o,this.#Nn();const s=this.#ne.secondary??"decline";if("none"!==s){const e="next"===s,t=bt({className:Ve("reward-cta-secondary"),label:e?"Next offer":"No thanks",onActivate:()=>e?this.#ne.onNext?.():this.#ne.onDecline(),useCase:i,...!e&&this.#ne.declineSlot&&{slot:this.#ne.declineSlot}});r.appendChild(t.element),this.#Tn=t}return e.appendChild(r),this.#yt=e,e}setSelectedOffer(e){this.#Rn=e,this.#Nn()}#Nn(){if(!this.#An)return;const e=this.#Rn?.trim();this.#An.setAccessibleName(e?`${It} from ${e}`:void 0)}destroy(){this.#An?.destroy(),this.#Tn?.destroy(),this.#yt?.remove(),this.#yt=null,this.#An=null,this.#Tn=null}}const kt=["#B728F5","#6515ED","#FF9F2B","#22C55E","#38BDF8","#F43F5E"];function Et(e,t){return e+Math.random()*(t-e)}class $t{#Un=null;#Ln=null;#On=[];#_n=null;#Pn=0;#Mn=0;#xt=!1;static shouldSkip(){try{return window.matchMedia("(prefers-reduced-motion: reduce)").matches}catch{return!1}}start(e){if(!this.#xt&&!$t.shouldSkip())try{const t=e.getBoundingClientRect(),n=Math.round(t.width),r=Math.round(t.height);if(n<1||r<1)return;const i=document.createElement("canvas");i.className=Ve("reward-confetti"),i.setAttribute("aria-hidden","true");const o=i.getContext("2d");if(!o)return;e.appendChild(i),this.#Un=i,this.#Ln=o,this.#Dn(n,r),this.#zn(),this.#Pn=performance.now(),this.#Mn=this.#Pn,this.#_n=requestAnimationFrame(this.#Fn)}catch(e){h.debug("Confetti unavailable — rendering the sheet without it",e),this.destroy()}}#Dn(e,t){const n=this.#Un,r=this.#Ln;if(!n||!r)return;const i=Math.min(2,window.devicePixelRatio||1);n.width=e*i,n.height=t*i,r.scale(i,i)}#zn(){const e=this.#Un;if(!e)return;const t=Math.min(2,window.devicePixelRatio||1),n=e.width/t,r=e.height/t;this.#On=Array.from({length:22},()=>{const e=Et(6,11);return{x:Et(0,n)+Et(-46,46),y:0*r+Et(.15*-r,.3*r),vx:Et(-46,46),vy:Et(40,160),w:e,h:e*Et(.4,.7),rotation:Et(0,2*Math.PI),spin:Et(-4,4),color:kt[Math.floor(Et(0,kt.length))]??"#B728F5"}})}#Fn=e=>{if(this.#xt)return;const t=this.#Un,n=this.#Ln;if(!t||!n)return;const r=e-this.#Pn,i=Math.min(.05,(e-this.#Mn)/1e3);if(this.#Mn=e,r>=2e3)return void this.destroy();const o=Math.min(2,window.devicePixelRatio||1),s=t.height/o;n.clearRect(0,0,t.width/o,s);const a=r/2e3;n.globalAlpha=a<.66?1:Math.max(0,1-(a-.66)/.34);for(const e of this.#On)e.vy+=320*i,e.vx*=Math.pow(.86,i),e.x+=e.vx*i,e.y+=e.vy*i,e.rotation+=e.spin*i,e.y-e.h>s||(n.save(),n.translate(e.x,e.y),n.rotate(e.rotation),n.fillStyle=e.color,n.fillRect(-e.w/2,-e.h/2,e.w,e.h),n.restore());this.#_n=requestAnimationFrame(this.#Fn)};destroy(){this.#xt=!0,null!==this.#_n&&(cancelAnimationFrame(this.#_n),this.#_n=null),this.#Un?.remove(),this.#Un=null,this.#Ln=null,this.#On=[]}}class St{#Bn=null;#Hn=null;#Vn=!1;start(e){this.#Vn?h.warn("FocusDetector already active"):(this.#Bn=()=>{h.debug("Window focused"),e()},this.#Hn=()=>{"visible"===document.visibilityState&&(h.debug("Document became visible"),e())},window.addEventListener("focus",this.#Bn),document.addEventListener("visibilitychange",this.#Hn),this.#Vn=!0,h.debug("FocusDetector started"))}stop(){this.#Vn&&(this.#Bn&&(window.removeEventListener("focus",this.#Bn),this.#Bn=null),this.#Hn&&(document.removeEventListener("visibilitychange",this.#Hn),this.#Hn=null),this.#Vn=!1,h.debug("FocusDetector stopped"))}isActive(){return this.#Vn}}const At="user_id",Tt="user_attributes";function Rt(e){const t=e.useCase;if(void 0===t||a(t))return e;const n="string"==typeof t?o(t):void 0,{useCase:r,...i}=e;return n?{...i,useCase:n}:i}function Nt(e){const t=e?.values?.text;return!!t&&Object.keys(t).length>0}function Ut(e){return"reduceChurn"===(e??"reduceChurn")}const Lt=new class{#Kn;#p;#m=null;#k=null;#qn=null;#jn=null;#Wn=null;#Gn=null;#Qn=null;#Yn=new Set;#Ue;#Xn=null;#f=null;#Zn={};#Jn=!1;#er=!1;#gt=!0;#tr={};#nr;#rr={};#ir;#or={};#sr={};#ar=new Set;#lr=new Set;#cr=null;#dr=null;#hr;#ur;constructor(){var e;this.#Kn=new u,this.#p=new m,this.#hr=new V((e=this.#p,{read:()=>e.get(z),write:t=>e.set(z,t)})),this.#ur=new V(function(){let e=null;return{read:()=>e,write:t=>{e=t}}}()),this.#Ue=new me}configure(e){const t=this.#Kn.configure(e);if(t){this.#pr();const e=this.#Kn.getBaseURL(),t=this.#Kn.getAnalyticsBaseURL(),n=this.#Kn.getApiKey()??"";if(e){if(this.#m=new X(n,e),t){if(this.#k=new re(n,t,this.#p),!this.#Wn){const e=new ce(n,t,this.#p);this.#Wn=new ae(this.#p,()=>this.#f,e),e.flush()}this.#Xn||(this.#Xn=new de(n,t,this.#p),this.#Xn.flush())}this.#f&&(this.#qn=new g(this.#p,this.#m,this.#f),this.#Qn="strict"===this.#Kn.getUnlockMode()?new O(this.#p,this.#m,this.#f):null,this.#jn?.destroy(),this.#jn=new A(this.#m,this.#f,this.#k??void 0)),this.#Gn=new St}if(h.info("Encore SDK initialized successfully",{version:W}),this.#k&&this.#f){const e="undefined"!=typeof window?window.location.hostname:"unknown";this.#k.track(function(e,t,n){return{name:"sdk_initialized",distinctId:e,properties:{sdkVersion:W,appBundleId:n,platform:"web"}}}(this.#f,0,e))}this.#m&&this.#f&&this.#m.initUser(this.#f).catch(e=>{h.warn("Failed to init user on backend (non-blocking)",e),this.#mr("api_request",e)}),this.#fr(),this.#gr()}return t}#pr(){const e=this.#p.get(At);e?(this.#f=e,h.debug("Loaded existing user ID:",e)):(this.#f=S(),this.#p.set(At,this.#f),h.debug("Generated new user ID:",this.#f));const t=this.#p.get(Tt);t&&(this.#Zn=t,h.debug("Loaded user attributes"))}#br(){return!!this.#Kn.isConfigured()||(h.error("SDK not configured. Call Encore.configure() first."),!1)}identify(e,t){if(!this.#br())return;if(!e||"string"!=typeof e)return void h.error("identify() requires a valid user ID string");const n=this.#f;if(this.#f=e,this.#p.set(At,e),t&&this.setUserAttributes(t),n!==e&&(h.info("User identified:",e),this.#qn&&this.#qn.setUserId(e),this.#jn&&this.#jn.setUserId(e),this.#Qn?.setUserId(e),this.#m&&n&&this.#m.identifyUser(n,e,t?.email?{email:t.email}:void 0).catch(e=>{h.warn("Failed to identify user on backend (non-blocking)",e),this.#mr("api_request",e)}),this.#k)){const n="undefined"!=typeof window?window.location.hostname:"unknown";this.#k.track(function(e,t,n,r){return{name:"user_identified",distinctId:e,properties:{userId:t,appBundleId:n,...r&&{attributes:r}}}}(e,e,n,t))}}getCurrentUserId(){return this.#f}getAppAccountId(){return this.#f}reset(){this.#br()&&(h.info("Resetting SDK"),this.#p.clear(),this.#f=S(),this.#p.set(At,this.#f),this.#Zn={},this.#tr={},this.#or={},this.#rr={},this.#ir=void 0,this.#ur.clear(),this.#sr={},this.#ar.clear(),this.#cr=null,this.#qn&&(this.#qn.clearQueue(),this.#qn.destroy(),this.#m&&this.#f&&(this.#qn=new g(this.#p,this.#m,this.#f))),this.#f&&this.#Qn?.setUserId(this.#f),this.#jn&&(this.#jn.clearCache(),this.#jn.destroy(),this.#m&&this.#f&&(this.#jn=new A(this.#m,this.#f,this.#k??void 0))),this.#Gn?.isActive()&&this.#Gn.stop(),this.#gr(),this.#dr?.(),this.#dr=null,h.debug("SDK reset complete",{newUserId:this.#f}))}getVersion(){return W}get isClaimEnabled(){return this.#gt}set isClaimEnabled(e){this.#gt=e,h.debug("Claim enablement changed",{isClaimEnabled:e})}isConfigured(){return this.#Kn.isConfigured()}getConfiguration(){return this.#Kn.isConfigured()?{apiKey:this.#Kn.getApiKey()??"",environment:this.#Kn.getEnvironment()??"",baseURL:this.#Kn.getBaseURL()??"",analyticsBaseURL:this.#Kn.getAnalyticsBaseURL()??"",logLevel:this.#Kn.getConfig()?.logLevel??"none"}:null}async getExperimentState(){return this.#Kn.isConfigured()&&this.#Wn?this.#Wn.getState():null}setLogLevel(e){h.setLogLevel(e)}async revokeEntitlements(){if(!this.#br())return!1;if(!this.#m||!this.#f)return!1;try{return await this.#m.revokeEntitlements(this.#f)}catch(e){return h.error("Failed to revoke entitlements",e),!1}}setUserAttributes(e){this.#br()&&(e&&"object"==typeof e?(this.#Zn={...this.#Zn,...e,custom:{...this.#Zn.custom,...e.custom}},this.#p.set(Tt,this.#Zn),h.debug("User attributes updated",this.#Zn)):h.error("setUserAttributes() requires a valid UserAttributes object"))}getUserAttributes(){return{...this.#Zn}}async show(e,t,n){const{result:r,...i}=await this.#vr(e,t,n);return this.#wr(r,i,t,n),r}async#vr(t,n,i){const o=S(),l=(c=n?.useCase,a(c)?c:"reduceChurn");var c;if(this.#yr(o,l,i),!this.#br()){const n="notConfigured";return t?.onNotGranted?.(n),t?.onError?.({code:e.INITIALIZATION_ERROR,message:"SDK not configured"}),this.#xr("not_configured",o,l,i),{result:{status:"dismissed",reason:n},presentationId:o}}const d=function(t){return void 0===t||r.includes(t)?null:{code:e.INVALID_REQUEST,message:`useCase ${s(t)} is not a recognised Encore use case — nothing was presented. Supported values: ${r.map(e=>`'${e}'`).join(", ")}.`,details:{useCase:t}}}(n?.useCase);if(d){h.error(`[Encore SDK] Integration error: ${d.message}`),this.#mr("configuration",new Error(d.message));const e={type:"error",error:d};return t?.onNotGranted?.(e),t?.onError?.(d),{result:{status:"dismissed",reason:e},presentationId:o}}if(this.#er){h.warn("show() called while already presenting, ignoring duplicate request");const e="alreadyPresenting";return t?.onNotGranted?.(e),this.#xr("already_presenting",o,l,i),{result:{status:"dismissed",reason:e},presentationId:o}}this.#er=!0;try{const e=await this.#Ir(o,n,i),r=e.result;return"claimed"===r.status?t?.onGranted?.(void 0):"dismissed"===r.status&&r.reason&&t?.onNotGranted?.(r.reason),e}catch(n){h.error("Error during show",n),this.#mr("present_offer_initialization",n);const r={type:"error",error:{code:e.UNKNOWN_ERROR,message:n instanceof Error?n.message:"Unknown error"}};return t?.onError?.(r.error),t?.onNotGranted?.(r),{result:{status:"dismissed",reason:r},presentationId:o,override:{notPresentedReason:"error.unknown_error"}}}finally{this.#er=!1}}#yr(e,t,n){var r;this.#Xn&&this.#f&&this.#Xn.enqueue({name:"sdk_show_entered",distinctId:this.#f,properties:{layer:"web",presentationId:(r={presentationId:e,useCase:t,...void 0!==n&&{placementId:n}}).presentationId,use_case:i(r.useCase),...I(r.placementId)}},S())}#xr(e,t,n,r,o){var s;this.#Xn&&this.#f&&this.#Xn.enqueue({name:"sdk_show_aborted",distinctId:this.#f,properties:{layer:"web",reason:(s={reason:e,presentationId:t,useCase:n,...void 0!==r&&{placementId:r},...void 0!==o&&{variantId:o}}).reason,presentationId:s.presentationId,use_case:i(s.useCase),...I(s.placementId),...void 0!==s.variantId&&{variantId:s.variantId}}},S())}#wr(e,t,n,r){if(!this.#Xn||!this.#f)return;const o=t.presentationId,s={...void 0!==r&&{placementId:r},presentationId:o,useCase:i(n?.useCase??"reduceChurn"),unlockMode:this.#Kn.getUnlockMode(),...void 0!==t.variantId&&{variantId:t.variantId},...pe(e,t.override)};this.#Xn.enqueue(function(e,t){const{placementId:n,...r}=t,i=v(n);return{name:"sdk_placement_resolved",distinctId:e,properties:{...r,...i&&{placementId:i}}}}(this.#f,s),o)}async presentOffer(e,t){const n=await this.show(e,t);switch(n.status){case"unavailable":return{granted:!1,reason:"noOffersAvailable"};case"dismissed":return{granted:!1,...n.reason&&{reason:n.reason}};case"claimed":return{granted:!0}}}async redeem(t){if(!this.#br())return{status:"dismissed",reason:{type:"error",error:{code:e.INITIALIZATION_ERROR,message:"SDK not configured"}}};const n=this.#Cr(t?.placement);if(n&&"rewardUsers"!==n.transaction.useCase&&!t?.host?.name&&await this.#kr(),!n)return h.info("redeem(): nothing pending to redeem"),{status:"unavailable"};const{transaction:r,store:i}=n;let o=null;try{this.#Jn||(He({}),this.#Jn=!0),o=new Ke;const n=o;return await new Promise(o=>{let s=!1;const a=e=>{s||(s=!0,o(e))};n.on("close",()=>a({status:"dismissed"})),n.on("backdropClick",()=>{n.hide(),a({status:"dismissed"})}),n.on("hide",()=>a({status:"dismissed"})),n.show(),this.#Er(n,r,t?.host,()=>{const t=this.#$r(),o=this.#Sr(r.useCase),s=r.useCase??"reduceChurn";if(this.#Ar(e=>$(e,{...o&&{variantId:o},actionType:"claimOffer",presentationId:r.id,currentState:"redemption",useCase:s})),!this.#Tr(r.offer,r.id,s,t,{campaignId:r.offer.campaignId,...r.offer.advertiserName&&{advertiserName:r.offer.advertiserName},...o&&{variantId:o},useCase:s}))return a({status:"dismissed",reason:{type:"error",error:{code:e.UNKNOWN_ERROR,message:"The advertiser could not be opened (the browser blocked the popup). The claim is still pending — call redeem() again from a user gesture."}}}),void n.hide();i.markRedeemed(r.id),a({status:"redeemed"}),n.hide()})})}catch(t){return h.error("Error during redeem",t),this.#mr("present_offer_initialization",t),{status:"dismissed",reason:{type:"error",error:{code:e.UNKNOWN_ERROR,message:t instanceof Error?t.message:"Unknown error"}}}}finally{o?.destroy()}}getPendingTransaction(e){return this.#br()?this.#Cr(e)?.transaction??null:null}isActive(e,t){return h.error("isActive() has been removed. Entitlement validation must be done server-side. See: https://docs.encorekit.com/server-side-validation"),!1}didGrant(e,t){this.#br()&&(this.#qn?t&&"string"==typeof t?this.#qn.sendGrantSignal(t,e):h.error("didGrant() requires a valid transaction ID"):h.error("SignalManager not initialized"))}async waitForVerification(e,t){if(!this.#br())return h.error("SDK not configured"),"failed";if(!this.#m)return h.error("API client not initialized"),"failed";if(!e)return h.error("waitForVerification() requires a transaction ID"),"failed";try{h.debug("Starting verification wait",{transactionId:e,timeout:t});const n={transactionId:e};void 0!==t&&(n.timeout=t);const r=new U(this.#m,n);return await r.poll()}catch(t){return h.error("Error during verification wait",{transactionId:e,error:t}),"failed"}}on(e,t){return h.error("on() event listener has been removed. Entitlement validation must be done server-side. See: https://docs.encorekit.com/server-side-validation"),()=>{}}observeEntitlement(e,t){return h.error("observeEntitlement() has been removed. Entitlement validation must be done server-side. See: https://docs.encorekit.com/server-side-validation"),{subscribe:e=>()=>{}}}onStrictUnlockVerified(e){return this.#Ue.on("strictUnlockVerified",e)}placement(e,t){let n,r,i;return"string"==typeof e?(n=e,r=e,i=t):(n=`placement_${S().slice(0,8)}`,i=e),new _(n,async e=>this.show(void 0,e,r),i,async()=>this.redeem(r?{placement:r}:void 0))}#mr(t,n){if(!this.#m)return;const r=n instanceof Error?n.message:String(n),i=n instanceof Error?n.stack:void 0,o=N(n),s=function(t){if("object"!=typeof t||null===t)return{};const n=t,r=R(n,"code"),i=n.statusCode;return{...r&&r!==String(e.API_ERROR)?{serverCode:r}:{},..."number"==typeof i?{statusCode:String(i)}:{}}}(n);this.#m.reportError({errorType:o,message:r,context:t,severity:"error",...i&&{stackTrace:i},...this.#f&&{userId:this.#f},...Object.keys(s).length>0&&{metadata:s}}).catch(()=>{}),this.#k&&this.#f&&this.#k.track(function(e,t,n,r){return{name:"sdk_error",distinctId:e,properties:{errorType:t,errorDescription:n,...r&&{context:r}}}}(this.#f,o,r,t))}async#Rr(e,t,n){if("reduceChurn"!==t)return null;const r=this.#Wn?await this.#Wn.getCohort():"notEnrolled";return this.#Wn?.logExposure(r),"control"!==r?null:(this.#k&&this.#f&&this.#k.track(C(this.#f,"experiment_control",e,this.#nr,t,n)),this.#xr("experiment_control",e,t,n,this.#Sr(t)),h.debug("NCL control cohort — ghost trigger, no UI shown"),{result:{status:"unavailable"},override:{notPresentedReason:"experiment_control"}})}#Nr(e){if(e.ui?.values?.text){const t=e.ui.values.text;this.#tr={...t},h.debug("Remote config loaded",t)}this.#nr=e.ui?.variantId??void 0,this.#ir=e.ui?.values,this.#rr={...e.ui?.values?.text?.appName&&{appName:e.ui.values.text.appName},...e.ui?.values?.media?.appstoreIcon&&{appIconUrl:e.ui.values.media.appstoreIcon},...e.entitlements?.native&&{entitlementValue:e.entitlements.native.value,entitlementUnit:e.entitlements.native.unit,trialDurationDays:e.entitlements.native.durationDays}};const t=e.useCases??{},n={};for(const[e,r]of Object.entries(t)){const t=o(e);t&&(n[t]=r)}const r={};for(const e of Object.keys(this.#sr)){const t=this.#or[e];t&&(r[e]=t)}this.#or={...n,...r},this.#Wn?.setConfig(e.experiments?.ncl)}#Ur(e){if(this.#ar.has(e))return null;const t=this.#or[e];return t&&Nt(t)?{variantId:t.variantId??void 0,values:t.values}:null}async#Lr(e){this.#cr||this.#fr(),await this.#kr();return this.#Ur(e)||(await this.#Or(e),this.#Ur(e))}#Or(e){const t=this.#sr[e];if(t)return t;if(!this.#m||!this.#f)return Promise.resolve();this.#_r(e);const n=this.#f,r=this.#m.fetchConfig(n,W,e).then(t=>{if(this.#f!==n)return;const r=t.ui,o=r?.useCase===i(e),s=r?.values;o&&Nt({values:s})?(this.#ar.delete(e),this.#or[e]={variantId:r.variantId??null,variantName:r.variantName??null,template:r.template??null,values:s}):(this.#ar.add(e),delete this.#or[e])}).catch(t=>{h.warn(`Failed to fetch config for use case '${e}' (non-blocking)`,t),delete this.#sr[e]});return this.#sr[e]=r,r}#_r(e){this.#lr.has(e)||(this.#lr.add(e),h.warn(`[INTEGRATION] Use case '${e}' was not prefetched, so it is being fetched on demand — this first presentation will be slower, then it is cached. Nothing has failed. To make it instant, ask Encore to enable '${e}' for this app.`))}#Sr(e){return e&&"reduceChurn"!==e?this.#Ur(e)?.variantId:this.#nr}#fr(){if(!this.#m||!this.#f)return;const e=Date.now(),t=this.#f;this.#cr=this.#m.fetchConfig(t,W).then(n=>{this.#f===t&&(this.#Nr(n),this.#Pr("remote",Date.now()-e))}).catch(t=>{h.warn("Failed to fetch remote config (non-blocking)",t),this.#mr("configuration",t),this.#Pr("fallback",Date.now()-e),this.#cr=null})}#Pr(e,t){var n;this.#k&&this.#f&&this.#k.track({name:"sdk_sdui_config_loaded",distinctId:this.#f,properties:{...(n={...this.#nr&&{variantId:this.#nr},loadSource:e,loadDurationMs:t}).variantId&&{variantId:n.variantId},loadSource:n.loadSource,loadDurationMs:n.loadDurationMs,...n.presentationId&&{presentationId:n.presentationId}}})}async#kr(){if(!this.#cr)return;let e;await Promise.race([this.#cr,new Promise(t=>{e=setTimeout(t,2500)})]),clearTimeout(e)}async#Ir(t,n,r){const i=n?.useCase??"reduceChurn";let o=null;if("reduceChurn"!==i&&(o=await this.#Lr(i),!o))return h.info(`[Encore SDK] No template for use case '${i}' on this app — no-op`),this.#k&&this.#f&&this.#k.track(C(this.#f,"no_template",t,void 0,i,r)),{result:{status:"unavailable"},presentationId:t,override:{notPresentedReason:"use_case_unavailable"}};if(!this.#jn||!this.#m)return h.error("Managers not initialized"),{result:{status:"dismissed",reason:{type:"error",error:{code:e.INITIALIZATION_ERROR,message:"Managers not initialized"}}},presentationId:t};const s={title:b(n?.headline),subtitle:b(n?.subheadline)},a=this.#Sr(i);this.#k&&this.#f&&this.#k.track(function(e,t,n,r,i){return{name:"sdk_offer_presentation_triggered",distinctId:e,properties:{presentationId:t,...n&&{variantId:n},...x(r),...I(i)}}}(this.#f,t,a,i,r));const l=await this.#Rr(t,i,r);if(l)return{...l,presentationId:t,...void 0!==a&&{variantId:a}};const c=[],d=()=>{for(const e of c.splice(0))try{e()}catch{}};try{const l=n?.appearance,u={...l?.accentColor&&{primaryColor:l.accentColor},...l?.backgroundColor&&{backgroundColor:l.backgroundColor},...l?.textColor&&{textColor:l.textColor}};this.#Jn?l&&function(e){const t=document.documentElement,n=De(e);n.primaryColor&&t.style.setProperty("--encore-primary-color",n.primaryColor),n.backgroundColor&&t.style.setProperty("--encore-bg-color",n.backgroundColor),n.textColor&&t.style.setProperty("--encore-text-color",n.textColor),n.borderRadius&&t.style.setProperty("--encore-border-radius",n.borderRadius),n.fontFamily&&t.style.setProperty("--encore-font-family",n.fontFamily),h.debug("Theme variables updated",n)}(u):(He(u),this.#Jn=!0),h.debug("Fetching offers");const p="strict"===this.#Kn.getUnlockMode(),{offers:m}=await this.#jn.fetchOffers(this.#Zn,!0,r,p?15e3:void 0);if(0===m.length)return h.info("No offers available"),this.#k&&this.#f&&this.#k.track(C(this.#f,"no_offer_available",t,a,i,r)),{result:{status:"unavailable"},presentationId:t,...void 0!==a&&{variantId:a},override:{notPresentedReason:"no_offer_available"}};const f={...this.#tr,...s.title&&{titleText:s.title,customHeadline:s.title},...s.subtitle&&{subtitleText:s.subtitle,customSubheadline:s.subtitle}};this.#jn.beginPresentation(a,i,r,t);const g=new Map;m.forEach(e=>{g.set(e.id,S())});const v=e=>{let t=g.get(e);return t||(t=S(),g.set(e,t)),t};this.#k&&this.#f&&this.#k.track(function(e,t,n,r,i,o){return{name:"sdk_offer_presentation_success",distinctId:e,properties:{presentationId:t,offerCount:n,...r&&{variantId:r},...x(i),...I(o)}}}(this.#f,t,m.length,a,i,r));const w=e=>({campaignId:e.campaignId,...e.creativeId&&{creativeId:e.creativeId},...null!=e.merchantName&&{advertiserName:e.merchantName},impressionId:v(e.id),offerIndex:m.indexOf(e),totalOffers:m.length,presentationId:t,...a&&{variantId:a},...i&&{useCase:i},...r&&{placementId:r}}),y=new Ke({},{showCloseButton:"rewardUsers"!==i,...!1===n?.dismissible&&{dismissible:!1},...l?.modalBackgroundColor&&{backgroundColor:l.modalBackgroundColor}}),k={rewardActions:null,confetti:null},A=new Xe(m,f,"rewardUsers"===i?{mode:"paged",hideHeader:!0,selectable:!0,claimEnabled:this.#gt,...l?.dotColor&&{dotColor:l.dotColor},...l?.dotActiveColor&&{dotActiveColor:l.dotActiveColor}}:{claimEnabled:this.#gt});c.push(()=>y.destroy()),c.push(()=>A.destroy()),c.push(()=>k.rewardActions?.destroy()),c.push(()=>k.confetti?.destroy());const T=await new Promise(c=>{let d=!1;const u=(e,n)=>{d||(d=!0,c({result:e,presentationId:t,...void 0!==a&&{variantId:a},...n&&{override:n}}))};let p=null,f="carousel";A.on("offerClaim",n=>{const o=n.offer;h.debug("User claimed offer",{offerId:o.id});const s=w(o);this.#Ar(e=>function(e,t){return{name:"sdk_offer_claim_tapped",distinctId:e,properties:E(t)}}(e,s)),this.#Ar(e=>$(e,{...a&&{variantId:a},actionType:"claimOffer",presentationId:t,currentState:"carousel",useCase:i,...r&&{placementId:r}}));const l=this.#Mr(i),c=P(l)?null:this.#$r();(async()=>{try{const e=v(o.id),t=m.indexOf(o),n=await this.#Dr(o,e,t,m.length,i),a=this.#zr(o,n);if(p=a,P(l)){const e=this.#Fr(l,o,n,i,r,o.perk);return this.#jn?.endPresentation(void 0,i),f="primer",void this.#Br(y,e,()=>{u(a),y.hide()})}this.#Tr(o,n,i,c,s),this.#jn?.endPresentation(void 0,i),y.hide(),u(a)}catch(t){h.error("Error creating transaction",{offerId:o.id,error:t}),this.#mr("start_transaction",t),p||this.#Ar(e=>function(e,t,n){return{name:"sdk_offer_claim_failed",distinctId:e,properties:{...E(t),reason:n.reason,...n.errorDescription&&{errorDescription:n.errorDescription},...n.transactionId&&{transactionId:n.transactionId}}}}(e,s,{reason:this.#jn?"transaction_start_failed":"manager_unavailable",errorDescription:t instanceof Error?t.message:"Transaction failed"})),this.#Hr(c),this.#jn?.endPresentation("error",i),y.hide(),p?u(p):u({status:"dismissed",reason:{type:"error",error:{code:e.UNKNOWN_ERROR,message:t instanceof Error?t.message:"Transaction failed"}}},{advertiserOutcome:"failed",dismissal:"interrupted"})}})()}),A.on("complete",e=>{e.claimed||(h.debug("User declined last offer"),this.#jn?.endPresentation("userDeclinedLastOffer",i),A.destroy(),y.hide(),u({status:"dismissed",reason:"userDeclinedLastOffer"}))});const g=()=>{if(this.#Ar(e=>$(e,{...a&&{variantId:a},actionType:"close",presentationId:t,currentState:f,useCase:i,...r&&{placementId:r}})),p)return A.destroy(),void u(p);h.debug("User closed modal"),this.#jn?.endPresentation("userClosedModal",i),A.destroy(),u({status:"dismissed",reason:"userClosedModal"})};if(y.on("close",g),y.on("backdropClick",()=>{if(p)return A.destroy(),y.hide(),void u(p);h.debug("User clicked outside modal"),this.#jn?.endPresentation("userClickedOutside",i),A.destroy(),y.hide(),u({status:"dismissed",reason:"userClickedOutside"})}),A.on("offerView",e=>{const{offer:t}=e,n=v(t.id),r=m.indexOf(t);this.#jn&&this.#jn.trackOfferPresented(t,n,r,m.length,i)}),A.on("scroll",e=>{this.#Ar(n=>function(e,t){return{name:"sdk_sdui_scroll",distinctId:e,properties:{...t.variantId&&{variantId:t.variantId},scrollAxis:t.scrollAxis,scrollPosition:t.scrollPosition,presentationId:t.presentationId,...x(t.useCase),...I(t.placementId)}}}(n,{...a&&{variantId:a},scrollAxis:e.axis,scrollPosition:e.position,presentationId:t,useCase:i,...r&&{placementId:r}}))}),y.on("hide",()=>{u(p||{status:"dismissed",reason:"userClosedModal"})}),"rewardUsers"===i){const e=new Ct({onClaim:()=>A.claimSelected(),onDecline:()=>{g(),y.hide()},claimEnabled:this.#gt,useCase:i,...!1===n?.dismissible&&{secondary:A.getTotalOffers()>1?"next":"none",onNext:()=>A.getCurrentIndex()>=A.getTotalOffers()-1?A.selectOffer(0):A.next()},...l?.claimButton&&{claimSlot:l.claimButton},...l?.declineButton&&{declineSlot:l.declineButton}});k.rewardActions=e,A.on("offerSelect",t=>{e.setSelectedOffer(t.offer.merchantName)})}y.show();const C=A.render();let S;if("rewardUsers"===i&&o){const e=o.values?.text,t=b(gt(l?.headline),s.title,e?.rewardHeadline)??"Congrats! You’ve unlocked an exclusive gift",r=b(gt(l?.subheadline),s.subtitle,e?.rewardSubheadline)??"Choose one of our partner offers below";S=function(e,t={}){const{title:n,subtitle:r,statusIcon:i="none",actions:o,headlineSlot:s,subheadlineSlot:a,useCase:l="rewardUsers"}=t,c=document.createElement("div");c.className=`${Ve("thankyou")} ${Ve("thankyou--reward")}`;const d=document.createElement("div");if(d.className=Ve("thankyou-status"),"success"===i){const e=document.createElement("span");e.className=Ve("thankyou-check"),e.setAttribute("aria-hidden","true"),e.innerHTML='<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><path d="M5 12.5l4.5 4.5L19 7.5" /></svg>',d.appendChild(e)}if(n){const e=document.createElement("h2");e.className=Ve("thankyou-title"),e.id=xt,e.textContent=n,d.appendChild(ft(e,n,l,s))}else h.warn("Reward layout rendered without a headline — the dialog has no accessible name");if(r||a){const e=document.createElement("p");e.className=Ve("thankyou-subtitle"),e.textContent=r??"";const t=ft(e,r??"",l,a);(t.textContent?.trim()||t.childElementCount>0)&&d.appendChild(t)}return c.appendChild(d),c.appendChild(e),o&&c.appendChild(o),c}(C,{title:t,...r&&{subtitle:r},...n?.statusIcon&&{statusIcon:n.statusIcon},...k.rewardActions&&{actions:k.rewardActions.render()},useCase:i,...l?.headline&&{headlineSlot:l.headline},...l?.subheadline&&{subheadlineSlot:l.subheadline}}),y.setLabelledBy(xt)}else S=C;if(y.setContent(S),"rewardUsers"===i){const e=new $t;k.confetti=e;const t=S;requestAnimationFrame(()=>e.start(t))}});return d(),T}catch(n){return h.error("Error in offer flow",n),this.#mr("present_offer_initialization",n),d(),{result:{status:"dismissed",reason:{type:"error",error:{code:e.UNKNOWN_ERROR,message:n instanceof Error?n.message:"Unknown error"}}},presentationId:t,...void 0!==a&&{variantId:a},override:{advertiserOutcome:"not_attempted",dismissal:"interrupted"}}}}#zr(e,t){return t||h.warn("[Encore SDK] Claim resolved WITHOUT a transactionId — this conversion cannot be traced back to the user or app. The claim itself succeeded; the transaction record did not."),{status:"claimed",offerId:e.id,campaignId:e.campaignId,advertiserName:e.merchantName??"",...t&&{transactionId:t}}}async#Dr(e,t,n,r,i){if(!this.#jn)throw new Error("OfferManager not initialized");const o=await this.#jn.startTransaction(e.campaignId,i),s=this.#jn.placementId;return this.#Qn?.notePending(o,{grantsEntitlement:Ut(i),...void 0!==i&&{useCase:i},...void 0!==s&&{placementId:s}}),this.#jn.trackOfferClaimed(e,t,o,n,r,i),h.debug("Transaction created",{transactionId:o}),o}#Tr(e,t,n,r,i){const o=this.#Vr(e.advertiserUrl,e.trackingParameters,t),s=this.#Kr(o);i&&this.#Ar(e=>function(e,t,n){return{name:"sdk_offer_webview_attempting_open",distinctId:e,properties:{...E(t),url:n.url,urlHost:n.urlHost}}}(e,i,{url:o,urlHost:s}));const a=this.#qr(r,o);return a||h.warn("Failed to open advertiser URL (popup blocked?)"),i&&(a?(this.#Ar(e=>function(e,t,n){return{name:"sdk_offer_webview_opened",distinctId:e,properties:{...E(t),url:n.url,urlHost:n.urlHost,openedAt:n.openedAt}}}(e,i,{url:o,urlHost:s,openedAt:(new Date).toISOString()})),this.#jr(i,t)):this.#Ar(e=>function(e,t,n){return{name:"sdk_offer_webview_load_failed",distinctId:e,properties:{...E(t),url:n.url,urlHost:n.urlHost,loadSuccess:!1,reason:n.reason}}}(e,i,{url:o,urlHost:s,reason:"popup_blocked"}))),a&&this.#Wr(t,i),Ut(n)&&"strict"!==this.#Kn.getUnlockMode()&&this.didGrant("provisional",t),a}#gr(){this.#Qn&&(this.#Gn?.start(()=>{this.#Gr()}),this.#Gr())}async#Gr(){const e=this.#Qn;if(!e||this.#er)return;const t=e.getPending();if(t&&!this.#Yn.has(t.transactionId)){h.debug("Strict unlock: reconciling pending claim",{transactionId:t.transactionId}),this.#Yn.add(t.transactionId);try{"verified"===await e.verify(t.transactionId)&&this.#Qr(t.transactionId)}finally{this.#Yn.delete(t.transactionId)}}}#Wr(e,t){const n=this.#Qn;n&&!this.#Yn.has(e)&&(this.#Yn.add(e),(async()=>{try{const r=await n.verify(e);if("verified"!==r)return void h.debug("Strict unlock: not verified in session, left pending",{transactionId:e,status:r});this.#Qr(e,t)}finally{this.#Yn.delete(e)}})())}#Qr(e,t){const n=this.#Qn?.getPending();n?.transactionId===e?(this.#Qn?.clearPending(),n.grantsEntitlement&&this.didGrant("final",e),this.#Ar(r=>function(e,t,n){return{name:"sdk_offer_verified",distinctId:e,properties:{...n?E(n):{},transactionId:t.transactionId,...x(t.useCase),...I(t.placementId)}}}(r,{transactionId:e,...void 0!==n.useCase&&{useCase:n.useCase},...void 0!==n.placementId&&{placementId:n.placementId}},t)),this.#Ue.emit("strictUnlockVerified",e),h.debug("Strict unlock: claim verified",{transactionId:e})):h.debug("Strict unlock: verification superseded by a newer claim",{transactionId:e})}#Kr(e){try{return new URL(e).hostname}catch{return""}}#jr(e,t){if("undefined"==typeof window||"undefined"==typeof document)return;const n=this.#f;if(this.#k&&n)try{this.#dr?.();const r=Date.now();let i=!1;const o=()=>{window.removeEventListener("focus",s),document.removeEventListener("visibilitychange",s),this.#dr===o&&(this.#dr=null)},s=()=>{if(i||"visible"!==document.visibilityState)return;i=!0,o();const s=(Date.now()-r)/1e3;this.#k?.track(function(e,t,n){return{name:"sdk_offer_claim_returned",distinctId:e,properties:{...E(t),...n.transactionId&&{transactionId:n.transactionId}}}}(n,e,{transactionId:t})),this.#k?.track(function(e,t,n){return{name:"sdk_offer_webview_dismissed",distinctId:e,properties:{...E(t),timeSpentSeconds:n.timeSpentSeconds}}}(n,e,{timeSpentSeconds:s}))};window.addEventListener("focus",s),document.addEventListener("visibilitychange",s),this.#dr=o}catch{}}#Ar(e){const t=this.#f;this.#k&&t&&this.#k.track(e(t))}#Vr(e,t,n){try{const r=new URL(e);t&&Object.entries(t).forEach(([e,t])=>{r.searchParams.append(e,String(t))});let i=r.toString();return i=i.replace(/TRANSACTION_ID/g,n),h.debug("Built final advertiser URL",{original:e,final:i,transactionId:n}),i}catch(t){return h.error("Failed to build advertiser URL",{url:e,error:t}),e.replace(/TRANSACTION_ID/g,n)}}#$r(){try{return window.open("","_blank")}catch(e){return h.error("Failed to open blank advertiser window",{error:e}),null}}#qr(e,t){try{if(e)return e.location.href=t,e.focus(),!0;const n=window.open(t,"_blank","noopener,noreferrer");return!!n&&(n.focus(),!0)}catch(e){return h.error("Failed to navigate advertiser URL",{url:t,error:e}),!1}}#Hr(e){try{e?.close()}catch(e){h.error("Failed to close advertiser window",{error:e})}}#Cr(e){return[this.#hr,this.#ur].map(t=>{const n=e?t.getByPlacement(e):t.getLatest();return n?{transaction:Rt(n),store:t}:null}).filter(e=>null!==e).sort((e,t)=>F(t.transaction)-F(e.transaction))[0]??null}#Mr(e){return function(e,t){return function(e){if(!e||"object"!=typeof e)return;const t=e.claimBehavior;return D.includes(t)?t:void 0}(t)??M[e]}(e,"reduceChurn"===e?this.#ir:this.#or[e]?.values)}#Fr(e,t,n,r,i,o){const s=Date.now(),a={id:n,appAccountId:this.#f??"",...i&&{placementId:i},offer:{id:t.id,campaignId:t.campaignId,advertiserUrl:t.advertiserUrl,...t.trackingParameters&&{trackingParameters:t.trackingParameters},...t.merchantName&&{advertiserName:t.merchantName},...o&&{reward:o},...t.imageUrl&&{imageUrl:t.imageUrl},...t.logoUrl&&{logoUrl:t.logoUrl}},useCase:r,status:"claimed",createdAt:new Date(s).toISOString(),expiresAt:new Date(s+6048e5).toISOString()};return("deferredWhileAlive"===e?this.#ur:this.#hr).save(a),a}#Yr(){return function(e){const t=K(e.appName),n=function(e){const t=K(e.entitlementValue),n=K(e.entitlementUnit);if(!t||!n)return;const r=n.endsWith("s")?n.slice(0,-1):n;return`${t} ${1===Number(t)?r:`${r}s`}`}(e),r=K(e.appIconUrl);return{...t&&{appDisplayName:t},...n&&{trialPeriod:n},...r&&{logoUrl:r}}}(this.#rr)}#Br(e,t,n){const r=this.#Yr();try{const i=new nt({variant:r.appDisplayName?"activation":"holding",display:r,partner:{...t.offer.advertiserName&&{name:t.offer.advertiserName},...t.offer.logoUrl&&{logoUrl:t.offer.logoUrl},...t.offer.imageUrl&&{imageUrl:t.offer.imageUrl}}});i.on("continue",()=>{i.destroy(),n()}),e.setContent(i.render()),h.debug("Primer screen displayed",{transactionId:t.id})}catch(e){h.error("Failed to show the primer screen",e),n()}}#Er(e,t,n,r){try{const{reward:o,advertiserName:s,logoUrl:a,imageUrl:l}=t.offer,c=this.#Yr(),d=n?.name??c.appDisplayName;let u={};if("rewardUsers"!==t.useCase&&d){const e=this.#rr.trialDurationDays,t=e?(i=new Date(Date.now()+24*e*60*60*1e3),`Free until ${new Intl.DateTimeFormat(void 0,{month:"long",day:"numeric",year:"numeric"}).format(i)}`):void 0,r=n?.logoUrl??c.logoUrl;u={host:{name:d,...c.trialPeriod&&{trialPeriod:c.trialPeriod},...n?.status&&{status:n.status},...t&&{detail:t},...r&&{logoUrl:r}}}}const p=new lt({variant:u.host?"activation":"reward",...o&&{reward:o},...s&&{advertiserName:s},...a&&{logoUrl:a},...l&&{imageUrl:l},...u});p.on("continue",()=>{p.destroy(),r()}),e.setContent(p.render()),h.debug("Redemption screen displayed",{transactionId:t.id})}catch(e){h.error("Failed to show redemption screen",e),r()}var i}};exports.Encore=Lt,exports.default=Lt;
|
|
2
2
|
//# sourceMappingURL=index.cjs.map
|