saltfish 0.3.65 → 0.3.67
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/player.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
|
|
2
2
|
/*!
|
|
3
|
-
* Saltfish playlist Player v0.3.
|
|
3
|
+
* Saltfish playlist Player v0.3.67
|
|
4
4
|
* (c) 2025
|
|
5
5
|
* Released under the MIT License.
|
|
6
6
|
*/
|
|
7
|
-
!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):(t="undefined"!=typeof globalThis?globalThis:t||self).SaltfishplaylistPlayer=e()}(this,(function(){"use strict";var t=Object.defineProperty,e=(e,n,i)=>((e,n,i)=>n in e?t(e,n,{enumerable:!0,configurable:!0,writable:!0,value:i}):e[n]=i)(e,"symbol"!=typeof n?n+"":n,i);const n={},i=t=>{let e;const i=new Set,s=(t,n)=>{const s="function"==typeof t?t(e):t;if(!Object.is(s,e)){const t=e;e=(null!=n?n:"object"!=typeof s||null===s)?s:Object.assign({},e,s),i.forEach((n=>n(e,t)))}},r=()=>e,a={setState:s,getState:r,getInitialState:()=>o,subscribe:t=>(i.add(t),()=>i.delete(t)),destroy:()=>{"production"!==(n?"production":void 0)&&console.warn("[DEPRECATED] The `destroy` method will be unsupported in a future version. Instead use unsubscribe function returned by subscribe. Everything will be garbage-collected if store is garbage-collected."),i.clear()}},o=e=t(s,r,a);return a};var s=Symbol.for("immer-nothing"),r=Symbol.for("immer-draftable"),a=Symbol.for("immer-state");function o(t,...e){throw new Error(`[Immer] minified error nr: ${t}. Full error at: https://bit.ly/3cXEKWf`)}var l=Object.getPrototypeOf;function c(t){return!!t&&!!t[a]}function d(t){var e;return!!t&&(u(t)||Array.isArray(t)||!!t[r]||!!(null==(e=t.constructor)?void 0:e[r])||y(t)||v(t))}var h=Object.prototype.constructor.toString();function u(t){if(!t||"object"!=typeof t)return!1;const e=l(t);if(null===e)return!0;const n=Object.hasOwnProperty.call(e,"constructor")&&e.constructor;return n===Object||"function"==typeof n&&Function.toString.call(n)===h}function p(t,e){0===m(t)?Reflect.ownKeys(t).forEach((n=>{e(n,t[n],t)})):t.forEach(((n,i)=>e(i,n,t)))}function m(t){const e=t[a];return e?e.type_:Array.isArray(t)?1:y(t)?2:v(t)?3:0}function g(t,e){return 2===m(t)?t.has(e):Object.prototype.hasOwnProperty.call(t,e)}function f(t,e,n){const i=m(t);2===i?t.set(e,n):3===i?t.add(n):t[e]=n}function y(t){return t instanceof Map}function v(t){return t instanceof Set}function b(t){return t.copy_||t.base_}function w(t,e){if(y(t))return new Map(t);if(v(t))return new Set(t);if(Array.isArray(t))return Array.prototype.slice.call(t);const n=u(t);if(!0===e||"class_only"===e&&!n){const e=Object.getOwnPropertyDescriptors(t);delete e[a];let n=Reflect.ownKeys(e);for(let i=0;i<n.length;i++){const s=n[i],r=e[s];!1===r.writable&&(r.writable=!0,r.configurable=!0),(r.get||r.set)&&(e[s]={configurable:!0,writable:!0,enumerable:r.enumerable,value:t[s]})}return Object.create(l(t),e)}{const e=l(t);if(null!==e&&n)return{...t};const i=Object.create(e);return Object.assign(i,t)}}function S(t,e=!1){return x(t)||c(t)||!d(t)||(m(t)>1&&(t.set=t.add=t.clear=t.delete=E),Object.freeze(t),e&&Object.entries(t).forEach((([t,e])=>S(e,!0)))),t}function E(){o(2)}function x(t){return Object.isFrozen(t)}var M,I={};function P(t){const e=I[t];return e||o(0),e}function C(){return M}function _(t,e){e&&(P("Patches"),t.patches_=[],t.inversePatches_=[],t.patchListener_=e)}function k(t){T(t),t.drafts_.forEach(z),t.drafts_=null}function T(t){t===M&&(M=t.parent_)}function A(t){return M={drafts_:[],parent_:M,immer_:t,canAutoFreeze_:!0,unfinalizedDrafts_:0}}function z(t){const e=t[a];0===e.type_||1===e.type_?e.revoke_():e.revoked_=!0}function L(t,e){e.unfinalizedDrafts_=e.drafts_.length;const n=e.drafts_[0];return void 0!==t&&t!==n?(n[a].modified_&&(k(e),o(4)),d(t)&&(t=V(e,t),e.parent_||D(e,t)),e.patches_&&P("Patches").generateReplacementPatches_(n[a].base_,t,e.patches_,e.inversePatches_)):t=V(e,n,[]),k(e),e.patches_&&e.patchListener_(e.patches_,e.inversePatches_),t!==s?t:void 0}function V(t,e,n){if(x(e))return e;const i=e[a];if(!i)return p(e,((s,r)=>O(t,i,e,s,r,n))),e;if(i.scope_!==t)return e;if(!i.modified_)return D(t,i.base_,!0),i.base_;if(!i.finalized_){i.finalized_=!0,i.scope_.unfinalizedDrafts_--;const e=i.copy_;let s=e,r=!1;3===i.type_&&(s=new Set(e),e.clear(),r=!0),p(s,((s,a)=>O(t,i,e,s,a,n,r))),D(t,e,!1),n&&t.patches_&&P("Patches").generatePatches_(i,n,t.patches_,t.inversePatches_)}return i.copy_}function O(t,e,n,i,s,r,a){if(c(s)){const a=V(t,s,r&&e&&3!==e.type_&&!g(e.assigned_,i)?r.concat(i):void 0);if(f(n,i,a),!c(a))return;t.canAutoFreeze_=!1}else a&&n.add(s);if(d(s)&&!x(s)){if(!t.immer_.autoFreeze_&&t.unfinalizedDrafts_<1)return;V(t,s),e&&e.scope_.parent_||"symbol"==typeof i||!Object.prototype.propertyIsEnumerable.call(n,i)||D(t,s)}}function D(t,e,n=!1){!t.parent_&&t.immer_.autoFreeze_&&t.canAutoFreeze_&&S(e,n)}var F={get(t,e){if(e===a)return t;const n=b(t);if(!g(n,e))return function(t,e,n){var i;const s=N(e,n);return s?"value"in s?s.value:null==(i=s.get)?void 0:i.call(t.draft_):void 0}(t,n,e);const i=n[e];return t.finalized_||!d(i)?i:i===U(t.base_,e)?(H(t),t.copy_[e]=$(i,t)):i},has:(t,e)=>e in b(t),ownKeys:t=>Reflect.ownKeys(b(t)),set(t,e,n){const i=N(b(t),e);if(null==i?void 0:i.set)return i.set.call(t.draft_,n),!0;if(!t.modified_){const i=U(b(t),e),o=null==i?void 0:i[a];if(o&&o.base_===n)return t.copy_[e]=n,t.assigned_[e]=!1,!0;if(((s=n)===(r=i)?0!==s||1/s==1/r:s!=s&&r!=r)&&(void 0!==n||g(t.base_,e)))return!0;H(t),R(t)}var s,r;return t.copy_[e]===n&&(void 0!==n||e in t.copy_)||Number.isNaN(n)&&Number.isNaN(t.copy_[e])||(t.copy_[e]=n,t.assigned_[e]=!0),!0},deleteProperty:(t,e)=>(void 0!==U(t.base_,e)||e in t.base_?(t.assigned_[e]=!1,H(t),R(t)):delete t.assigned_[e],t.copy_&&delete t.copy_[e],!0),getOwnPropertyDescriptor(t,e){const n=b(t),i=Reflect.getOwnPropertyDescriptor(n,e);return i?{writable:!0,configurable:1!==t.type_||"length"!==e,enumerable:i.enumerable,value:n[e]}:i},defineProperty(){o(11)},getPrototypeOf:t=>l(t.base_),setPrototypeOf(){o(12)}},B={};function U(t,e){const n=t[a];return(n?b(n):t)[e]}function N(t,e){if(!(e in t))return;let n=l(t);for(;n;){const t=Object.getOwnPropertyDescriptor(n,e);if(t)return t;n=l(n)}}function R(t){t.modified_||(t.modified_=!0,t.parent_&&R(t.parent_))}function H(t){t.copy_||(t.copy_=w(t.base_,t.scope_.immer_.useStrictShallowCopy_))}p(F,((t,e)=>{B[t]=function(){return arguments[0]=arguments[0][0],e.apply(this,arguments)}})),B.deleteProperty=function(t,e){return B.set.call(this,t,e,void 0)},B.set=function(t,e,n){return F.set.call(this,t[0],e,n,t[0])};function $(t,e){const n=y(t)?P("MapSet").proxyMap_(t,e):v(t)?P("MapSet").proxySet_(t,e):function(t,e){const n=Array.isArray(t),i={type_:n?1:0,scope_:e?e.scope_:C(),modified_:!1,finalized_:!1,assigned_:{},parent_:e,base_:t,draft_:null,copy_:null,revoke_:null,isManual_:!1};let s=i,r=F;n&&(s=[i],r=B);const{revoke:a,proxy:o}=Proxy.revocable(s,r);return i.draft_=o,i.revoke_=a,o}(t,e);return(e?e.scope_:C()).drafts_.push(n),n}function Y(t){if(!d(t)||x(t))return t;const e=t[a];let n;if(e){if(!e.modified_)return e.base_;e.finalized_=!0,n=w(t,e.scope_.immer_.useStrictShallowCopy_)}else n=w(t,!0);return p(n,((t,e)=>{f(n,t,Y(e))})),e&&(e.finalized_=!1),n}var X=new class{constructor(t){this.autoFreeze_=!0,this.useStrictShallowCopy_=!1,this.produce=(t,e,n)=>{if("function"==typeof t&&"function"!=typeof e){const n=e;e=t;const i=this;return function(t=n,...s){return i.produce(t,(t=>e.call(this,t,...s)))}}let i;if("function"!=typeof e&&o(6),void 0!==n&&"function"!=typeof n&&o(7),d(t)){const s=A(this),r=$(t,void 0);let a=!0;try{i=e(r),a=!1}finally{a?k(s):T(s)}return _(s,n),L(i,s)}if(!t||"object"!=typeof t){if(i=e(t),void 0===i&&(i=t),i===s&&(i=void 0),this.autoFreeze_&&S(i,!0),n){const e=[],s=[];P("Patches").generateReplacementPatches_(t,i,e,s),n(e,s)}return i}o(1)},this.produceWithPatches=(t,e)=>{if("function"==typeof t)return(e,...n)=>this.produceWithPatches(e,(e=>t(e,...n)));let n,i;return[this.produce(t,e,((t,e)=>{n=t,i=e})),n,i]},"boolean"==typeof(null==t?void 0:t.autoFreeze)&&this.setAutoFreeze(t.autoFreeze),"boolean"==typeof(null==t?void 0:t.useStrictShallowCopy)&&this.setUseStrictShallowCopy(t.useStrictShallowCopy)}createDraft(t){d(t)||o(8),c(t)&&(t=function(t){c(t)||o(10);return Y(t)}(t));const e=A(this),n=$(t,void 0);return n[a].isManual_=!0,T(e),n}finishDraft(t,e){const n=t&&t[a];n&&n.isManual_||o(9);const{scope_:i}=n;return _(i,e),L(void 0,i)}setAutoFreeze(t){this.autoFreeze_=t}setUseStrictShallowCopy(t){this.useStrictShallowCopy_=t}applyPatches(t,e){let n;for(n=e.length-1;n>=0;n--){const i=e[n];if(0===i.path.length&&"replace"===i.op){t=i.value;break}}n>-1&&(e=e.slice(n+1));const i=P("Patches").applyPatches_;return c(t)?i(t,e):this.produce(t,(t=>i(t,e)))}},W=X.produce;X.produceWithPatches.bind(X),X.setAutoFreeze.bind(X),X.setUseStrictShallowCopy.bind(X),X.applyPatches.bind(X),X.createDraft.bind(X),X.finishDraft.bind(X);const j=t=>(e,n,i)=>(i.setState=(t,n,...i)=>{const s="function"==typeof t?W(t):t;return e(s,n,...i)},t(i.setState,n,i));function q(t,e){void 0!==e?console.info(t,e):console.info(t)}function Z(t,e){console.warn(t)}function G(t,e){void 0!==e?console.error(t,e):console.error(t)}class K{constructor(t,n){e(this,"currentState"),e(this,"config"),e(this,"context"),e(this,"actionHandlers",{}),this.config=t,this.currentState=t.initial,this.context=n,this.setupDefaultActions(),this.runEntryActions(this.currentState)}setupDefaultActions(){this.actionHandlers={...this.actionHandlers,logStateEntry:t=>{this.currentState},logErrorEvent:(t,e)=>{"ERROR"===(null==e?void 0:e.type)&&e.error.message},logStepTransition:(t,e)=>{"TRANSITION_TO_STEP"===(null==e?void 0:e.type)&&e.step.id},logErrorRecovery:()=>{}}}registerActions(t){this.actionHandlers={...this.actionHandlers,...t},Object.keys(t).join(", ")}executeAction(t,e){if("string"==typeof t){const n=this.actionHandlers[t];n&&n(this.context,e)}else t(this.context,e)}send(t){const e=this.config.states[this.currentState].on[t.type];if(!e)return t.type,this.currentState,this.currentState;this.currentState,e.target,t.type,this.runExitActions(this.currentState),this.updateContextFromEvent(t),e.actions&&e.actions.forEach((e=>this.executeAction(e,t)));this.currentState;return this.currentState=e.target,this.runEntryActions(this.currentState),this.currentState,this.currentState}updateContextFromEvent(t){"TRANSITION_TO_STEP"===t.type||"MANIFEST_LOADED"===t.type||"VIDEO_FINISHED_WAIT"===t.type?this.context.currentStep=t.step:"ERROR"===t.type&&(this.context.error=t.error)}getState(){return this.currentState}getContext(){return this.context}updateContext(t){const e=t(this.context);this.context={...this.context,...e}}runEntryActions(t){const e=this.config.states[t];e.entry&&e.entry.forEach((t=>this.executeAction(t)))}runExitActions(t){const e=this.config.states[t];e.exit&&e.exit.forEach((t=>this.executeAction(t)))}}const J={initial:"idle",states:{idle:{on:{INITIALIZE:{target:"idle"},LOAD_MANIFEST:{target:"loading"}},entry:["logStateEntry"]},loading:{on:{MANIFEST_LOADED:{target:"paused"},ERROR:{target:"error",actions:["logErrorEvent"]}},entry:["logStateEntry","showLoadingState"],exit:["hideLoadingState"]},playing:{on:{PAUSE:{target:"paused"},MINIMIZE:{target:"minimized"},VIDEO_FINISHED_WAIT:{target:"waitingForInteraction"},AUTOPLAY_FALLBACK:{target:"autoplayBlocked"},TRANSITION_TO_STEP:{target:"playing",actions:["logStepTransition"]},ERROR:{target:"error"},COMPLETE_PLAYLIST:{target:"completed"},COMPLETE_PLAYLIST_WAITING_FOR_INTERACTION:{target:"completedWaitingForInteraction"}},entry:["logStateEntry","startVideoPlayback","showVideoControls","hidePlayButton"],exit:["pauseVideoPlayback"]},paused:{on:{PLAY:{target:"playing"},START_IDLE_MODE:{target:"idleMode"},MINIMIZE:{target:"minimized"},TRANSITION_TO_STEP:{target:"playing",actions:["logStepTransition"]}},entry:["logStateEntry","pauseVideoPlayback","showPlayButton"]},minimized:{on:{MAXIMIZE:{target:"paused"},EXIT:{target:"closing"}},entry:["logStateEntry","pauseVideoPlayback"]},waitingForInteraction:{on:{PLAY:{target:"playing"},PAUSE:{target:"paused"},MINIMIZE:{target:"minimized"},COMPLETE_PLAYLIST:{target:"completed"},COMPLETE_PLAYLIST_WAITING_FOR_INTERACTION:{target:"completedWaitingForInteraction"},TRANSITION_TO_STEP:{target:"playing",actions:["logStepTransition"]}},entry:["logStateEntry","showPlayButton"]},autoplayBlocked:{on:{PLAY:{target:"playing"},TRANSITION_TO_STEP:{target:"playing"},MINIMIZE:{target:"minimized"}},entry:["logStateEntry","enterCompactMode","startMutedLoopedVideo","hideVideoControls","showPlayButton","enablePlayButtonProminent"],exit:["disablePlayButtonProminent","showVideoControls","exitCompactMode"]},idleMode:{on:{PLAY:{target:"playing"},TRANSITION_TO_STEP:{target:"playing"},MINIMIZE:{target:"minimized"}},entry:["logStateEntry","startIdleModeVideo","hideVideoControls","showPlayButton","enablePlayButtonProminent"],exit:["disablePlayButtonProminent","showVideoControls","exitCompactMode"]},error:{on:{INITIALIZE:{target:"idle"},PLAY:{target:"playing",actions:["logErrorRecovery"]},AUTOPLAY_FALLBACK:{target:"autoplayBlocked"}},entry:["logStateEntry","handleError","showPlayButton"],exit:["hideError"]},completedWaitingForInteraction:{on:{COMPLETE_PLAYLIST:{target:"completed"},INITIALIZE:{target:"idle"},TRANSITION_TO_STEP:{target:"playing",actions:["logStepTransition"]},PLAY:{target:"playing"},MINIMIZE:{target:"minimized"}},entry:["logStateEntry","showPlayButton"]},completed:{on:{INITIALIZE:{target:"idle"}},entry:["logStateEntry","trackPlaylistComplete"]},closing:{on:{},entry:["logStateEntry","triggerPlaylistDismissed"]}}},Q="saltfish_progress",tt="saltfish_session",et="saltfish_anonymous_user_data",nt="saltfish_pending_navigation",it="https://player.saltfish.ai",st="https://studio-api.saltfish.ai/studio/flows2/share",rt="sf-player",at="sf-player--minimized",ot="sf-controls-container",lt="sf-player__logo",ct="sf-error-display",dt="sf-error-display--visible",ht="sf-error-display__content",ut="sf-error-display__message",pt="sf-loading-spinner",mt=class t{constructor(){e(this,"isLocalStorageAvailable"),this.isLocalStorageAvailable=this.checkLocalStorageAvailability(),this.isLocalStorageAvailable}static getInstance(){return t.instance||(t.instance=new t),t.instance}static resetInstance(){t.instance=null}checkLocalStorageAvailability(){if("undefined"==typeof window)return!1;try{const t="__storage_test__";return localStorage.setItem(t,"test"),localStorage.removeItem(t),!0}catch(t){return!1}}safeGetItem(t){if(!this.isLocalStorageAvailable)return null;try{const e=localStorage.getItem(t);return null===e?null:JSON.parse(e)}catch(e){return this.safeClearItem(t),null}}safeSetItem(t,e){if(!this.isLocalStorageAvailable)return!1;try{return localStorage.setItem(t,JSON.stringify(e)),!0}catch(n){if(n instanceof DOMException&&22===n.code){this.clearOldData();try{return localStorage.setItem(t,JSON.stringify(e)),!0}catch(i){}}return!1}}safeClearItem(t){if(this.isLocalStorageAvailable)try{localStorage.removeItem(t)}catch(e){}}clearOldData(){this.safeClearItem(tt)}getProgress(t){const e=this.safeGetItem(Q);return e?t&&e.userId&&e.userId!==t?(e.userId,null):e.playlists||null:null}setProgress(t,e){const n={userId:e,playlists:t};return this.safeSetItem(Q,n)}clearProgress(){this.safeClearItem(Q)}getSession(){return this.safeGetItem(tt)}setSession(t){return this.safeSetItem(tt,t)}clearSession(){this.safeClearItem(tt)}getAnonymousUserData(){return this.safeGetItem(et)}setAnonymousUserData(t){return this.safeSetItem(et,t)}clearAnonymousUserData(){this.safeClearItem(et)}getPendingNavigation(){return this.safeGetItem(nt)}setPendingNavigation(t){return t.nextStepId,t.urlPattern,this.safeSetItem(nt,t)}clearPendingNavigation(){this.safeClearItem(nt)}clearAll(){this.clearProgress(),this.clearSession(),this.clearAnonymousUserData(),this.clearPendingNavigation()}};e(mt,"instance",null);let gt=mt;const ft=gt.getInstance(),yt=i(j(((t,e)=>{let n=new K(J,{currentStep:null,error:null});const i=t=>n.send(t);return{config:null,user:null,userData:null,currentState:n.getState(),manifest:null,currentStepId:null,isMinimized:!1,position:null,progress:{},error:null,playlistOptions:null,backendPlaylists:[],isAdmin:!1,isMuted:!1,abTests:[],abTestAssignments:{},initialize:async e=>{t((t=>{t.config=e,t.currentState=i({type:"INITIALIZE"})}))},setPlaylistOptions:e=>{t((t=>{if(t.playlistOptions=e,e.position){const n="bottom-left"===e.position||"bottom-right"===e.position?e.position:"bottom-right";t.position={x:0,y:0},t.playlistOptions={...e,position:n}}}))},identifyUser:(e,n)=>{const i={id:e,...n};t((t=>{t.user=i}))},setUserData:e=>{t((t=>{t.userData=e}))},setManifest:(e,n)=>{t((t=>{t.manifest=e,t.currentStepId=n;const s=e.steps.find((t=>t.id===n));t.currentState=i(s?{type:"MANIFEST_LOADED",step:s}:{type:"ERROR",error:new Error(`Start step '${n}' not found in manifest`)})}))},play:()=>{const{currentState:n}=e();t((t=>{t.currentState=i({type:"PLAY"})}))},pause:()=>{const{currentState:n}=e();t((t=>{t.currentState=i({type:"PAUSE"})}))},minimize:()=>{const{currentState:n}=e();t((t=>{"playing"===t.currentState&&(t.currentState=i({type:"PAUSE"})),t.currentState=i({type:"MINIMIZE"}),t.isMinimized=!0}))},maximize:()=>{t((t=>{t.currentState=i({type:"MAXIMIZE"}),t.isMinimized=!1}))},goToStep:n=>{const{manifest:s}=e();if("completed"!==n){if(s&&s.steps.some((t=>t.id===n))){const e=s.steps.find((t=>t.id===n));t((t=>{var r,a,o;t.currentStepId=n,e&&(t.currentState=i({type:"TRANSITION_TO_STEP",step:e}),(t.position||(null==(r=t.playlistOptions)?void 0:r.position))&&(t.position={x:0,y:0})),t.progress[s.id]={...t.progress[s.id],lastStepId:n,lastVisited:(new Date).toISOString()};if((null==(a=t.playlistOptions)?void 0:a.persistence)??!0){const e=null==(o=t.user)?void 0:o.id;ft.setProgress(t.progress,e)}}))}}else t((t=>{t.currentState=i({type:"COMPLETE_PLAYLIST"})}))},reset:()=>{t((t=>{t.config=null,t.user=null,t.userData=null,t.currentState=n.getState(),t.manifest=null,t.currentStepId=null,t.isMinimized=!1,t.position=null,t.progress={},t.error=null,n=new K(J,{currentStep:null,error:null})}))},setError:e=>{t((t=>{t.currentState=i({type:"ERROR",error:e}),t.error=e}))},setAutoplayFallback:()=>{t((t=>{t.currentState=i({type:"AUTOPLAY_FALLBACK"})}))},setIdleMode:()=>{t((t=>{t.currentState=i({type:"START_IDLE_MODE"})}))},setMuted:e=>{t((t=>{t.isMuted=e}))},setBackendPlaylists:e=>{t((t=>{t.backendPlaylists=e}))},setIsAdmin:e=>{t((t=>{t.isAdmin=e}))},completePlaylist:()=>{t((t=>{t.currentState=i({type:"COMPLETE_PLAYLIST"})}))},resetForNewPlaylist:()=>{t((t=>{const e=t.config,i=t.user,s=t.userData,r=t.progress;t.manifest=null,t.currentStepId=null,t.isMinimized=!1,t.position=null,t.error=null,t.playlistOptions=null,n=new K(J,{currentStep:null,error:null}),t.currentState=n.getState(),t.config=e,t.user=i,t.userData=s,t.progress=r}))},loadPlaylistProgress:(e,n)=>{t((t=>{t.progress[e]=n}))},registerStateMachineActions:t=>{n.registerActions(t)},sendStateMachineEvent:e=>{t((t=>{t.currentState=i(e)}))},updateProgressWithCompletion:(e,n)=>{t((t=>{var s,r;t.currentState=i({type:"COMPLETE_PLAYLIST_WAITING_FOR_INTERACTION"}),t.progress[e]={...t.progress[e],lastStepId:n,lastVisited:(new Date).toISOString(),completedWaitingForInteraction:!0};if((null==(s=t.playlistOptions)?void 0:s.persistence)??!0){const e=null==(r=t.user)?void 0:r.id;ft.setProgress(t.progress,e)}}))},setABTests:e=>{t((t=>{t.abTests=e}))},setABTestAssignments:e=>{t((t=>{t.abTestAssignments=e}))},getFilteredPlaylists:()=>{const t=e(),n=t.backendPlaylists||[],i=t.abTests||[],s=t.abTestAssignments||{};if(0===i.length)return n;const r=new Set;for(const e of i){const t=s[e.id];t&&t.assigned||r.add(e.playlistId)}return n.filter((t=>!r.has(t.id)))}}}))),vt={getState:()=>yt.getState(),setState:yt.setState,subscribe:yt.subscribe,destroy:yt.destroy};function bt(){try{return vt.getState()}catch(t){throw new Error(`[storeUtils] Failed to access Saltfish store: ${t}`)}}function wt(t){if(!t)return null;if(t.lastProgressAt&&"object"==typeof t.lastProgressAt&&"_seconds"in t.lastProgressAt&&"_nanoseconds"in t.lastProgressAt){const e=t.lastProgressAt;return 1e3*e._seconds+Math.floor(e._nanoseconds/1e6)}return t.timestamp&&"number"==typeof t.timestamp?t.timestamp:t.lastProgressAt&&"number"==typeof t.lastProgressAt?t.lastProgressAt:null}function St(t,e=6e3){const n=wt(t);if(!n)return{isValid:!1,ageMs:null,timestampMs:null};const i=Date.now()-n;return{isValid:i<=e,ageMs:i,timestampMs:n}}class Et{static handle(t,e={},n={}){var i;const s={...this.DEFAULT_OPTIONS,...n},r=this.normalizeError(t,e);if(s.shouldLog&&this.logError(r,e,s.severity),s.shouldUpdateStore&&this.updateStore(r),s.shouldTriggerEvent&&this.triggerErrorEvent(r,e,null==(i=e.component)?void 0:i.toLowerCase()),s.shouldDestroy&&this.destroyPlayer(),s.shouldThrow)throw r;return r}static handleInitializationError(t,e={}){return this.handle(t,{...e,component:"Initialization"},{severity:"critical",shouldLog:!0,shouldUpdateStore:!0,shouldDestroy:!0,shouldThrow:!0})}static handlePlaylistError(t,e={}){return this.handle(t,{...e,component:"Playlist"},{severity:"error",shouldLog:!0,shouldUpdateStore:!0,shouldTriggerEvent:!0})}static handleVideoError(t,e={}){return this.handle(t,{...e,component:"Video"},{severity:"error",shouldLog:!0,shouldUpdateStore:!0,shouldTriggerEvent:!0})}static handleNetworkError(t,e={}){return this.handle(t,{...e,component:"Network"},{severity:"warning",shouldLog:!0,shouldTriggerEvent:!0})}static handleWarning(t,e={}){return this.handle(t,e,{severity:"warning",shouldLog:!0,shouldThrow:!1})}static handleCleanupError(t,e={}){return this.handle(t,{...e,component:"Cleanup"},{severity:"warning",shouldLog:!0,shouldThrow:!1})}static normalizeError(t,e){if(t instanceof Error)return t;if("string"==typeof t)return new Error(t);const n=String(t&&"object"==typeof t&&"message"in t?t.message:t);return new Error(`Unknown error in ${e.component||"application"}: ${n}`)}static formatErrorMessage(t,e){const n=[];return e.component&&n.push(`[${e.component}]`),e.method&&n.push(`${e.method}:`),n.push(t.message),n.join(" ")}static logError(t,e,n){const i=this.formatErrorMessage(t,e),s={error:{name:t.name,message:t.message,stack:t.stack},context:e,severity:n,timestamp:(new Date).toISOString()};switch(n){case"info":break;case"warning":console.warn(i,s);break;case"error":case"critical":console.error(i,s)}}static updateStore(t){try{bt().setError(t)}catch(e){console.error("Failed to update store with error:",e)}}static triggerErrorEvent(t,e,n){var i,s;try{const r=bt();if("undefined"!=typeof window&&window._saltfishPlayer){const a=window._saltfishPlayer;a&&a.eventManager&&a.eventManager.trigger("error",{timestamp:Date.now(),playlistId:e.playlistId||(null==(i=r.manifest)?void 0:i.id),stepId:e.stepId||r.currentStepId,error:t,errorType:e.errorType||n||(null==(s=e.component)?void 0:s.toLowerCase())||"unknown"})}}catch(r){console.error("Failed to trigger error event:",r)}}static destroyPlayer(){try{if("undefined"!=typeof window&&window._saltfishPlayer){const t=window._saltfishPlayer;t&&"function"==typeof t.destroy&&t.destroy()}}catch(t){console.error("Failed to destroy player during error handling:",t)}}static createError(t,e={}){const n=new Error(this.formatErrorMessage(new Error(t),e));return e.component&&(n.component=e.component),e.method&&(n.method=e.method),e.playlistId&&(n.playlistId=e.playlistId),e.stepId&&(n.stepId=e.stepId),n}static isRecoverable(t){if(t.message.includes("fetch")||t.message.includes("network")||t.message.includes("timeout"))return!0;return[/autoplay.*blocked/i,/video.*failed.*load/i,/manifest.*not.*found/i].some((e=>e.test(t.message)))}static async safeExecute(t,e={},n={}){try{return await t()}catch(i){return this.handle(i,e,n),null}}}e(Et,"DEFAULT_OPTIONS",{severity:"error",shouldLog:!0,shouldThrow:!1,shouldUpdateStore:!1,shouldTriggerEvent:!1,shouldDestroy:!1});class xt{detectShareIdFromUrl(){try{const t=window.location.href,e=/saltfish-share-id=([^&#]*)/,n=t.match(e);if(n&&n[1]){const t=n[1];return t}return null}catch(t){return null}}async fetchShareData(t){try{const e=await fetch(`${st}/${t}`,{method:"GET",headers:{"Content-Type":"application/json"}});if(!e.ok)throw new Error(`Share API returned status ${e.status}`);const n=await e.json();if(!n.flowId)throw new Error("Share API response missing flowId");return n.shareId,n.flowId,n.createdBy,n}catch(e){throw Et.handleInitializationError(e,{component:"ShareLinkService",method:"fetchShareData",additionalData:{shareId:t}})}}async shouldAutoStartSharePlaylist(){try{const t=this.detectShareIdFromUrl();if(!t)return null;const e=await this.fetchShareData(t);return e.flowId,e.isGlobal,e}catch(t){return null}}}const Mt=3e4,It=100,Pt=12e4,Ct=500,_t=500,kt=5e3,Tt=18e5,At=6e4,zt=10;class Lt{constructor(t){e(this,"managers"),e(this,"userManagementService"),e(this,"playlistOrchestrator"),e(this,"shareLinkService"),e(this,"lastConfig",null),this.managers=t,this.shareLinkService=new xt}setUserManagementService(t){this.userManagementService=t}setPlaylistOrchestrator(t){this.playlistOrchestrator=t}getLastConfig(){return this.lastConfig}async initialize(t){var e;try{const n=await fetch(`${it}/validate-token`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({token:t.token,playerVersion:"0.2.73"})}),i=await n.json();if(!i.isValid)throw Et.handleInitializationError(i.error||"Token validation failed",{component:"PlayerInitializationService",method:"initialize",additionalData:{token:(null==(e=t.token)?void 0:e.substring(0,10))+"..."}});const s={...t,showLogo:!1!==i.showLogo};this.lastConfig=s;const r=bt();if(r.initialize(s),this.managers.analyticsManager.initialize(t,this.managers.sessionManager.getSessionId()),i.isAdmin&&r.setIsAdmin&&r.setIsAdmin(!0),i.playlists&&Array.isArray(i.playlists)&&r.setBackendPlaylists)i.playlists,r.setBackendPlaylists(i.playlists),i.playlists.length>0?this.managers.triggerManager.registerTriggers(i.playlists):i.isAdmin,i.abTests&&Array.isArray(i.abTests)&&(i.abTests,this.managers.abTestManager.initializeTests(i.abTests));else if(!i.isAdmin)throw Et.handleInitializationError("Backend validation successful, but no playlists array provided in the response. Cannot initialize player.",{component:"PlayerInitializationService",method:"initialize",additionalData:{responseData:i}});this.managers.eventManager.trigger("initialized",{timestamp:Date.now()})}catch(n){throw Et.handleInitializationError(n,{component:"PlayerInitializationService",method:"initialize"})}}async fetchUserData(t,e){var n;try{const i=bt();if(!(null==(n=i.config)?void 0:n.token))return void Et.handleWarning("Cannot fetch user data: Token not available",{component:"PlayerInitializationService",method:"fetchUserData",userId:t});const s=await fetch(`https://player.saltfish.ai/clients/${i.config.token}/users/${t}`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({userData:e})});if(!s.ok){await s.text();return s.status,void s.statusText}const r=await s.json();if(r.success){i.setUserData({watchedPlaylists:r.watchedPlaylists||{},language:r.language});const e=r.userListAssignments||{},n=r.abTestAssignments||{};this.managers.abTestManager.assignUserToTests(t,n,e),this.managers.eventManager.trigger("userDataLoaded",{timestamp:Date.now(),userId:t,userData:{watchedPlaylists:r.watchedPlaylists||{}}}),this.userManagementService&&this.userManagementService.resolveUserDataLoaded();const s=await this.checkAndResumeFromPendingNavigation();if(!(s||await this.checkAndResumeInProgressPlaylist(r.watchedPlaylists||{}))){const t=await this.shareLinkService.shouldAutoStartSharePlaylist();t&&this.playlistOrchestrator?(t.flowId,await this.playlistOrchestrator.startPlaylist(t.flowId,{once:!1,position:"bottom-right",_startedFromShareLink:!0,_isGlobalShare:t.isGlobal})):this.managers.triggerManager.startMonitoring()}}else this.userManagementService&&this.userManagementService.resolveUserDataLoaded()}catch(i){Et.handleNetworkError(i,{component:"PlayerInitializationService",method:"fetchUserData",userId:t}),this.userManagementService&&this.userManagementService.resolveUserDataLoaded()}}async loadAnonymousUserData(t,e){try{if("undefined"==typeof window)return;const n=this.managers.abTestManager.assignUserToTests(t,void 0,{}),i=this.managers.storageManager.getAnonymousUserData();let s={userId:t,userData:e||{},watchedPlaylists:{},abTestAssignments:n,timestamp:Date.now()};if(i){const n=i.abTestAssignments||{},r=this.managers.abTestManager.assignUserToTests(t,n);s={userId:t,userData:{...i.userData,...e},watchedPlaylists:i.watchedPlaylists||{},abTestAssignments:r,timestamp:Date.now()}}this.managers.storageManager.setAnonymousUserData(s);bt().setUserData({watchedPlaylists:s.watchedPlaylists||{},language:null==e?void 0:e.language}),this.managers.eventManager.trigger("userDataLoaded",{timestamp:Date.now(),userId:t,userData:{watchedPlaylists:s.watchedPlaylists||{}}});const r=await this.checkAndResumeFromPendingNavigation(),a=s.watchedPlaylists||{};if(!(r||await this.checkAndResumeInProgressPlaylist(a))){const t=await this.shareLinkService.shouldAutoStartSharePlaylist();t&&this.playlistOrchestrator?(t.flowId,await this.playlistOrchestrator.startPlaylist(t.flowId,{once:!1,position:"bottom-right",_startedFromShareLink:!0,_isGlobalShare:t.isGlobal})):this.managers.triggerManager.startMonitoring()}}catch(n){Et.handleNetworkError(n,{component:"PlayerInitializationService",method:"loadAnonymousUserData",userId:t})}}async checkAndResumeInProgressPlaylist(t){var e;if(!t)return!1;const n=bt(),i=null==(e=n.manifest)?void 0:e.id,s=n.currentState;if(i&&"idle"!==s&&"error"!==s)return!1;const r=Object.entries(t).find((([t,e])=>{if("in_progress"!==(null==e?void 0:e.status))return!1;const{isValid:n,ageMs:i}=St(e);return!!n}));if(r){const[t,e]=r;wt(e);try{if(this.playlistOrchestrator)return await this.playlistOrchestrator.startPlaylist(t),!0}catch(a){return!1}}return!1}async checkAndResumeFromPendingNavigation(){const t=this.managers.storageManager.getPendingNavigation();if(!t)return!1;if(Date.now()-t.timestamp>At)return this.managers.storageManager.clearPendingNavigation(),!1;if(!this.isURLPathMatch(t.urlPattern))return t.urlPattern,this.managers.storageManager.clearPendingNavigation(),!1;t.playlistId,t.nextStepId,this.managers.storageManager.clearPendingNavigation();try{if(this.playlistOrchestrator)return await this.playlistOrchestrator.startPlaylist(t.playlistId,{startNodeId:t.nextStepId}),!0}catch(e){return!1}return!1}isURLPathMatch(t){if(!t||"undefined"==typeof window)return!1;const e=window.location.href,n=window.location.pathname,i=t.replace(/[.*+?^${}()|[\]\\]/g,"\\$&").replace(/\\\*/g,".*"),s=new RegExp(i);return s.test(e)||s.test(n)}getOrCreateAnonymousUserId(){if("undefined"==typeof window)return`anonymous_${Date.now()}_${Math.random().toString(36).substring(2,11)}`;const t=this.managers.storageManager.getAnonymousUserData();if(null==t?void 0:t.userId)return t.userId,t.userId;const e=`anonymous_${Date.now()}_${Math.random().toString(36).substring(2,11)}`;return this.managers.storageManager.setAnonymousUserData({userId:e,userData:{},watchedPlaylists:{},timestamp:Date.now()}),e}destroy(){this.lastConfig=null}}function Vt(t){if(!t)return;if("auto"===t){return function(){try{const t=navigator.language||navigator.userLanguage;if(!t)return;return t.split("-")[0].toLowerCase()}catch(t){return}}()}return t.split("-")[0].toLowerCase()}class Ot{constructor(t){e(this,"managers"),e(this,"playerInitializationService"),e(this,"userDataLoadedPromise",null),e(this,"userDataLoadedResolve",null),e(this,"lastUserIdentification",null),this.managers=t}setPlayerInitializationService(t){this.playerInitializationService=t}getLastUserIdentification(){return this.lastUserIdentification}getUserDataLoadedPromise(){return this.userDataLoadedPromise}identifyUser(t,e){let n=e;if(e&&"string"==typeof e.language){const t=Vt(e.language);n={...e,language:t},e.language}this.lastUserIdentification={userId:t,userData:n};const i=bt();i.identifyUser(t,n),this.managers.analyticsManager.setUser({id:t,...n});(i.abTests||[]).length>0&&(this.userDataLoadedPromise=new Promise((t=>{this.userDataLoadedResolve=t}))),this.playerInitializationService&&this.playerInitializationService.fetchUserData(t,n)}async identifyAnonymous(t){if(!this.playerInitializationService)throw new Error("PlayerInitializationService not set");let e=t;if(t&&"string"==typeof t.language){const n=Vt(t.language);e={...t,language:n},t.language}const n=this.playerInitializationService.getOrCreateAnonymousUserId();this.lastUserIdentification={userId:n,userData:e};bt().identifyUser(n,{...e,__isAnonymous:!0}),this.managers.analyticsManager.setUser({id:n,...e}),await this.playerInitializationService.loadAnonymousUserData(n,e)}async recordABTestAttempt(t){var e;try{const n=bt(),i=n.user;if(!i||!(null==(e=n.config)?void 0:e.token))return;const s=(n.abTests||[]).find((e=>e.playlistId===t));if(!s)return;const r=(n.abTestAssignments||{})[s.id];if(!r)return void s.id;s.name,r.assigned;const a=await fetch(`https://player.saltfish.ai/clients/${n.config.token}/users/${i.id}`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({abTestAssignments:{[s.id]:r}})});a.ok?s.name:(a.status,a.statusText)}catch(n){}}resolveUserDataLoaded(){this.userDataLoadedResolve&&(this.userDataLoadedResolve(),this.userDataLoadedResolve=null,this.userDataLoadedPromise=null)}destroy(){this.userDataLoadedPromise=null,this.userDataLoadedResolve=null,this.lastUserIdentification=null}}class Dt{async validatePlaylistStart(t){const{playlistId:e,options:n,eventManager:i}=t;try{const t=bt();if(!t.config)return{isValid:!1,error:"Saltfish Player must be initialized before starting a playlist"};if(!0===t.isAdmin){return{isValid:!0,manifestPath:`https://storage.saltfish.ai/flows2/drafts/${e}.json`,updatedOptions:n}}if(!0===(null==n?void 0:n._startedFromShareLink)&&!0===(null==n?void 0:n._isGlobalShare)){return{isValid:!0,manifestPath:`https://storage.saltfish.ai/flows2/drafts/${e}.json`,updatedOptions:n}}!0===(null==n?void 0:n._startedFromShareLink)&&(null==n||n._isGlobalShare);const s=t.backendPlaylists;if(!s||0===s.length)return Et.handlePlaylistError("No playlist list available from backend validation",{component:"PlaylistValidator",method:"validatePlaylistStart",playlistId:e,errorType:"playlist_backend_unavailable"}),{isValid:!1,error:"No backend playlists available"};const r=s.find((t=>t.id===e));if(!r)return Et.handlePlaylistError(`Playlist ID '${e}' not found in the list provided by backend validation`,{component:"PlaylistValidator",method:"validatePlaylistStart",playlistId:e,errorType:"playlist_not_found",additionalData:{backendPlaylists:s}}),{isValid:!1,error:"Playlist not found in backend list"};if((null==r?void 0:r.hasTriggers)??(null==r?void 0:r.autoStart)??!1){const t=await this.validateTriggerConditions(e,r,i);if(!t.isValid)return t}let a=n;if(null==n?void 0:n.once){const t=await this.validateOnceOptionConditions(e,n,i);if(!t.isValid)return t;a=t.updatedOptions||n}const o=await this.validateDeviceCompatibility(r,e);return o.isValid?{isValid:!0,manifestPath:r.path,updatedOptions:a}:o}catch(s){const t=s instanceof Error?s.message:"Unknown validation error";return Et.handlePlaylistError(`Playlist validation failed: ${t}`,{component:"PlaylistValidator",method:"validatePlaylistStart",playlistId:e,additionalData:{error:s}}),{isValid:!1,error:t}}}async validateTriggerConditions(t,e,n){var i,s;const r=bt();if(!r.user)return Et.handlePlaylistError("User must be identified before starting auto-start playlist",{component:"PlaylistValidator",method:"validateAutoStartConditions",playlistId:t,errorType:"playlist_user_required"}),{isValid:!1,error:"User identification required for triggered playlist"};r.userData||await this.waitForUserData(n);const a=(null==(i=bt().userData)?void 0:i.watchedPlaylists)||{},o=e.hasTriggers??e.autoStart??!1,l=a[t],c=null==(s=e.triggers)?void 0:s.maxVisits,d=(null==l?void 0:l.visitCount)??("completed"===(null==l?void 0:l.status)||"dismissed"===(null==l?void 0:l.status)?1:0);return o&&null!=c&&d>=c?(q(`Playlist ${t} has hasTriggers enabled with maxVisits:${c} and user has ${d} visits. Skipping playlist start.`,{watchedPlaylists:a,triggers:e.triggers}),{isValid:!1,error:`Playlist visit limit reached (${d}/${c})`}):{isValid:!0}}async validateOnceOptionConditions(t,e,n){var i;const s=bt();if(!s.user)return Et.handlePlaylistError("User must be identified before starting playlist with once option",{component:"PlaylistValidator",method:"validateOnceOptionConditions",playlistId:t,errorType:"playlist_auth_required"}),{isValid:!1,error:"User identification required for once option"};s.userData||await this.waitForUserData(n);const r=(null==(i=bt().userData)?void 0:i.watchedPlaylists)||{},a=r[t];if(a&&("completed"===a.status||"dismissed"===a.status))return q(`Playlist ${t} has once option enabled and has already been ${a.status}. Skipping playlist start.`,{watchedPlaylists:r,playlistStatus:a.status}),{isValid:!1,error:`Playlist already ${a.status} with once option`};if(a&&"in_progress"===a.status&&!(null==e?void 0:e.startNodeId)&&a.currentStepId){return{isValid:!0,updatedOptions:{...e,startNodeId:a.currentStepId}}}return{isValid:!0}}async validateDeviceCompatibility(t,e){try{const n=t.deviceType||"both",{isDeviceCompatible:i}=await Promise.resolve().then((()=>Wt));return i(n)?{isValid:!0}:(Et.handlePlaylistError(`Playlist '${e}' is not compatible with this device. Required: ${n}`,{component:"PlaylistValidator",method:"validateDeviceCompatibility",playlistId:e,errorType:"playlist_device_incompatible",additionalData:{requiredDeviceType:n,manifestPath:t.path}}),{isValid:!1,error:`Device incompatible. Required: ${n}`})}catch(n){const i=n instanceof Error?n.message:"Unknown error";return Et.handlePlaylistError(`Device compatibility check failed: ${i}`,{component:"PlaylistValidator",method:"validateDeviceCompatibility",playlistId:e,additionalData:{error:n,manifestPath:t.path}}),{isValid:!1,error:`Device compatibility check failed: ${i}`}}}async waitForUserData(t){return new Promise(((e,n)=>{const i=setTimeout((()=>{t.off("userDataLoaded",s),n(new Error("Timeout waiting for user data"))}),5e3),s=()=>{clearTimeout(i),bt(),e()};t.on("userDataLoaded",s)}))}}class Ft{constructor(t){e(this,"managers"),e(this,"userManagementService"),e(this,"managerOrchestrator"),e(this,"playerInitializationService"),e(this,"stateMachineActionHandler"),this.managers=t}setUserManagementService(t){this.userManagementService=t}setManagerOrchestrator(t){this.managerOrchestrator=t}setPlayerInitializationService(t){this.playerInitializationService=t}setStateMachineActionHandler(t){this.stateMachineActionHandler=t}async startPlaylist(t,e){var n,i,s,r,a;try{const l=this.isInitialized()&&!this.managers.uiManager.getPlayerElement();if(!this.isInitialized()&&this.playerInitializationService){const e=this.playerInitializationService.getLastConfig();if(e)try{await this.playerInitializationService.initialize(e);const t=null==(n=this.userManagementService)?void 0:n.getLastUserIdentification();t&&this.userManagementService&&this.userManagementService.identifyUser(t.userId,t.userData),this.resetManagers(),this.stateMachineActionHandler&&this.stateMachineActionHandler.registerStateMachineActions()}catch(o){throw Et.handleInitializationError(`Failed to reinitialize player: ${o instanceof Error?o.message:"Unknown error"}`,{component:"PlaylistOrchestrator",method:"startPlaylist",playlistId:t,additionalData:{reinitError:o}})}}l&&(this.resetManagers(),this.managers.transitionManager.setTriggerManager(this.managers.triggerManager),this.stateMachineActionHandler&&this.stateMachineActionHandler.registerStateMachineActions());const c=bt();if(!c.config){if(!(null==(i=this.playerInitializationService)?void 0:i.getLastConfig()))throw Et.createError("Saltfish Player must be initialized at least once before starting a playlist",{component:"PlaylistOrchestrator",method:"startPlaylist",playlistId:t});throw Et.createError("Saltfish Player must be initialized before starting a playlist",{component:"PlaylistOrchestrator",method:"startPlaylist",playlistId:t})}c.manifest&&("playing"===c.currentState||"paused"===c.currentState||"loading"===c.currentState||"waitingForInteraction"===c.currentState||"autoplayBlocked"===c.currentState||"minimized"===c.currentState||"idleMode"===c.currentState)&&(this.managerOrchestrator&&this.managerOrchestrator.cleanupCurrentPlaylist(),c.resetForNewPlaylist(),this.stateMachineActionHandler&&this.stateMachineActionHandler.registerStateMachineActions()),"completed"!==c.currentState&&"closing"!==c.currentState||(c.currentState,c.resetForNewPlaylist(),this.stateMachineActionHandler&&this.stateMachineActionHandler.registerStateMachineActions());this.managers.sessionManager.startNewRun();this.managers.triggerManager.markPlaylistAsTriggered(t);const d=null==(s=this.userManagementService)?void 0:s.getUserDataLoadedPromise();if(d&&await d,this.userManagementService&&await this.userManagementService.recordABTestAttempt(t),!this.managers.abTestManager.isPlaylistAvailable(t))return;const h=new Dt,u=await h.validatePlaylistStart({playlistId:t,options:e,eventManager:this.managers.eventManager});if(!u.isValid)return;e=u.updatedOptions||e;const p=u.manifestPath,m=e||{};m?(c.setPlaylistOptions(m),m.position||c.setPlaylistOptions({...m,position:"bottom-right"})):c.setPlaylistOptions({position:"bottom-right"}),this.managers.uiManager.createPlayerUI(this.managers.videoManager,this.managers.cursorManager,this.managers.interactionManager),this.managerOrchestrator&&this.managerOrchestrator.setupUpdaters(),this.managers.uiManager.updatePosition(),c.sendStateMachineEvent({type:"LOAD_MANIFEST"});const g=null==e?void 0:e.persistence;if("undefined"!=typeof window){const e=null==(r=c.user)?void 0:r.id,n=this.managers.storageManager.getProgress(e);if(n&&n[t])c.loadPlaylistProgress(t,n[t]);else if(c.progress[t]){const e={...c.progress};delete e[t],vt.setState((t=>{t.progress=e}))}}this.managers.analyticsManager.trackPlaylistStart(t),this.managers.cursorManager.resetFirstAnimation(),await this.managers.playlistManager.load(p,{...m,persistence:g});const f=bt();if(f.manifest){const t=m.persistence??f.manifest.isPersistent??!0,e=f.playlistOptions||{};f.setPlaylistOptions({...e,...m,persistence:t})}if(m.startNodeId&&f.manifest){f.manifest.steps.find((t=>t.id===m.startNodeId))?f.goToStep(m.startNodeId):console.warn(`[PlaylistOrchestrator] startNodeId '${m.startNodeId}' not found in manifest steps. Starting from default step.`)}if(f.manifest){f.manifest.cursorColor&&this.managers.cursorManager.setColor(f.manifest.cursorColor),f.manifest.cursorLabel&&this.managers.cursorManager.setLabel(f.manifest.cursorLabel);m._triggeredByTriggerManager;const t=f.currentStepId===(null==(a=f.manifest.steps[0])?void 0:a.id);if(f.manifest.idleMode&&t){if(f.manifest.compactFirstStep){const t=this.managers.uiManager.getPlayerElement();null==t||t.classList.add("sf-player--compact"),f.manifest.compactLabel&&this.managers.uiManager.showCompactLabel(f.manifest.compactLabel)}c.setIdleMode()}else c.play()}else c.play();q(`Playlist started: ${t}${f.manifest?` (${f.manifest.name})`:""}`)}catch(l){this.managers.uiManager.hideLoading();bt().sendStateMachineEvent({type:"ERROR",error:l instanceof Error?l:new Error(String(l))}),Et.handlePlaylistError(l,{component:"PlaylistOrchestrator",method:"startPlaylist",playlistId:t,errorType:"playlist_load_failed"})}}resetPlaylist(){const t=bt();t.manifest&&t.goToStep(t.manifest.startStep)}isInitialized(){return!!bt().config}resetManagers(){this.managers.videoManager.reset(),this.managers.cursorManager.reset(),this.managers.interactionManager.reset(),this.managers.transitionManager.reset(),this.managers.uiManager.reset(),this.managers.stepTimeoutManager.reset()}destroy(){}}function Bt(t){const{pattern:e,matchType:n}=t;if(!e)return!0;const i=window.location.href,s=window.location.pathname;if("regex"===n)try{const t=new RegExp(e),n=t.test(i),r=t.test(s),a=n||r;return a}catch(r){return!1}if("contains"===n){return i.includes(e)||s.includes(e)}return i===e||s===e}class Ut{constructor(t){e(this,"managers"),e(this,"destroyCallback",null),e(this,"cursorAnimationListener",null),e(this,"cursorAnimationVideoElement",null),e(this,"cursorAnimationStepId",null),this.managers=t}setDestroyCallback(t){this.destroyCallback=t}registerStateMachineActions(){bt().registerStateMachineActions({startVideoPlayback:t=>{this.handleStartVideoPlayback(t)},pauseVideoPlayback:()=>{this.handlePauseVideoPlayback()},startMutedLoopedVideo:()=>{this.handleStartMutedLoopedVideo()},startIdleModeVideo:t=>{this.handleStartIdleModeVideo(t)},trackPlaylistComplete:()=>{this.handleTrackPlaylistComplete()},handleError:t=>{this.handleError(t)},hideError:()=>{this.handleHideError()},showLoadingState:()=>{this.handleShowLoadingState()},hideLoadingState:()=>{this.handleHideLoadingState()},hideVideoControls:()=>{this.handleHideVideoControls()},showVideoControls:()=>{this.handleShowVideoControls()},showPlayButton:()=>{this.handleShowPlayButton()},hidePlayButton:()=>{this.handleHidePlayButton()},enablePlayButtonProminent:()=>{this.handleEnablePlayButtonProminent()},disablePlayButtonProminent:()=>{this.handleDisablePlayButtonProminent()},enterCompactMode:()=>{this.handleEnterCompactMode()},exitCompactMode:()=>{this.handleExitCompactMode()},triggerPlaylistDismissed:()=>{this.handleTriggerPlaylistDismissed()},scheduleDestroy:()=>{this.handleScheduleDestroy()}})}getVideoUrl(t){var e;const n=null==(e=bt().userData)?void 0:e.language;let i;if(n&&t.translations&&t.translations[n]){i=t.translations[n].videoUrl}else i=t.compressedUrl||t.videoUrl;return i&&""!==i.trim()||!t.audioUrl||""===t.audioUrl.trim()?i:(t.id,t.audioUrl)}isUsingAudioFallback(t){var e;const n=null==(e=bt().userData)?void 0:e.language;let i;return i=n&&t.translations&&t.translations[n]?t.translations[n].videoUrl:t.compressedUrl||t.videoUrl,!(i&&""!==i.trim()||!t.audioUrl||""===t.audioUrl.trim())}findNextVideoUrl(t){const e=bt();if(!e.manifest||!t)return null;if(t.transitions.length>0){const n=t.transitions[0];if("url-path"===n.type||"dom-click"===n.type)return null;const i=n.nextStep,s=e.manifest.steps.find((t=>t.id===i));if(s)return this.getVideoUrl(s)}const n=e.manifest.steps.findIndex((e=>e.id===t.id));return n>=0&&n<e.manifest.steps.length-1?this.getVideoUrl(e.manifest.steps[n+1]):null}destroy(){this.cleanupCursorAnimationListener()}cleanupCursorAnimationListener(t){t&&this.cursorAnimationStepId&&t!==this.cursorAnimationStepId?this.cursorAnimationStepId:this.cursorAnimationListener&&this.cursorAnimationVideoElement&&(this.cursorAnimationVideoElement.removeEventListener("timeupdate",this.cursorAnimationListener),this.cursorAnimationListener=null,this.cursorAnimationVideoElement=null,this.cursorAnimationStepId=null)}scheduleCursorAnimation(t,e){this.cleanupCursorAnimationListener();let n=t.showAtSeconds??0;if("number"==typeof n&&isFinite(n)||(n=0),n<0&&(n=0),n<=0)this.managers.cursorManager.animate(t);else{const i=this.managers.videoManager.getVideoElement();if(!i)return;let s=!1,r=!1;const a=()=>{if(s)return;const e=i.currentTime,a=i.duration;if(a&&!isNaN(a)&&n>a&&!r)return r=!0,s=!0,this.cleanupCursorAnimationListener(),void this.managers.cursorManager.animate(t);e>=n&&(s=!0,this.cleanupCursorAnimationListener(),this.managers.cursorManager.animate(t))},o=()=>{if(!s){const n=bt();if(n.currentStepId!==e)return n.currentStepId,void this.cleanupCursorAnimationListener(e);i.duration,s=!0,this.managers.cursorManager.animate(t),this.cleanupCursorAnimationListener()}};this.cursorAnimationListener=()=>{a()},this.cursorAnimationVideoElement=i,this.cursorAnimationStepId=e,i.addEventListener("timeupdate",this.cursorAnimationListener),i.addEventListener("ended",o,{once:!0})}}async validateStepUrlRequirement(t){if(!t.urlRequirement)return!0;t.id,this.managers.transitionManager.startStateMachineValidation();try{const e=await async function(t,e=20,n=100){if(!t)return!0;for(let i=0;i<e;i++){if(Bt(t))return!0;if(i<e-1&&(await new Promise((t=>setTimeout(t,n))),!window._saltfishPlayer))return!1}return t.pattern,t.matchType,!1}(t.urlRequirement);if(!e){t.id;const e=window._saltfishPlayer;e&&"function"==typeof e.destroy&&e.destroy()}return e}finally{this.managers.transitionManager.endStateMachineValidation()}}async handleStartVideoPlayback(t){if(!t.currentStep)return;const e=t.currentStep;if(e.urlRequirement){e.id;if(!(await this.validateStepUrlRequirement(e)))return}this.managers.uiManager.updatePosition(),this.managers.uiManager.showPlayer();const n=this.getVideoUrl(e),i=this.isUsingAudioFallback(e);if(i){const t=bt().manifest,n=e.gifUrl,i=null==t?void 0:t.avatarThumbnailUrl;this.managers.videoManager.showAudioFallbackOverlay(n,i)}else this.managers.videoManager.hideAudioFallbackOverlay();try{this.managers.interactionManager.clearButtons(),e.buttons&&this.managers.interactionManager.createButtons(e.buttons),e.cursorAnimations&&e.cursorAnimations.length;const t=e.buttons&&e.buttons.length>0||e.transitions.some((t=>"dom-click"===t.type||"url-path"===t.type||"dom-element-visible"===t.type)),s=t?"manual":"auto";t&&this.managers.transitionManager.setupTransitions(e,!1,!0),this.managers.videoManager.setCompletionPolicy(s,(()=>{var n;const i=bt();if(t){const t=e.transitions.find((t=>"timeout"===t.type)),s=null==(n=e.buttons)?void 0:n.some((t=>"goto"===t.action.type||"next"===t.action.type));if(t&&!s){const n=t.timeout||0;t.nextStep,setTimeout((()=>{var n;const i=bt();i.currentStepId!==e.id||"waitingForInteraction"!==i.currentState&&"playing"!==i.currentState?i.currentState:(t.nextStep,null==(n=i.goToStep)||n.call(i,t.nextStep))}),n),i.sendStateMachineEvent({type:"VIDEO_FINISHED_WAIT",step:e})}else i.sendStateMachineEvent({type:"VIDEO_FINISHED_WAIT",step:e})}else{const t=e.transitions.find((t=>"timeout"===t.type));t&&t.timeout&&t.timeout>0?(t.timeout,this.managers.transitionManager.setupTransitions(e,!1)):this.managers.transitionManager.setupTransitions(e,!0);e.transitions.some((t=>i.manifest.steps.some((e=>e.id===t.nextStep))))||i.sendStateMachineEvent({type:"COMPLETE_PLAYLIST"})}}));const r=()=>{var t,n;const i=bt(),s=(null==(t=i.manifest)?void 0:t.captions)??!0,r=null==(n=i.userData)?void 0:n.language;let a=e.transcript;if(r&&e.translations&&e.translations[r]){const t=e.translations[r].transcript;t&&(a=t,e.id)}a?(e.id,this.managers.videoManager.loadTranscript(a,s)):(e.id,this.managers.videoManager.loadTranscript(null,!0))};this.managers.videoManager.loadVideo(n).then((()=>{this.managers.uiManager.hideError(),r(),e.cursorAnimations&&e.cursorAnimations.length>0?(e.id,this.managers.cursorManager.setShouldShowCursor(!0),this.scheduleCursorAnimation(e.cursorAnimations[0],e.id)):(e.id,this.managers.cursorManager.setShouldShowCursor(!1)),i?this.managers.videoManager.startAudioVisualization():this.managers.videoManager.initializeAudioForVideo(),this.managers.videoManager.play();const t=this.findNextVideoUrl(e);t&&this.managers.videoManager.preloadNextVideo(t)})).catch((t=>{var n;this.managers.uiManager.showError(t instanceof Error?t:new Error(`Failed to load video: ${t}`),"video");const i=bt(),s=t instanceof Error?t:new Error(`Failed to load video: ${t}`),r=t;this.managers.eventManager.trigger("error",{timestamp:Date.now(),playlistId:(null==(n=i.manifest)?void 0:n.id)||void 0,stepId:e.id,error:s,errorType:"video",videoUrl:null==r?void 0:r.videoUrl,mediaErrorCode:null==r?void 0:r.mediaErrorCode,mediaErrorMessage:null==r?void 0:r.mediaErrorMessage,failureReason:null==r?void 0:r.failureReason})}))}catch(s){}}handlePauseVideoPlayback(){this.managers.videoManager.pause()}handleStartMutedLoopedVideo(){const t=this.managers.videoManager.getVideoElement();t&&(t.muted=!0,t.loop=!0,t.play().catch((()=>{})))}handleStartIdleModeVideo(t){if(!t.currentStep)return;const e=t.currentStep,n=this.getVideoUrl(e),i=this.isUsingAudioFallback(e);if(this.managers.uiManager.showPlayer(),i){const t=bt().manifest,n=e.gifUrl,i=null==t?void 0:t.avatarThumbnailUrl;this.managers.videoManager.showAudioFallbackOverlay(n,i)}else this.managers.videoManager.hideAudioFallbackOverlay();this.managers.videoManager.loadVideo(n).then((()=>{this.managers.uiManager.hideError(),i&&this.managers.videoManager.startAudioVisualization();const t=this.managers.videoManager.getVideoElement();t&&(t.muted=!0,t.loop=!0,t.play().catch((()=>{})))})).catch((t=>{}))}handleTrackPlaylistComplete(){var t,e;const n=bt();if(n.manifest&&this.managers.eventManager){const i=n.manifest.id;this.managers.eventManager.trigger("playlistEnded",{timestamp:Date.now(),playlist:{id:i,title:n.manifest.name}});if(((null==(t=n.playlistOptions)?void 0:t.persistence)??!0)&&n.progress[i]){const t={...n.progress};delete t[i];const s=null==(e=n.user)?void 0:e.id;this.managers.storageManager.setProgress(t,s)}}}handleError(t){var e,n;if(null==(e=t.error)||e.message,t.error&&this.managers.uiManager.getPlayerElement()){this.managers.uiManager.showError(t.error,"player");const e=bt();this.managers.eventManager.trigger("error",{timestamp:Date.now(),playlistId:(null==(n=e.manifest)?void 0:n.id)||void 0,stepId:e.currentStepId||void 0,error:t.error,errorType:"player"})}}handleHideError(){this.managers.uiManager.hideError()}handleShowLoadingState(){this.managers.uiManager.showLoading("Loading...")}handleHideLoadingState(){this.managers.uiManager.hideLoading()}handleHideVideoControls(){this.managers.videoManager.hideProgressBar(),this.managers.videoManager.hideMuteButton()}handleShowVideoControls(){this.managers.videoManager.showProgressBar(),this.managers.videoManager.showMuteButton()}handleShowPlayButton(){this.managers.uiManager.updatePlayPauseButton("paused")}handleHidePlayButton(){this.managers.uiManager.updatePlayPauseButton("playing")}handleEnablePlayButtonProminent(){this.managers.uiManager.enablePlayButtonProminent()}handleDisablePlayButtonProminent(){this.managers.uiManager.disablePlayButtonProminent()}handleEnterCompactMode(){var t,e,n;const i=bt();if(i.manifest&&i.currentStepId===(null==(t=i.manifest.steps[0])?void 0:t.id)&&(null==(e=i.manifest)?void 0:e.compactFirstStep)){const t=this.managers.uiManager.getPlayerElement();null==t||t.classList.add("sf-player--compact"),(null==(n=i.manifest)?void 0:n.compactLabel)&&this.managers.uiManager.showCompactLabel(i.manifest.compactLabel)}}handleExitCompactMode(){const t=this.managers.uiManager.getPlayerElement();null==t||t.classList.remove("sf-player--compact"),this.managers.uiManager.hideCompactLabel()}handleTriggerPlaylistDismissed(){const t=bt();t.manifest&&this.managers.eventManager&&this.managers.eventManager.trigger("playlistDismissed",{timestamp:Date.now(),playlist:{id:t.manifest.id,title:t.manifest.name}})}handleScheduleDestroy(){setTimeout((()=>{this.destroyCallback&&this.destroyCallback()}),0)}}function Nt(t,e){let n=null;const i=()=>{n=t.querySelector(".sf-player__minimize-button")};i();let s={currentState:"",isMinimized:!1,currentStepId:null};function r(t,n){var i;if(!e)return;const s=null==(i=null==n?void 0:n.steps)?void 0:i.find((e=>e.id===t));s&&s.cursorAnimations&&s.cursorAnimations.length>0&&e.setShouldShowCursor(!0)}return vt.subscribe((a=>{var o,l,c,d;n||i(),a.currentState!==s.currentState&&(o=a.currentState,["sf-player--idle","sf-player--loading","sf-player--playing","sf-player--paused","sf-player--waitingForInteraction","sf-player--autoplayBlocked","sf-player--idleMode","sf-player--error","sf-player--completed","sf-player--completedWaitingForInteraction"].forEach((e=>{t.classList.remove(e)})),t.classList.add(`sf-player--${o}`)),a.isMinimized!==s.isMinimized&&(l=a.isMinimized,c=a.currentStepId,d=a.manifest,l?(t.classList.add("sf-player--minimized"),e&&e.setShouldShowCursor(!1)):(t.classList.remove("sf-player--minimized"),r(c,d)),function(t){if(!n)return;n.innerHTML=t?'\n <svg width="18" height="18" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">\n <path d="M12 5v14M5 12h14" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>\n </svg>\n ':'\n <svg width="20" height="20" viewBox="0 0 256 256" fill="currentColor" xmlns="http://www.w3.org/2000/svg">\n <path d="M205.66,194.34a8,8,0,0,1-11.32,11.32L128,139.31,61.66,205.66a8,8,0,0,1-11.32-11.32L116.69,128,50.34,61.66A8,8,0,0,1,61.66,50.34L128,116.69l66.34-66.35a8,8,0,0,1,11.32,11.32L139.31,128Z"></path>\n </svg>\n '}(a.isMinimized)),a.currentStepId!==s.currentStepId&&(a.isMinimized||r(a.currentStepId,a.manifest)),s={currentState:a.currentState,isMinimized:a.isMinimized,currentStepId:a.currentStepId}}))}function Rt(t){let e=null,n=null,i=null,s=null;const r=vt.subscribe((r=>{var a;if(e===r.currentState&&i===r.isMinimized&&s===r.currentStepId)return;const o=e,l=n,c=i,d=s;n=e,e=r.currentState,i=r.isMinimized,s=r.currentStepId;const h={prevPreviousState:l,previousState:o,currentState:r.currentState,currentStepId:r.currentStepId,isMinimized:r.isMinimized};null==(a=r.manifest)||a.id,function(t,e,n){const{prevPreviousState:i,previousState:s,currentState:r,currentStepId:a}=t,o="playing"===r&&"paused"===s&&"loading"===i,l="playing"===r&&("autoplayBlocked"===s||"idleMode"===s);if((o||l)&&e.manifest&&a){if(a===e.manifest.startStep)return e.manifest.id,void n.trigger("playlistStarted",{timestamp:Date.now(),playlist:{id:e.manifest.id,title:e.manifest.name}})}"paused"===s&&"playing"===r?n.trigger("playerResumed",{timestamp:Date.now(),previousState:s,currentState:r}):"playing"===s&&"paused"===r&&n.trigger("playerPaused",{timestamp:Date.now(),previousState:s,currentState:r})}(h,r,t),function(t,e,n,i){const{previousState:s,currentState:r,isMinimized:a}=t,o=i||!1;!a&&o?n.trigger("playerMaximized",{timestamp:Date.now(),previousState:s,currentState:r}):a&&!o&&n.trigger("playerMinimized",{timestamp:Date.now(),previousState:s,currentState:r})}(h,0,t,c),function(t,e,n,i){var s,r,a;const{prevPreviousState:o,previousState:l,currentStepId:c,currentState:d}=t,h=e.currentStepId?((null==(s=e.manifest)?void 0:s.steps)||[]).find((t=>t.id===e.currentStepId)):null;null==h||h.id,null==(r=e.manifest)||r.id,e.manifest;const u=i&&e.manifest&&(i!==c||"waitingForInteraction"===d||"completed"===d);if(e.manifest,u){const t=((null==(a=e.manifest)?void 0:a.steps)||[]).find((t=>t.id===i));null==t||t.id,t&&(t.id,n.trigger("stepEnded",{timestamp:Date.now(),step:{id:t.id,title:t.title||t.id},playlist:{id:e.manifest.id,title:e.manifest.name}}))}const p=c!==i&&"playing"===d,m=("autoplayBlocked"===l||"idleMode"===l)&&"playing"===d&&i===c,g="loading"===o&&"paused"===l&&"playing"===d&&c,f=h&&e.manifest&&(p||m||g);null==h||h.id,e.manifest,f&&(h.id,n.trigger("stepStarted",{timestamp:Date.now(),step:{id:h.id,title:h.title||h.id},playlist:{id:e.manifest.id,title:e.manifest.name}}))}(h,r,t,d),function(t,e,n){var i;const{currentState:s,previousState:r}=t;"error"===s&&"error"!==r&&e.error&&n.trigger("error",{timestamp:Date.now(),playlistId:null==(i=e.manifest)?void 0:i.id,stepId:e.currentStepId,error:e.error,errorType:"state"})}(h,r,t)}));return r}const Ht=class t{constructor(t){e(this,"managers"),e(this,"uiUpdaterUnsubscribe",null),e(this,"eventUpdaterUnsubscribe",null),e(this,"cursorAnimationListener",null),e(this,"cursorAnimationVideoElement",null),e(this,"cursorAnimationStepId",null),e(this,"isInitialized",!1),this.managers=t}setInitialized(t){this.isInitialized=t}setupUpdaters(){this.uiUpdaterUnsubscribe&&this.uiUpdaterUnsubscribe(),this.eventUpdaterUnsubscribe&&this.eventUpdaterUnsubscribe();const t=this.managers.uiManager.getPlayerElement();t&&(this.uiUpdaterUnsubscribe=Nt(t,this.managers.cursorManager)),this.eventUpdaterUnsubscribe=Rt(this.managers.eventManager);const e=vt.subscribe((t=>{this.managers.stepTimeoutManager.update({currentState:t.currentState,currentStepId:t.currentStepId,isMinimized:t.isMinimized,previousState:void 0})})),n=this.eventUpdaterUnsubscribe;this.eventUpdaterUnsubscribe=()=>{n&&n(),e()}}cleanupCursorAnimationListener(t){t&&this.cursorAnimationStepId&&t!==this.cursorAnimationStepId?this.cursorAnimationStepId:this.cursorAnimationListener&&this.cursorAnimationVideoElement&&(this.cursorAnimationVideoElement.removeEventListener("timeupdate",this.cursorAnimationListener),this.cursorAnimationListener=null,this.cursorAnimationVideoElement=null,this.cursorAnimationStepId=null)}scheduleCursorAnimation(t,e){this.cleanupCursorAnimationListener();let n=t.showAtSeconds??0;if("number"==typeof n&&isFinite(n)||(n=0),n<0&&(n=0),n<=0)this.managers.cursorManager.animate(t);else{const i=this.managers.videoManager.getVideoElement();if(!i)return;let s=!1,r=!1;const a=()=>{if(s)return;const e=i.currentTime,a=i.duration;if(a&&!isNaN(a)&&n>a&&!r)return r=!0,s=!0,this.cleanupCursorAnimationListener(),void this.managers.cursorManager.animate(t);e>=n&&(s=!0,this.cleanupCursorAnimationListener(),this.managers.cursorManager.animate(t))},o=()=>{if(!s){const n=bt();if(n.currentStepId!==e)return n.currentStepId,void this.cleanupCursorAnimationListener(e);i.duration,s=!0,this.managers.cursorManager.animate(t),this.cleanupCursorAnimationListener()}};this.cursorAnimationListener=()=>{a()},this.cursorAnimationVideoElement=i,this.cursorAnimationStepId=e,i.addEventListener("timeupdate",this.cursorAnimationListener),i.addEventListener("ended",o,{once:!0})}}handleStoreChanges(){if(!this.isInitialized)return;const e=bt();if(e.currentState!==t.prevState.currentState||e.currentStepId!==t.prevState.currentStepId||e.isMinimized!==t.prevState.isMinimized){if(t.prevState.currentState,e.currentState,t.prevState.currentStepId,e.currentStepId,t.prevState.isMinimized,e.isMinimized,this.managers.uiManager.getPlayerRoot()&&this.managers.uiManager.getPlayerElement()&&this.managers.uiManager.updatePosition(),this.managers.videoManager.transcriptManager.handleStateChange(e.currentState),"autoplayBlocked"===e.currentState)this.managers.cursorManager.stopAnimation(),this.managers.cursorManager.setShouldShowCursor(!1);else if("playing"===e.currentState&&"autoplayBlocked"===t.prevState.currentState){const t=e.manifest,n=null==t?void 0:t.steps.find((t=>t.id===e.currentStepId));(null==n?void 0:n.cursorAnimations)&&n.cursorAnimations.length>0&&(this.managers.cursorManager.setShouldShowCursor(!0),this.scheduleCursorAnimation(n.cursorAnimations[0],e.currentStepId||"unknown"))}else"completed"!==e.currentState&&"closing"!==e.currentState||this.cleanupPlaylist();e.isMinimized!==t.prevState.isMinimized&&this.managers.uiManager.handleMinimizeStateChange(e.isMinimized),t.prevState={currentState:e.currentState,currentStepId:e.currentStepId,isMinimized:e.isMinimized}}}cleanupCurrentPlaylist(){try{this.cleanupCursorAnimationListener(),this.eventUpdaterUnsubscribe&&(this.eventUpdaterUnsubscribe(),this.eventUpdaterUnsubscribe=null),this.managers.stepTimeoutManager&&this.managers.stepTimeoutManager.reset(),this.managers.videoManager&&(this.managers.videoManager.pause(),this.managers.videoManager.reset()),this.managers.cursorManager&&(this.managers.cursorManager.stopAnimation(),this.managers.cursorManager.setShouldShowCursor(!1)),this.managers.transitionManager&&this.managers.transitionManager.cleanupTransitions(),this.managers.interactionManager&&this.managers.interactionManager.clearButtons(),this.managers.uiManager.reset()}catch(t){Et.handleCleanupError(t,{component:"ManagerOrchestrator",method:"cleanupCurrentPlaylist"})}}cleanupPlaylist(){var t;if(this.isInitialized)try{const e=bt();e.currentState,e.currentStepId,e.isMinimized,null==(t=e.manifest)||t.id,this.uiUpdaterUnsubscribe&&(this.uiUpdaterUnsubscribe(),this.uiUpdaterUnsubscribe=null),this.managers.transitionManager.destroy(),this.managers.videoManager.destroy(),this.managers.cursorManager.destroy(),this.managers.interactionManager.destroy(),this.managers.playlistManager.destroy(),this.managers.stepTimeoutManager.destroy(),this.managers.uiManager.destroy()}catch(e){Et.handleCleanupError(e,{component:"ManagerOrchestrator",method:"cleanupPlaylist"})}else console.warn("Saltfish playlist Player is not initialized")}destroyAll(){var t;if(this.isInitialized)try{const e=bt();e.currentState,e.currentStepId,e.isMinimized,null==(t=e.manifest)||t.id,this.cleanupCursorAnimationListener(),this.uiUpdaterUnsubscribe&&(this.uiUpdaterUnsubscribe(),this.uiUpdaterUnsubscribe=null),this.eventUpdaterUnsubscribe&&(this.eventUpdaterUnsubscribe(),this.eventUpdaterUnsubscribe=null),this.managers.transitionManager.destroy(),this.managers.triggerManager.destroy(),this.managers.videoManager.destroy(),this.managers.cursorManager.destroy(),this.managers.interactionManager.destroy(),this.managers.analyticsManager.destroy(),this.managers.sessionManager.destroy(),this.managers.playlistManager.destroy(),this.managers.stepTimeoutManager.destroy(),this.managers.uiManager.destroy(),this.isInitialized=!1,e.reset()}catch(e){Et.handleCleanupError(e,{component:"ManagerOrchestrator",method:"destroyAll"});try{this.isInitialized=!1;bt().reset()}catch(n){Et.handleCleanupError(n,{component:"ManagerOrchestrator",method:"destroyAll",additionalData:{originalError:e}})}}else console.warn("Saltfish playlist Player is not initialized")}getManagers(){return this.managers}destroy(){this.destroyAll()}};e(Ht,"prevState",{currentState:"idle",currentStepId:null,isMinimized:!1});let $t=Ht;class Yt{constructor(){e(this,"container",null),e(this,"shadowRoot",null),e(this,"styleElement",null)}create(){if(this.container)return;this.container=document.createElement("div"),this.container.id="saltfish-container",this.container.appendChild(document.createTextNode("")),document.body.appendChild(this.container),this.shadowRoot=this.container.attachShadow({mode:"open"});try{const t=new CSSStyleSheet;t.replaceSync(this.getBaseStyles()),this.shadowRoot.adoptedStyleSheets=[t]}catch(e){this.styleElement=document.createElement("style"),this.styleElement.textContent=this.getBaseStyles(),this.shadowRoot.appendChild(this.styleElement)}const t=document.createElement("div");t.id="sf-player-root",this.shadowRoot.appendChild(t)}getShadowRoot(){return this.shadowRoot}getRootElement(){if(!this.shadowRoot)return null;return this.shadowRoot.getElementById("sf-player-root")}addStyles(t){if(this.shadowRoot){if(this.shadowRoot.adoptedStyleSheets&&this.shadowRoot.adoptedStyleSheets.length>0)try{const e=this.shadowRoot.adoptedStyleSheets[0],n=Array.from(e.cssRules).map((t=>t.cssText)).join("\n");return void e.replaceSync(n+"\n"+t)}catch(e){console.warn("ShadowDOMManager: Failed to append to adoptedStyleSheet:",e)}this.styleElement&&(this.styleElement.textContent+=t)}}remove(){this.container&&(document.body.removeChild(this.container),this.container=null,this.shadowRoot=null,this.styleElement=null)}getBaseStyles(){return"\n /* \n * CSS Reset for the Saltfish playlist Player\n * Minimal reset for the Shadow DOM to ensure consistent rendering\n */\n\n:host {\n all: initial;\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;\n box-sizing: border-box;\n}\n\n:host *,\n:host *::before,\n:host *::after {\n box-sizing: inherit;\n margin: 0;\n padding: 0;\n}\n\nbutton {\n background: none;\n border: none;\n cursor: pointer;\n font: inherit;\n outline: none;\n padding: 0;\n}\n\n/* Utility classes for CSP-compliant styling */\n.sf-hidden {\n display: none !important;\n} \n /* \n * Variables for the Saltfish playlist Player\n * Defines all design tokens used throughout the application\n */\n\n:host {\n /* Colors */\n --sf-primary-color: #4a9bff;\n --sf-secondary-color: #6ccfff;\n --sf-background-color: #1e1e1e;\n --sf-text-color: #ffffff;\n --sf-button-bg: rgba(0, 0, 0, 0.5);\n --sf-button-hover-bg: rgba(0, 0, 0, 0.7);\n --sf-overlay-gradient: linear-gradient(180deg, rgba(0, 0, 0, 0.7) 0%, transparent 30%, transparent 70%, rgba(0, 0, 0, 0.7) 100%);\n --sf-progress-gradient: linear-gradient(90deg, var(--sf-primary-color), var(--sf-secondary-color));\n --sf-error-color: #ff4d4d;\n --sf-error-bg: rgba(255, 77, 77, 0.1);\n \n /* Spacing */\n --sf-spacing-xs: 4px;\n --sf-spacing-sm: 8px;\n --sf-spacing-md: 12px;\n --sf-spacing-lg: 16px;\n --sf-spacing-xl: 24px;\n \n /* Sizes */\n --sf-player-width: 240px;\n --sf-player-height: 336px;\n --sf-player-min-width: 80px;\n --sf-player-min-height: 80px;\n --sf-player-compact-width: 120px;\n --sf-player-compact-height: 120px;\n --sf-control-button-size: 24px;\n --sf-play-button-size: 60px;\n --sf-play-button-compact-size: 44px;\n --sf-minimize-button-size: 34px;\n --sf-mute-button-size: 32px;\n --sf-cc-button-size: 32px;\n --sf-cursor-size: 32px;\n \n /* Border radius */\n --sf-border-radius-sm: 4px;\n --sf-border-radius-md: 8px;\n --sf-border-radius-lg: 16px;\n --sf-border-radius-circle: 50%;\n \n /* Transitions */\n --sf-transition-fast: 0.1s ease;\n --sf-transition-normal: 0.2s ease;\n --sf-transition-slow: 0.3s cubic-bezier(0.25, 0.8, 0.25, 1);\n \n /* Shadows */\n --sf-shadow-small: 0 2px 5px rgba(0, 0, 0, 0.2);\n --sf-shadow-medium: 0 4px 8px rgba(0, 0, 0, 0.15);\n --sf-shadow-large: 0 10px 25px rgba(0, 0, 0, 0.2);\n \n /* Z-index layering */\n --sf-z-index-base: 1;\n --sf-z-index-overlay: 2;\n --sf-z-index-controls: 10;\n --sf-z-index-cursor: 9999;\n --sf-z-index-player: 2147483648;\n \n /* Font sizes */\n --sf-font-size-sm: 14px;\n --sf-font-size-md: 16px;\n --sf-font-size-lg: 18px;\n --sf-font-size-xl: 24px;\n} \n\n/* Mobile device responsive adjustments - make player smaller for mobile screens */\n@media (max-width: 768px) {\n :host {\n /* Reduce player size on mobile for better space utilization */\n --sf-player-width: 180px; /* 25% smaller than desktop (240px -> 180px) */\n --sf-player-height: 252px; /* 25% smaller than desktop (336px -> 252px) */\n --sf-player-min-width: 60px; /* Smaller when minimized (80px -> 60px) */\n --sf-player-min-height: 60px; /* Smaller when minimized (80px -> 60px) */\n --sf-player-compact-width: 90px; /* Smaller compact mode for mobile (120px -> 90px) */\n --sf-player-compact-height: 90px; /* Smaller compact mode for mobile (120px -> 90px) */\n\n /* Keep controls touch-friendly despite smaller player size */\n --sf-play-button-size: 44px; /* Smaller but still touch-friendly (60px -> 44px) */\n --sf-play-button-compact-size: 36px; /* Touch-friendly compact play button */\n --sf-control-button-size: 28px; /* Keep larger for touch targets (24px -> 28px) */\n --sf-mute-button-size: 26px; /* Smaller for mobile (32px -> 26px) */\n --sf-cc-button-size: 26px; /* Smaller for mobile (32px -> 26px) */\n --sf-minimize-button-size: 26px; /* Match other mobile button sizes */\n }\n}\n\n/* Touch device specific adjustments (tablets and larger touch devices, excluding mobile) */\n@media (pointer: coarse) and (min-width: 769px) {\n :host {\n /* Ensure touch-friendly sizes even on larger touch devices */\n --sf-control-button-size: 28px;\n --sf-mute-button-size: 38px;\n --sf-cc-button-size: 38px;\n --sf-minimize-button-size: 38px; /* Match other touch device button sizes */\n }\n} \n\n /* \n * Player component styles for the Saltfish playlist Player\n * Following BEM naming convention\n */\n\n/* Main player container */\n.sf-player {\n border-radius: var(--sf-border-radius-md);\n box-shadow: 0 15px 30px rgba(0, 0, 0, 0.15), 0 5px 15px rgba(0, 0, 0, 0.08);\n position: relative;\n backdrop-filter: blur(10px);\n -webkit-backdrop-filter: blur(10px);\n opacity: 0;\n /* Smooth transitions for size changes and opacity */\n transition: opacity 0.3s ease-in-out,\n width 0.3s cubic-bezier(0.25, 0.8, 0.25, 1),\n height 0.3s cubic-bezier(0.25, 0.8, 0.25, 1),\n border-radius 0.3s cubic-bezier(0.25, 0.8, 0.25, 1);\n}\n\n/* Player visible state - show with fade in */\n.sf-player--visible {\n opacity: 1;\n}\n\n/* Gradient overlay now moved to video container - see _video.css */\n\n/* Full-size player state */\n.sf-player:not(.sf-player--minimized) {\n width: var(--sf-player-width);\n height: var(--sf-player-height);\n}\n\n/* Autoplay fallback state - ensure play button is visible */\n.sf-player--waiting-for-user-interaction .sf-controls-container__play-button {\n display: flex !important;\n opacity: 1 !important;\n visibility: visible !important;\n}\n\n/* Also show the center play button in autoplay fallback state */\n.sf-player--waiting-for-user-interaction .sf-player__center-play-button {\n display: flex !important;\n opacity: 1 !important;\n z-index: calc(var(--sf-z-index-controls) + 20) !important; /* Higher z-index to appear above overlay */\n}\n\n/* Make the autoplay fallback state more prominent to indicate need for interaction */\n.sf-player--waiting-for-user-interaction::after {\n content: '';\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(0, 0, 0, 0.3);\n pointer-events: none;\n z-index: var(--sf-z-index-overlay);\n}\n\n/* Player state: minimized */\n.sf-player--minimized {\n /* Equal width and height are essential for maintaining a perfect circle when using border-radius: 50% */\n width: var(--sf-player-min-width);\n height: var(--sf-player-min-height);\n border-radius: var(--sf-border-radius-circle);\n box-shadow: 0 15px 30px rgba(0, 0, 0, 0.20), 0 5px 15px rgba(0, 0, 0, 0.12);\n cursor: pointer;\n /* Force overriding any inline styles that might be applied */\n max-width: var(--sf-player-min-width) !important;\n max-height: var(--sf-player-min-height) !important;\n min-width: var(--sf-player-min-width) !important;\n min-height: var(--sf-player-min-height) !important;\n}\n\n/* Player state: compact (first step, small rounded) */\n.sf-player--compact {\n width: var(--sf-player-compact-width) !important;\n height: var(--sf-player-compact-height) !important;\n border-radius: var(--sf-border-radius-circle);\n box-shadow: 0 15px 30px rgba(0, 0, 0, 0.20), 0 5px 15px rgba(0, 0, 0, 0.12);\n cursor: pointer; /* Whole bubble is clickable */\n /* Force overriding any inline styles that might be applied */\n max-width: var(--sf-player-compact-width) !important;\n max-height: var(--sf-player-compact-height) !important;\n min-width: var(--sf-player-compact-width) !important;\n min-height: var(--sf-player-compact-height) !important;\n}\n\n/* Hide center play button in compact mode - the whole bubble is clickable */\n.sf-player--compact .sf-player__center-play-button {\n display: none !important;\n}\n\n/* Hide elements in compact mode */\n.sf-player--compact .sf-player__logo,\n.sf-player--compact .sf-player__minimize-button {\n display: none;\n}\n\n/* Hide gradient overlay when in compact mode - see _video.css */\n.sf-player--compact .sf-video-container::after {\n display: none;\n}\n\n/* Hide controls when minimized */\n.sf-player--minimized .sf-controls-container {\n display: none;\n}\n\n/* Hide controls when in compact mode */\n.sf-player--compact .sf-controls-container {\n display: none;\n}\n\n/* Only show the minimize button when hovering on minimized player */\n.sf-player--minimized .sf-player__minimize-button {\n opacity: 0;\n}\n\n.sf-player--minimized:hover .sf-player__minimize-button {\n opacity: 1;\n}\n\n/* Player root element */\n#sf-player-root {\n position: fixed;\n z-index: var(--sf-z-index-player);\n}\n\n/* Fixed positioning classes */\n.sf-player-root--bottom-left {\n bottom: 20px;\n left: 20px;\n}\n\n.sf-player-root--bottom-right {\n bottom: 20px;\n right: 20px;\n}\n\n/* Player error message */\n.sf-player__error {\n padding: var(--sf-spacing-md);\n color: var(--sf-error-color);\n background-color: var(--sf-error-bg);\n border-radius: var(--sf-border-radius-md);\n margin: var(--sf-spacing-sm);\n font-size: var(--sf-font-size-sm);\n border-left: 4px solid var(--sf-error-color);\n}\n\n/* Minimize button */\n.sf-player__minimize-button {\n position: absolute;\n top: 8px;\n right: 4px;\n width: var(--sf-minimize-button-size);\n height: var(--sf-minimize-button-size);\n background: none !important;\n border-radius: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n cursor: pointer;\n z-index: var(--sf-z-index-controls);\n color: white;\n border: none;\n font-size: calc(var(--sf-font-size-sm) + 4px);\n transition: all var(--sf-transition-normal);\n text-shadow: 0 1px 3px rgba(0, 0, 0, 0.3);\n opacity: 0;\n}\n\n/* Minimize button background circle */\n.sf-player__minimize-button::before {\n content: '';\n position: absolute;\n width: 80%;\n height: 80%;\n background-color: rgba(0, 0, 0, 0.1);\n border-radius: 50%;\n z-index: -1;\n transition: all var(--sf-transition-normal);\n}\n\n/* Minimize button hover state */\n.sf-player__minimize-button:hover {\n transform: scale(1.1);\n}\n\n/* Show minimize button on player hover */\n.sf-player:hover .sf-player__minimize-button {\n opacity: 1;\n}\n\n/* Mobile and touch device overrides for minimize button visibility */\n/* Ensure minimize button is always visible on touch devices, even when minimized */\n@media (pointer: coarse) {\n .sf-player__minimize-button {\n opacity: 1 !important;\n z-index: calc(var(--sf-z-index-controls) + 50) !important; /* Much higher z-index for touch devices */\n }\n \n .sf-player--minimized .sf-player__minimize-button {\n opacity: 1 !important;\n z-index: calc(var(--sf-z-index-controls) + 50) !important; /* Much higher z-index for touch devices */\n }\n}\n\n/* Ensure minimize button is always visible on mobile screens under 768px */\n@media (max-width: 768px) {\n .sf-player__minimize-button {\n opacity: 1 !important;\n z-index: calc(var(--sf-z-index-controls) + 50) !important; /* Much higher z-index for mobile */\n /* Position closer to top right corner on mobile */\n top: var(--sf-spacing-xs) !important; /* 4px from top instead of 16px */\n right: var(--sf-spacing-xs) !important; /* 4px from right instead of 12px */\n }\n \n .sf-player--minimized .sf-player__minimize-button {\n opacity: 1 !important;\n z-index: calc(var(--sf-z-index-controls) + 50) !important; /* Much higher z-index for mobile */\n /* Position closer to top right corner on mobile */\n top: var(--sf-spacing-xs) !important; /* 4px from top instead of 16px */\n right: var(--sf-spacing-xs) !important; /* 4px from right instead of 12px */\n }\n}\n\n/* Player title */\n.sf-player__title {\n position: absolute;\n top: var(--sf-spacing-md);\n left: var(--sf-spacing-md);\n color: var(--sf-text-color);\n font-size: var(--sf-font-size-md);\n font-weight: 600;\n z-index: var(--sf-z-index-controls);\n text-shadow: 0 1px 2px rgba(0, 0, 0, 0.5);\n max-width: 70%;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n/* Centered play/pause button overlay */\n.sf-player__center-play-button {\n position: absolute;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n width: var(--sf-play-button-size);\n height: var(--sf-play-button-size);\n background-color: rgba(0, 0, 0, 0.5);\n border-radius: var(--sf-border-radius-circle);\n display: none; /* Hidden by default */\n justify-content: center;\n align-items: center;\n z-index: calc(var(--sf-z-index-controls) + 10); /* Ensure higher z-index than other elements */\n color: white;\n border: none;\n font-size: var(--sf-control-button-size);\n cursor: pointer;\n transition: transform var(--sf-transition-normal), background-color var(--sf-transition-normal), opacity var(--sf-transition-normal);\n backdrop-filter: blur(1px);\n -webkit-backdrop-filter: blur(1px);\n pointer-events: auto; /* Enable pointer events to capture clicks */\n}\n\n/* Icon visibility control - use opacity for smooth transitions */\n.sf-player__center-play-button__pause-icon,\n.sf-player__center-play-button__play-icon {\n position: absolute;\n transition: opacity var(--sf-transition-normal);\n}\n\n.sf-player__center-play-button__pause-icon {\n opacity: 0;\n}\n\n.sf-player__center-play-button__play-icon {\n opacity: 1;\n}\n\n/* When playing, make button hoverable but invisible (desktop only) */\n@media (hover: hover) and (pointer: fine) {\n .sf-player--playing .sf-player__center-play-button {\n display: flex;\n opacity: 0;\n pointer-events: auto;\n }\n\n /* Show pause icon on hover when playing */\n .sf-player--playing .sf-player__center-play-button:hover {\n opacity: 1;\n }\n\n .sf-player--playing .sf-player__center-play-button:hover .sf-player__center-play-button__play-icon {\n opacity: 0;\n transition: none; /* Instant switch when hovering during playback */\n }\n\n .sf-player--playing .sf-player__center-play-button:hover .sf-player__center-play-button__pause-icon {\n opacity: 1;\n transition: none; /* Instant switch when hovering during playback */\n }\n\n /* Delay icon switch when not hovering during playback so pause icon stays visible during fade-out */\n .sf-player--playing .sf-player__center-play-button .sf-player__center-play-button__play-icon,\n .sf-player--playing .sf-player__center-play-button .sf-player__center-play-button__pause-icon {\n transition: opacity 0s 0.2s; /* Instant transition but delayed by button fade duration */\n }\n}\n\n/* Replay icon hidden by default */\n.sf-player__center-play-button__replay-icon {\n opacity: 0;\n position: absolute;\n transition: opacity var(--sf-transition-normal);\n}\n\n/* Show replay icon when video completed or waiting for interaction */\n.sf-player--completedWaitingForInteraction .sf-player__center-play-button__replay-icon,\n.sf-player--waitingForInteraction .sf-player__center-play-button__replay-icon {\n opacity: 1;\n transition: none;\n}\n\n/* Hide play/pause icons when showing replay */\n.sf-player--completedWaitingForInteraction .sf-player__center-play-button__play-icon,\n.sf-player--completedWaitingForInteraction .sf-player__center-play-button__pause-icon,\n.sf-player--waitingForInteraction .sf-player__center-play-button__play-icon,\n.sf-player--waitingForInteraction .sf-player__center-play-button__pause-icon {\n opacity: 0;\n transition: none;\n}\n\n/* Center play button visible state */\n.sf-player__center-play-button--visible {\n display: flex !important;\n}\n\n/* Center play button prominent state (for autoplay blocked, idle mode) */\n.sf-player__center-play-button--prominent {\n opacity: 1 !important;\n pointer-events: auto !important;\n}\n\n/* Center play button hover state */\n.sf-player__center-play-button:hover {\n transform: translate(-50%, -50%) scale(1.1);\n}\n\n/* Hide center play button in minimized state */\n.sf-player--minimized .sf-player__center-play-button {\n display: none !important;\n}\n\n/* Center play button with dynamic positioning when buttons are present */\n/* Positions button centered between top of player and top of first button */\n.sf-player__center-play-button--with-buttons {\n /* Available space above buttons = playerHeight - bottomSpacing - buttonContainerHeight */\n /* Center point = availableSpace / 2 */\n top: calc((var(--sf-player-height) - var(--sf-spacing-xl) - var(--sf-button-container-height, 0px)) / 2) !important;\n transform: translate(-50%, -50%) !important;\n}\n\n/* Maintain scale on hover for buttons with dynamic positioning */\n.sf-player__center-play-button--with-buttons:hover {\n transform: translate(-50%, -50%) scale(1.1) !important;\n}\n\n/* Exit button for minimized mode */\n.sf-player__exit-button {\n position: absolute;\n top: -22px; /* Position it above the player */\n right: 0;\n width: 22px;\n height: 22px;\n background-color: rgba(0, 0, 0, 0.5);\n border-radius: var(--sf-border-radius-circle);\n display: flex;\n align-items: center;\n justify-content: center;\n cursor: pointer;\n z-index: var(--sf-z-index-controls);\n color: white;\n border: none;\n font-size: var(--sf-font-size-md);\n transition: all var(--sf-transition-normal);\n text-shadow: 0 1px 3px rgba(0, 0, 0, 0.3);\n}\n\n.sf-player__exit-button svg {\n width: 18px;\n height: 18px;\n}\n\n/* Exit button hover state */\n.sf-player__exit-button:hover {\n transform: scale(1.1);\n background-color: rgba(0, 0, 0, 0.7);\n}\n\n/* Show exit button on minimized player hover */\n.sf-player--minimized:hover .sf-player__exit-button {\n opacity: 1;\n}\n\n/* Saltfish logo */\n.sf-player__logo {\n position: absolute;\n bottom: var(--sf-spacing-xs);\n left: 0;\n right: 0;\n height: 18px;\n z-index: var(--sf-z-index-controls);\n opacity: 0.7;\n transition: opacity var(--sf-transition-normal);\n cursor: pointer;\n display: flex;\n justify-content: center;\n align-items: center;\n}\n\n.sf-player__logo svg {\n width: 55px;\n height: 20px;\n}\n\n/* Logo hover state */\n.sf-player:hover .sf-player__logo {\n opacity: 0.9;\n}\n\n/* Hide logo when minimized */\n.sf-player--minimized .sf-player__logo {\n display: none;\n} \n /* \n * Video component styles for the Saltfish playlist Player\n * Following BEM naming convention\n */\n\n/* Video container */\n.sf-video-container {\n position: relative;\n width: 100%;\n height: 100%;\n border-radius: var(--sf-border-radius-md);\n overflow: hidden;\n pointer-events: auto; /* Ensure clicks on video container are captured */\n background-color: #000; /* Fallback background for audio-only mode */\n /* Force clean border-radius clipping */\n isolation: isolate;\n transform: translateZ(0);\n -webkit-mask-image: -webkit-radial-gradient(white, black);\n /* Ensure video container and its children (including captions) sit above the gradient overlay */\n z-index: 3;\n /* Smooth transition for border-radius changes */\n transition: border-radius var(--sf-transition-slow);\n}\n\n/* Dark gradient overlay at bottom of video - ensures captions are visible above it */\n.sf-video-container::after {\n content: '';\n position: absolute;\n bottom: 0;\n left: 0;\n right: 0;\n height: 33.33%; /* One third of container height */\n background: linear-gradient(to top, rgba(0, 0, 0, 0.8) 0%, rgba(0, 0, 0, 0) 100%);\n pointer-events: none;\n z-index: var(--sf-z-index-overlay);\n border-radius: 0 0 var(--sf-border-radius-md) var(--sf-border-radius-md);\n}\n\n/* Dark gradient overlay at bottom of video - ensures captions are visible above it */\n.sf-video-container::after {\n content: '';\n position: absolute;\n bottom: 0;\n left: 0;\n right: 0;\n height: 33.33%; /* One third of container height */\n background: linear-gradient(to top, rgba(0, 0, 0, 0.6) 0%, rgba(0, 0, 0, 0) 100%);\n pointer-events: none;\n z-index: var(--sf-z-index-overlay);\n border-radius: 0 0 var(--sf-border-radius-md) var(--sf-border-radius-md);\n}\n\n/* Dark gradient overlay at bottom of video - ensures captions are visible above it */\n.sf-video-container::after {\n content: '';\n position: absolute;\n bottom: 0;\n left: 0;\n right: 0;\n height: 33.33%; /* One third of container height */\n background: linear-gradient(to top, rgba(0, 0, 0, 0.6) 0%, rgba(0, 0, 0, 0) 100%);\n pointer-events: none;\n z-index: var(--sf-z-index-overlay);\n border-radius: 0 0 var(--sf-border-radius-lg) var(--sf-border-radius-lg);\n}\n\n/* Dark gradient overlay at bottom of video - ensures captions are visible above it */\n.sf-video-container::after {\n content: '';\n position: absolute;\n bottom: 0;\n left: 0;\n right: 0;\n height: 33.33%; /* One third of container height */\n background: linear-gradient(to top, rgba(0, 0, 0, 0.6) 0%, rgba(0, 0, 0, 0) 100%);\n pointer-events: none;\n z-index: var(--sf-z-index-overlay);\n border-radius: 0 0 var(--sf-border-radius-lg) var(--sf-border-radius-lg);\n}\n\n/* Dark gradient overlay at bottom of video - ensures captions are visible above it */\n.sf-video-container::after {\n content: '';\n position: absolute;\n bottom: 0;\n left: 0;\n right: 0;\n height: 33.33%; /* One third of container height */\n background: linear-gradient(to top, rgba(0, 0, 0, 0.6) 0%, rgba(0, 0, 0, 0) 100%);\n pointer-events: none;\n z-index: var(--sf-z-index-overlay);\n border-radius: 0 0 var(--sf-border-radius-md) var(--sf-border-radius-md);\n}\n\n/* Dark gradient overlay at bottom of video - ensures captions are visible above it */\n.sf-video-container::after {\n content: '';\n position: absolute;\n bottom: 0;\n left: 0;\n right: 0;\n height: 33.33%; /* One third of container height */\n background: linear-gradient(to top, rgba(0, 0, 0, 0.6) 0%, rgba(0, 0, 0, 0) 100%);\n pointer-events: none;\n z-index: var(--sf-z-index-overlay);\n border-radius: 0 0 var(--sf-border-radius-md) var(--sf-border-radius-md);\n}\n\n/* Dark gradient overlay at bottom of video - ensures captions are visible above it */\n.sf-video-container::after {\n content: '';\n position: absolute;\n bottom: 0;\n left: 0;\n right: 0;\n height: 33.33%; /* One third of container height */\n background: linear-gradient(to top, rgba(0, 0, 0, 0.6) 0%, rgba(0, 0, 0, 0) 100%);\n pointer-events: none;\n z-index: var(--sf-z-index-overlay);\n border-radius: 0 0 var(--sf-border-radius-md) var(--sf-border-radius-md);\n}\n\n/* Dark gradient overlay at bottom of video - ensures captions are visible above it */\n.sf-video-container::after {\n content: '';\n position: absolute;\n bottom: 0;\n left: 0;\n right: 0;\n height: 33.33%; /* One third of container height */\n background: linear-gradient(to top, rgba(0, 0, 0, 0.6) 0%, rgba(0, 0, 0, 0) 100%);\n pointer-events: none;\n z-index: var(--sf-z-index-overlay);\n border-radius: 0 0 var(--sf-border-radius-md) var(--sf-border-radius-md);\n}\n\n/* Dark gradient overlay at bottom of video - ensures captions are visible above it */\n.sf-video-container::after {\n content: '';\n position: absolute;\n bottom: 0;\n left: 0;\n right: 0;\n height: 33.33%; /* One third of container height */\n background: linear-gradient(to top, rgba(0, 0, 0, 0.6) 0%, rgba(0, 0, 0, 0) 100%);\n pointer-events: none;\n z-index: var(--sf-z-index-overlay);\n border-radius: 0 0 var(--sf-border-radius-md) var(--sf-border-radius-md);\n}\n\n/* Dark gradient overlay at bottom of video - ensures captions are visible above it */\n.sf-video-container::after {\n content: '';\n position: absolute;\n bottom: 0;\n left: 0;\n right: 0;\n height: 33.33%; /* One third of container height */\n background: linear-gradient(to top, rgba(0, 0, 0, 0.6) 0%, rgba(0, 0, 0, 0) 100%);\n pointer-events: none;\n z-index: var(--sf-z-index-overlay);\n border-radius: 0 0 var(--sf-border-radius-md) var(--sf-border-radius-md);\n}\n\n/* Audio fallback poster image */\n.sf-video-container--audio-fallback {\n background-size: cover;\n background-position: center;\n background-repeat: no-repeat;\n background-image: var(--sf-audio-poster-url, none);\n}\n\n/* Audio fallback overlay */\n.sf-audio-fallback-overlay {\n position: absolute;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n background: rgba(0, 0, 0, 0.6);\n z-index: 2;\n pointer-events: none;\n}\n\n/* Avatar mode overlay - no background, just container */\n.sf-audio-fallback-overlay--avatar {\n background: none;\n}\n\n.sf-audio-fallback-overlay__icon {\n width: 60px;\n height: 60px;\n margin-bottom: 16px;\n color: white;\n opacity: 0.9;\n}\n\n.sf-audio-fallback-overlay__text {\n color: white;\n font-size: 14px;\n text-align: center;\n padding: 0 20px;\n text-shadow: 0 2px 4px rgba(0, 0, 0, 0.5);\n opacity: 0.9;\n}\n\n.sf-audio-fallback-overlay__avatar {\n position: absolute;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n object-fit: cover;\n z-index: 1;\n}\n\n/* Semi-transparent overlay on top of avatar */\n.sf-audio-fallback-overlay__dim {\n position: absolute;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n background: rgba(0, 0, 0, 0.3);\n z-index: 2;\n}\n\n/* Soundbar-only mode overlay - dark background for soundbar visibility */\n.sf-audio-fallback-overlay--soundbar-only {\n background: rgba(0, 0, 0, 0.85);\n}\n\n/* Audio visualization soundbar container */\n.sf-audio-soundbar {\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 8px;\n height: 120px;\n width: auto;\n max-width: 300px;\n z-index: 3;\n position: relative;\n padding: 0 20px;\n}\n\n/* Individual soundbar frequency bar */\n.sf-audio-soundbar__bar {\n flex: 1;\n min-width: 8px;\n max-width: 20px;\n height: 10%; /* Default minimum height */\n background-color: hsla(180, 70%, 60%, 0.3);\n border-radius: 4px;\n transition: height 0.05s ease-out, background-color 0.1s ease-out;\n transform-origin: center;\n will-change: height, background-color;\n}\n\n/* Video element */\n.sf-video-container__video {\n width: 100%;\n height: 100%;\n object-fit: cover;\n /* Ensure video is visible on mobile */\n display: block;\n /* Add explicit positioning to ensure video is visible */\n position: relative;\n z-index: 1;\n /* Remove any border-radius - let container's overflow: hidden do the clipping */\n border-radius: 0;\n /* Force GPU acceleration for cleaner clipping with scale effect */\n transform: scale(1.04) translateZ(0);\n backface-visibility: hidden;\n transition: transform 0.3s cubic-bezier(0.25, 0.8, 0.25, 1);\n}\n\n/* Video blur effect (for end-of-video transitions) */\n.sf-video-container__video--blurred {\n filter: blur(3px);\n transform: scale(1.04) translateZ(0);\n transition: filter 0.3s ease-out, transform 0.3s ease-out;\n}\n\n\n\n/* Mobile-specific video styles */\n@media (max-width: 768px) {\n\n .sf-video-container__video {\n /* Force video dimensions on mobile */\n width: 100% !important;\n height: 100% !important;\n object-fit: cover !important;\n /* Prevent video from being hidden */\n opacity: 1 !important;\n visibility: visible !important;\n position: relative !important;\n }\n \n /* Make controls more touch-friendly on mobile */\n .sf-video-container__controls {\n height: 5px; /* Thicker on mobile for easier touch */\n }\n \n /* Adjust pseudo-element for mobile touch target */\n .sf-video-container__controls::before {\n height: 14px; /* Larger touch target on mobile */\n }\n \n .sf-video-container__mute-button {\n /* Use CSS variable for consistent sizing */\n min-width: var(--sf-mute-button-size) !important;\n min-height: var(--sf-mute-button-size) !important;\n opacity: 1; /* Always visible on mobile (no hover) */\n }\n \n .sf-video-container__cc-button {\n /* Use CSS variable for consistent sizing */\n min-width: var(--sf-cc-button-size) !important;\n min-height: var(--sf-cc-button-size) !important;\n opacity: 1; /* Always visible on mobile (no hover) */\n }\n}\n\n/* Touch device specific styles */\n@media (pointer: coarse) {\n .sf-video-container__controls:hover {\n height: 5px; /* Keep consistent height on touch devices */\n }\n \n /* Maintain consistent clickable area on touch devices */\n .sf-video-container__controls::before,\n .sf-video-container__controls:hover::before {\n height: 14px; /* Consistent touch target */\n }\n \n .sf-video-container__mute-button {\n opacity: 1; /* Always show on touch devices */\n }\n \n .sf-video-container__cc-button {\n opacity: 1; /* Always show on touch devices */\n }\n \n .sf-video-container:hover .sf-video-container__mute-button {\n opacity: 1;\n }\n}\n\n/* Video in minimized state */\n.sf-player--minimized .sf-video-container {\n border-radius: var(--sf-border-radius-circle);\n cursor: pointer;\n z-index: var(--sf-z-index-base);\n width: 100%;\n height: 100%;\n /* Ensure clean clipping in circular state */\n isolation: isolate;\n transform: translateZ(0);\n}\n\n/* Hide gradient overlay when minimized */\n.sf-player--minimized .sf-video-container::after {\n display: none;\n}\n\n.sf-player--minimized .sf-video-container__video {\n border-radius: 0; /* Let container handle clipping */\n object-fit: cover;\n width: 100%;\n height: 100%;\n transform: scale(1.2) translateZ(0);\n}\n\n/* Hide progress bar in minimized state */\n.sf-player--minimized .sf-video-container__controls {\n display: none !important;\n}\n\n/* Also hide mute button in minimized state */\n.sf-player--minimized .sf-video-container__mute-button {\n display: none !important;\n}\n\n/* Also hide CC button in minimized state */\n.sf-player--minimized .sf-video-container__cc-button {\n display: none !important;\n}\n\n/* Progress bar container */\n.sf-video-container__controls {\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n width: 100%;\n height: 4px;\n background-color: rgba(255, 255, 255, 0.3);\n z-index: var(--sf-z-index-controls);\n /* Match the container's top border-radius for seamless integration */\n border-radius: var(--sf-border-radius-md) var(--sf-border-radius-md) 0 0;\n cursor: pointer;\n /* Ensure pixel-perfect alignment and edge-to-edge coverage */\n transform: translateZ(0);\n backface-visibility: hidden;\n /* Smooth transition for height change on hover */\n transition: height 0.15s ease-in-out, background-color 0.15s ease-in-out;\n /* Ensure it covers the full width */\n margin: 0;\n box-sizing: border-box;\n}\n\n/* Invisible pseudo-element to extend clickable area downward */\n.sf-video-container__controls::before {\n content: '';\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n height: 10px; /* Visual height (4px) + extended clickable area (6px) */\n cursor: pointer;\n}\n\n/* Show slightly thicker progress bar on hover for better UX */\n.sf-video-container__controls:hover {\n height: 6px;\n background-color: rgba(255, 255, 255, 0.35);\n}\n\n/* Extend pseudo-element when progress bar grows on hover */\n.sf-video-container__controls:hover::before {\n height: 12px; /* Visual height (6px) + extended clickable area (6px) */\n}\n\n/* Progress indicator */\n.sf-video-container__progress {\n height: 100%;\n background: linear-gradient(90deg, rgba(255, 255, 255, 0.9) 0%, rgba(255, 255, 255, 0.85) 100%);\n width: 0%;\n transition: width 0.1s linear;\n /* Only apply top-left border-radius to maintain seamless look */\n border-radius: var(--sf-border-radius-md) 0 0 0;\n cursor: pointer;\n transform-origin: left;\n /* Ensure smooth rendering */\n will-change: width;\n}\n\n/* Mute button */\n.sf-video-container__mute-button {\n position: absolute;\n top: calc(8px + var(--sf-minimize-button-size) + 6px);\n right: 4px;\n width: var(--sf-mute-button-size);\n height: var(--sf-mute-button-size);\n background: none !important;\n border-radius: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n cursor: pointer;\n z-index: var(--sf-z-index-controls);\n color: white;\n border: none;\n font-size: calc(var(--sf-font-size-md) + 2px);\n transition: all var(--sf-transition-normal);\n text-shadow: 0 1px 3px rgba(0, 0, 0, 0.3);\n opacity: 0;\n}\n\n/* Mute button background circle */\n.sf-video-container__mute-button::before {\n content: '';\n position: absolute;\n width: 80%;\n height: 80%;\n background-color: rgba(0, 0, 0, 0.1);\n border-radius: 50%;\n z-index: -1;\n transition: all var(--sf-transition-normal);\n}\n\n/* Mute button hover state */\n.sf-video-container__mute-button:hover {\n transform: scale(1.1);\n}\n\n/* Show mute button on container hover */\n.sf-video-container:hover .sf-video-container__mute-button {\n opacity: 1;\n}\n\n/* CC button */\n.sf-video-container__cc-button {\n position: absolute;\n top: calc(8px + var(--sf-minimize-button-size) + 6px + var(--sf-mute-button-size) + 6px);\n right: 4px;\n width: var(--sf-cc-button-size);\n height: var(--sf-cc-button-size);\n background: none !important;\n border-radius: 0;\n padding: 0; /* Remove default button padding */\n display: flex;\n align-items: center;\n justify-content: center;\n cursor: pointer;\n z-index: var(--sf-z-index-controls);\n color: white;\n border: none;\n font-size: calc(var(--sf-font-size-md) + 2px);\n transition: all var(--sf-transition-normal);\n text-shadow: 0 1px 3px rgba(0, 0, 0, 0.3);\n opacity: 0;\n}\n\n/* CC button background circle */\n.sf-video-container__cc-button::before {\n content: '';\n position: absolute;\n width: 80%;\n height: 80%;\n background-color: rgba(0, 0, 0, 0.1);\n border-radius: 50%;\n z-index: -1;\n transition: all var(--sf-transition-normal);\n}\n\n.sf-video-container__cc-button svg {\n display: block;\n margin: auto;\n width: 60%;\n height: 60%;\n}\n\n/* CC button hover state */\n.sf-video-container__cc-button:hover {\n transform: scale(1.1);\n}\n\n/* Compact mode styling - circular border-radius for video container */\n.sf-player--compact .sf-video-container {\n border-radius: var(--sf-border-radius-circle);\n}\n\n/* Hide gradient overlay in compact mode (already handled in _player.css but kept for clarity) */\n.sf-player--compact .sf-video-container::after {\n display: none;\n}\n\n/* Hide mute and cc buttons in autoplayBlocked and idleMode states */\n.sf-player--autoplayBlocked .sf-video-container__mute-button,\n.sf-player--autoplayBlocked .sf-video-container__cc-button,\n.sf-player--idleMode .sf-video-container__mute-button,\n.sf-player--idleMode .sf-video-container__cc-button {\n display: none !important;\n}\n\n/* Show mute and cc buttons on hover in playing/paused states */\n.sf-player--playing .sf-video-container:hover .sf-video-container__mute-button,\n.sf-player--playing .sf-video-container:hover .sf-video-container__cc-button,\n.sf-player--paused .sf-video-container:hover .sf-video-container__mute-button,\n.sf-player--paused .sf-video-container:hover .sf-video-container__cc-button {\n opacity: 1;\n} \n /* \n * Controls component styles for the Saltfish playlist Player\n * Following BEM naming convention\n */\n\n/* Main controls container */\n.sf-controls-container {\n position: absolute;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n display: flex;\n justify-content: center;\n align-items: center;\n background-color: transparent;\n z-index: var(--sf-z-index-controls);\n pointer-events: auto;\n}\n\n/* Play button */\n.sf-controls-container__play-button {\n background-color: rgba(0, 0, 0, 0.6);\n border: none;\n color: var(--sf-text-color);\n font-size: var(--sf-control-button-size);\n cursor: pointer;\n width: var(--sf-play-button-size);\n height: var(--sf-play-button-size);\n border-radius: var(--sf-border-radius-circle);\n display: flex;\n justify-content: center;\n align-items: center;\n transition: transform var(--sf-transition-normal), background-color var(--sf-transition-normal);\n padding-left: 4px; /* Optical centering for play icon */\n}\n\n/* Button hover state */\n.sf-controls-container__play-button:hover {\n background-color: rgba(0, 0, 0, 0.4);\n transform: scale(1.1);\n}\n\n/* Button container for interactive buttons */\n.sf-controls-container__buttons {\n display: flex;\n justify-content: center;\n align-items: center;\n gap: var(--sf-spacing-md);\n}\n\n/* Interactive button */\n.sf-controls-container__interactive-button {\n background-color: rgba(255, 255, 255, 0.2);\n backdrop-filter: blur(8px);\n -webkit-backdrop-filter: blur(8px);\n color: white;\n border: none;\n border-radius: var(--sf-border-radius-md);\n padding: var(--sf-spacing-xs) var(--sf-spacing-md);\n font-size: var(--sf-font-size-sm);\n cursor: pointer;\n transition: background-color var(--sf-transition-normal), transform var(--sf-transition-fast);\n box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);\n}\n\n.sf-controls-container__interactive-button:hover {\n background-color: rgba(255, 255, 255, 0.3);\n transform: translateY(-2px);\n}\n\n/* \n * Choice buttons container and buttons - positioned inside player\n */\n\n/* Choice buttons container - positioned inside the player at the bottom */\n.sf-choice-buttons-container {\n position: absolute;\n bottom: var(--sf-spacing-xl);\n left: 50%;\n transform: translateX(-50%);\n width: calc(100% - var(--sf-spacing-lg));\n max-width: calc(100% - var(--sf-spacing-lg));\n z-index: calc(var(--sf-z-index-controls) + 1);\n gap: var(--sf-spacing-sm);\n pointer-events: auto;\n align-items: center;\n display: flex;\n flex-direction: column;\n /* Ensure container is fully transparent */\n background: transparent;\n border: none;\n outline: none;\n}\n\n/* Choice buttons container with scrolling for 5+ buttons */\n.sf-choice-buttons-container--scrollable {\n max-height: 176px; /* Show ~4 buttons with gaps (4 * 36px button + 4 * 8px gap) */\n overflow-y: auto;\n overflow-x: hidden;\n scrollbar-width: thin; /* Show thin scrollbar in Firefox */\n scrollbar-color: rgba(255, 255, 255, 0.2) transparent; /* More transparent Firefox scrollbar */\n scroll-behavior: smooth;\n /* Important: Use block display for scrollable container */\n display: block !important;\n}\n\n/* Style webkit scrollbar to be visible but subtle */\n.sf-choice-buttons-container--scrollable::-webkit-scrollbar {\n width: 4px;\n}\n\n.sf-choice-buttons-container--scrollable::-webkit-scrollbar-track {\n background: transparent;\n}\n\n.sf-choice-buttons-container--scrollable::-webkit-scrollbar-thumb {\n background: rgba(255, 255, 255, 0.2); /* More transparent */\n border-radius: 2px;\n}\n\n.sf-choice-buttons-container--scrollable::-webkit-scrollbar-thumb:hover {\n background: rgba(255, 255, 255, 0.4); /* Still subtle on hover */\n}\n\n/* Removed fade gradient to keep container fully transparent */\n\n/* Choice button styles - solid rounded buttons matching the image */\n.sf-choice-button {\n width: 100%;\n max-width: none;\n background: rgba(0, 0, 0, 4);\n backdrop-filter: blur(8px);\n -webkit-backdrop-filter: blur(8px);\n color: white;\n border: none;\n border-radius: 24px; /* More rounded for pill shape */\n padding: var(--sf-spacing-md) var(--sf-spacing-md);\n font-size: 12px;\n cursor: pointer;\n transition: all 0.2s ease;\n text-align: center;\n outline: none;\n font-family: inherit;\n margin-bottom: 0;\n position: relative;\n overflow: hidden;\n opacity: 0; /* Start hidden for animation */\n pointer-events: none;\n /* Animation will be triggered by JavaScript when video reaches 90% */\n}\n\n/* Add margin between buttons in scrollable container */\n.sf-choice-buttons-container--scrollable .sf-choice-button {\n margin-bottom: var(--sf-spacing-sm);\n}\n\n/* Remove margin from last button */\n.sf-choice-buttons-container--scrollable .sf-choice-button:last-child {\n margin-bottom: 0;\n}\n\n/* Hover state for buttons */\n.sf-choice-button:hover {\n background: rgba(0, 0, 0, 0.9);\n transform: translateY(-2px);\n box-shadow: 0 6px 16px rgba(0, 0, 0, 0.8);\n}\n\n/* Active state for all buttons */\n.sf-choice-button:active {\n transform: translateY(0) scale(0.98);\n transition: all 0.1s ease;\n}\n\n/* Remove specific action type styling - use consistent dark buttons */\n.sf-choice-button--goto,\n.sf-choice-button--url,\n.sf-choice-button--next,\n.sf-choice-button--dom,\n.sf-choice-button--function {\n background: rgba(0, 0, 0, 0.4);\n border: none;\n}\n\n.sf-choice-button--goto:hover,\n.sf-choice-button--url:hover,\n.sf-choice-button--next:hover,\n.sf-choice-button--dom:hover,\n.sf-choice-button--function:hover {\n background: rgba(0, 0, 0, 0.9);\n transform: translateY(-2px);\n box-shadow: 0 6px 16px rgba(0, 0, 0, 0.4);\n}\n\n/* Hide choice buttons in minimized state */\n.sf-player--minimized .sf-choice-buttons-container {\n display: none !important;\n}\n\n/* Hide choice buttons in autoplayBlocked and idleMode states */\n.sf-player--autoplayBlocked .sf-choice-buttons-container,\n.sf-player--idleMode .sf-choice-buttons-container {\n display: none !important;\n}\n\n/* Smaller mobile screens - maintain same layout but with tighter spacing */\n@media (max-width: 480px) {\n .sf-choice-buttons-container {\n bottom: var(--sf-spacing-sm);\n width: calc(100% - var(--sf-spacing-md));\n max-width: calc(100% - var(--sf-spacing-md));\n gap: calc(var(--sf-spacing-xs) + 2px);\n }\n \n .sf-choice-button {\n padding: var(--sf-spacing-sm) var(--sf-spacing-sm);\n font-size: 11px;\n border-radius: 20px;\n }\n}\n\n/* Touch device specific adjustments */\n@media (pointer: coarse) {\n .sf-choice-buttons-container {\n gap: var(--sf-spacing-sm);\n }\n \n .sf-choice-button {\n min-height: 44px; /* Apple's recommended minimum touch target size */\n padding: var(--sf-spacing-md) var(--sf-spacing-md);\n }\n}\n\n/* Button fade-in animation */\n@keyframes buttonFadeIn {\n from {\n opacity: 0;\n transform: translateY(10px);\n }\n to {\n opacity: 1;\n transform: translateY(0);\n }\n}\n\n/* Animation class that will be added by JavaScript at 90% video progress */\n.sf-choice-button.sf-show-button {\n animation: buttonFadeIn 0.3s ease-out forwards;\n pointer-events: auto;\n}\n\n/* Staggered animation delays for multiple buttons when shown */\n.sf-choice-button.sf-show-button:nth-child(1) {\n animation-delay: 0s;\n}\n\n.sf-choice-button.sf-show-button:nth-child(2) {\n animation-delay: 0.15s;\n}\n\n.sf-choice-button.sf-show-button:nth-child(3) {\n animation-delay: 0.3s;\n}\n\n.sf-choice-button.sf-show-button:nth-child(4) {\n animation-delay: 0.45s;\n}\n\n.sf-choice-button.sf-show-button:nth-child(5) {\n animation-delay: 0.6s;\n}\n\n.sf-choice-button.sf-show-button:nth-child(6) {\n animation-delay: 0.75s;\n}\n\n.sf-choice-button.sf-show-button:nth-child(7) {\n animation-delay: 0.9s;\n}\n\n.sf-choice-button.sf-show-button:nth-child(8) {\n animation-delay: 1.05s;\n}\n\n/* Scroll indicator arrow */\n.sf-scroll-indicator {\n position: absolute;\n bottom: calc(var(--sf-spacing-xl) - 25px);\n left: 50%;\n transform: translateX(-50%);\n color: rgba(255, 255, 255, 0.6);\n font-size: 20px;\n pointer-events: none;\n z-index: calc(var(--sf-z-index-controls) + 2);\n transition: opacity 0.3s ease;\n display: flex;\n align-items: center;\n justify-content: center;\n width: 24px;\n height: 24px;\n opacity: 0; /* Start hidden */\n}\n\n/* Show scroll indicator with animation - appears after buttons */\n.sf-scroll-indicator.sf-show-scroll-indicator {\n animation: scrollIndicatorFadeIn 0.4s ease-out 1.2s forwards, bounceArrow 1.5s ease-in-out 1.6s infinite;\n}\n\n/* Hide arrow when scrolled to bottom */\n.sf-scroll-indicator--hidden {\n opacity: 0;\n}\n\n/* Fade in animation for scroll indicator */\n@keyframes scrollIndicatorFadeIn {\n from {\n opacity: 0;\n transform: translateX(-50%) translateY(-10px);\n }\n to {\n opacity: 1;\n transform: translateX(-50%) translateY(0);\n }\n}\n\n/* Bounce animation for the arrow */\n@keyframes bounceArrow {\n 0%, 100% {\n transform: translateX(-50%) translateY(0);\n }\n 50% {\n transform: translateX(-50%) translateY(5px);\n }\n}\n\n/* Hide scroll indicator in minimized state */\n.sf-player--minimized .sf-scroll-indicator {\n display: none !important;\n}\n\n/* Hide scroll indicator in autoplayBlocked and idleMode states */\n.sf-player--autoplayBlocked .sf-scroll-indicator,\n.sf-player--idleMode .sf-scroll-indicator {\n display: none !important;\n} \n /* \n * Transcript component styles for the Saltfish Playlist Player\n * Following BEM naming convention\n */\n\n/* Transcript container */\n.sf-transcript {\n position: absolute;\n bottom: 40px; /* Above the progress bar */\n left: 0;\n right: 0;\n max-height: 200px;\n background: transparent;\n margin: 0 var(--sf-spacing-md);\n overflow: hidden;\n z-index: var(--sf-z-index-controls);\n opacity: 0;\n transform: translateY(20px);\n transition: all 0.3s ease-out;\n pointer-events: none;\n}\n\n/* Visible state */\n.sf-transcript--visible {\n opacity: 1;\n transform: translateY(0);\n pointer-events: auto;\n}\n\n/* Transcript content */\n.sf-transcript__content {\n max-height: 180px;\n overflow: visible;\n padding: 0;\n display: flex;\n justify-content: center;\n align-items: center;\n width: 100%;\n text-align: center;\n}\n\n/* Webkit scrollbar styling */\n.sf-transcript__content::-webkit-scrollbar {\n width: 4px;\n}\n\n.sf-transcript__content::-webkit-scrollbar-track {\n background: transparent;\n}\n\n.sf-transcript__content::-webkit-scrollbar-thumb {\n background: rgba(255, 255, 255, 0.3);\n border-radius: 2px;\n}\n\n.sf-transcript__content::-webkit-scrollbar-thumb:hover {\n background: rgba(255, 255, 255, 0.5);\n}\n\n/* Word-by-word display container - progressive reveal style */\n.sf-transcript__word-container {\n display: flex;\n justify-content: center;\n align-items: center;\n gap: 0.04em; /* Much tighter gap to compensate for inverse scaling effect */\n min-height: 60px;\n padding: 0 var(--sf-spacing-md);\n flex-wrap: nowrap;\n overflow: hidden;\n width: 100%;\n max-width: 100%;\n box-sizing: border-box;\n text-align: center;\n transition: opacity 0.15s ease-in-out; /* Smooth fade during window transitions */\n}\n\n/* Individual word styling - base state (hidden by default) */\n.sf-transcript__word {\n color: rgba(255, 255, 255, 0.65);\n font-size: 20px; /* Increased from 18px to compensate for 0.893 scale (20 * 0.893 ≈ 18px) */\n font-weight: 500; /* Set to 500 from start to prevent pixel shift on activation */\n line-height: 1.3;\n white-space: nowrap;\n text-align: center;\n opacity: 0;\n transform: scale(0.893) translateY(0); /* Scaled down - active word will be normal size (1/1.12 ≈ 0.893) */\n transition: opacity 0.2s ease, color 0.2s ease, text-shadow 0.2s ease, transform 0.2s ease;\n padding-left: 0.12em; /* Consistent padding */\n padding-right: 0.12em;\n}\n\n/* Visible state - word has appeared */\n.sf-transcript__word--visible {\n opacity: 0.8;\n transform: scale(0.893) translateY(0); /* Keep scaled down */\n}\n\n/* Active word (currently speaking) - highlighted at normal size (inverse scale approach) */\n.sf-transcript__word--active {\n color: rgba(255, 255, 255, 1) !important;\n opacity: 1 !important;\n transform: scale(1) translateY(0); /* Normal size - appears 12% larger relative to scaled-down neighbors */\n text-shadow: 0 0 20px rgba(255, 255, 255, 0.3);\n /* font-weight removed - already 500 from base to prevent pixel shift */\n}\n\n/* Legacy segment styling (kept for compatibility) */\n.sf-transcript__segment {\n color: rgba(255, 255, 255);\n font-size: var(--sf-font-size-sm);\n line-height: 1.4;\n padding: var(--sf-spacing-xs) 0;\n cursor: pointer;\n transition: all 0.2s ease;\n padding-left: var(--sf-spacing-xs);\n padding-right: var(--sf-spacing-xs);\n}\n\n/* CC button styling removed - now handled via icon toggling */\n\n/* Mobile responsive styles */\n@media (max-width: 768px) {\n .sf-transcript {\n bottom: 35px; /* Positioned lower on mobile for better visibility */\n margin: 0 var(--sf-spacing-sm);\n max-height: 150px; /* Smaller on mobile */\n }\n\n .sf-transcript__content {\n max-height: 130px;\n padding: var(--sf-spacing-sm);\n }\n\n .sf-transcript__word-container {\n min-height: 50px;\n padding: 0 var(--sf-spacing-sm);\n gap: 0.2em; /* Tighter gap for mobile */\n }\n \n .sf-transcript__word {\n font-size: var(--sf-font-size-md);\n /* font-weight already 500 from base styles */\n }\n \n .sf-transcript__segment {\n font-size: var(--sf-font-size-xs);\n padding: var(--sf-spacing-xs) var(--sf-spacing-sm);\n }\n}\n\n/* Touch device optimizations */\n@media (pointer: coarse) {\n .sf-transcript__segment {\n padding: var(--sf-spacing-sm) var(--sf-spacing-xs);\n min-height: 44px; /* Larger touch target */\n display: flex;\n align-items: center;\n }\n}\n\n/* Hide transcript in minimized state */\n.sf-player--minimized .sf-transcript {\n display: none !important;\n}\n\n/* Hide transcript in autoplayBlocked and idleMode states */\n.sf-player--autoplayBlocked .sf-transcript,\n.sf-player--idleMode .sf-transcript {\n display: none !important;\n}\n\n/* Animation for transcript appearance */\n@keyframes transcriptFadeIn {\n from {\n opacity: 0;\n transform: translateY(20px);\n }\n to {\n opacity: 1;\n transform: translateY(0);\n }\n}\n\n@keyframes transcriptFadeOut {\n from {\n opacity: 1;\n transform: translateY(0);\n }\n to {\n opacity: 0;\n transform: translateY(20px);\n }\n}\n /* \n * Error Display component styles for the Saltfish playlist Player\n * Clean and subtle full-widget error overlay\n */\n\n/* Error display overlay - covers full widget */\n.sf-error-display {\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background-color: rgba(0, 0, 0, 0.75);\n backdrop-filter: blur(6px);\n -webkit-backdrop-filter: blur(6px);\n display: flex;\n align-items: center;\n justify-content: center;\n z-index: calc(var(--sf-z-index-controls) + 30);\n border-radius: var(--sf-border-radius-lg);\n opacity: 0;\n transition: opacity var(--sf-transition-slow);\n pointer-events: auto;\n}\n\n/* Error display visible state */\n.sf-error-display--visible {\n opacity: 1;\n}\n\n/* Error content container */\n.sf-error-display__content {\n background-color: rgba(20, 20, 20, 0.9);\n border-radius: var(--sf-border-radius-md);\n padding: var(--sf-spacing-lg) var(--sf-spacing-xl);\n backdrop-filter: blur(10px);\n -webkit-backdrop-filter: blur(10px);\n border: 1px solid rgba(255, 255, 255, 0.08);\n transform: translateY(8px);\n transition: transform var(--sf-transition-slow);\n max-width: 85%;\n text-align: center;\n}\n\n/* Error content visible animation */\n.sf-error-display--visible .sf-error-display__content {\n transform: translateY(0);\n}\n\n/* Error message */\n.sf-error-display__message {\n color: rgba(255, 255, 255, 0.95);\n font-size: var(--sf-font-size-md);\n line-height: 1.5;\n margin: 0;\n text-align: center;\n font-weight: 500;\n}\n\n/* Mobile responsive adjustments */\n@media (max-width: 768px) {\n .sf-error-display__content {\n padding: var(--sf-spacing-md) var(--sf-spacing-lg);\n max-width: 90%;\n }\n\n .sf-error-display__message {\n font-size: var(--sf-font-size-sm);\n }\n}\n\n/* Minimized player state adjustments */\n.sf-player--minimized .sf-error-display__content {\n padding: var(--sf-spacing-sm) var(--sf-spacing-md);\n max-width: 80%;\n}\n\n.sf-player--minimized .sf-error-display__message {\n font-size: var(--sf-font-size-sm);\n font-weight: 400;\n}\n\n/* High contrast mode support */\n@media (prefers-contrast: high) {\n .sf-error-display__content {\n background-color: rgba(0, 0, 0, 0.95);\n border: 2px solid rgba(255, 255, 255, 0.3);\n }\n\n .sf-error-display__message {\n color: rgba(255, 255, 255, 0.95);\n }\n}\n\n/* Reduced motion support */\n@media (prefers-reduced-motion: reduce) {\n .sf-error-display,\n .sf-error-display__content {\n transition: none;\n }\n}\n /**\n * Loading spinner styles\n */\n\n.sf-loading-spinner {\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n background-color: rgba(255, 255, 255, 0.95);\n backdrop-filter: blur(2px);\n z-index: 100;\n border-radius: 12px;\n opacity: 1 !important; /* Always visible when shown, overrides parent opacity */\n}\n\n.sf-loading-spinner__content {\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 12px;\n padding: 24px;\n}\n\n.sf-loading-spinner__icon {\n display: flex;\n align-items: center;\n justify-content: center;\n color: #000000;\n opacity: 0.9;\n}\n\n.sf-loading-spinner__icon svg {\n width: 60px;\n height: 60px;\n /* Remove the rotation animation since we now have internal SVG animation */\n}\n\n.sf-loading-spinner__text {\n color: #333333;\n font-size: 14px;\n font-weight: 500;\n text-align: center;\n opacity: 0.8;\n letter-spacing: 0.5px;\n}\n\n/* CSS keyframe animation removed - using SVG animateTransform instead */\n\n/* Responsive adjustments */\n@media (max-width: 480px) {\n .sf-loading-spinner__content {\n padding: 20px;\n gap: 10px;\n }\n \n .sf-loading-spinner__icon svg {\n width: 50px;\n height: 50px;\n }\n \n .sf-loading-spinner__text {\n font-size: 13px;\n }\n}\n /*\n * Cursor animation component styles for the Saltfish playlist Player\n * CSP-compliant: All styles use CSS classes and CSS custom properties instead of inline styles\n */\n\n/* Base cursor element */\n.sf-cursor {\n position: fixed;\n top: 0;\n left: 0;\n width: 36px;\n height: 36px;\n z-index: 9999999;\n pointer-events: none;\n display: none;\n will-change: transform;\n transform: var(--sf-cursor-transform, translate(0, 0));\n opacity: var(--sf-cursor-opacity, 1);\n}\n\n.sf-cursor--visible {\n display: block;\n}\n\n/* Selection element */\n.sf-selection {\n position: fixed;\n pointer-events: none;\n display: none;\n z-index: 9999998;\n border: 2px solid var(--sf-selection-color, #ff7614);\n background: var(--sf-selection-bg-color, rgba(255, 118, 20, 0.1));\n border-radius: 4px;\n left: var(--sf-selection-left, 0);\n top: var(--sf-selection-top, 0);\n width: var(--sf-selection-width, 0);\n height: var(--sf-selection-height, 0);\n}\n\n.sf-selection--visible {\n display: block;\n}\n\n/* Flashlight overlay */\n.sf-flashlight-overlay {\n position: fixed;\n top: 0;\n left: 0;\n width: 100vw;\n height: 100vh;\n pointer-events: none;\n z-index: 999997;\n display: none;\n background: var(--sf-flashlight-bg, radial-gradient(circle 150px at 50% 50%, transparent 0%, rgba(0, 0, 0, 0.4) 100%));\n clip-path: var(--sf-flashlight-clip, none);\n}\n\n.sf-flashlight-overlay--visible {\n display: block;\n}\n\n /**\n * Compact Label Styles\n * Label that appears next to the player when in compact first step mode\n * Position adapts based on player placement (left/right)\n */\n\n.sf-compact-label {\n position: absolute;\n top: 50%;\n transform: translateY(-50%);\n\n /* Typography */\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;\n font-size: 14px;\n font-weight: 500;\n line-height: 1.4;\n color: #ffffff;\n\n /* Visual styling */\n background: rgba(0, 0, 0, 0.85);\n backdrop-filter: blur(10px);\n padding: 10px 16px;\n border-radius: 8px;\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3),\n 0 0 0 1px rgba(255, 255, 255, 0.1);\n\n /* Ensure it doesn't wrap */\n white-space: nowrap;\n\n /* Layering */\n z-index: 10;\n\n /* Pointer events - will be enabled via JS when clickable */\n pointer-events: none;\n user-select: none;\n\n /* Smooth transitions for hover effects */\n transition: transform 0.2s cubic-bezier(0.25, 0.8, 0.25, 1),\n box-shadow 0.2s cubic-bezier(0.25, 0.8, 0.25, 1),\n background 0.2s cubic-bezier(0.25, 0.8, 0.25, 1);\n}\n\n/* Position to the LEFT of player (when player is on the right side) */\n.sf-compact-label--left {\n right: calc(100% + 16px); /* 16px spacing from player edge */\n animation: sf-compact-label-enter-from-left 0.4s cubic-bezier(0.25, 0.8, 0.25, 1) forwards;\n}\n\n/* Position to the RIGHT of player (when player is on the left side) */\n.sf-compact-label--right {\n left: calc(100% + 16px); /* 16px spacing from player edge */\n animation: sf-compact-label-enter-from-right 0.4s cubic-bezier(0.25, 0.8, 0.25, 1) forwards;\n}\n\n/* Entrance animation from LEFT - slide in from left with fade */\n@keyframes sf-compact-label-enter-from-left {\n 0% {\n opacity: 0;\n transform: translateY(-50%) translateX(-20px);\n }\n 100% {\n opacity: 1;\n transform: translateY(-50%) translateX(0);\n }\n}\n\n/* Entrance animation from RIGHT - slide in from right with fade */\n@keyframes sf-compact-label-enter-from-right {\n 0% {\n opacity: 0;\n transform: translateY(-50%) translateX(20px);\n }\n 100% {\n opacity: 1;\n transform: translateY(-50%) translateX(0);\n }\n}\n\n/* Hover effect - only applies when label is clickable (pointer-events: auto) */\n.sf-compact-label--left:hover,\n.sf-compact-label--right:hover {\n background: rgba(0, 0, 0, 0.95);\n box-shadow: 0 6px 20px rgba(0, 0, 0, 0.4),\n 0 0 0 1px rgba(255, 255, 255, 0.2),\n 0 0 25px rgba(255, 255, 255, 0.08);\n}\n\n.sf-compact-label--left:hover {\n transform: translateY(-50%) translateX(-2px);\n}\n\n.sf-compact-label--right:hover {\n transform: translateY(-50%) translateX(2px);\n}\n\n/* Active/click state */\n.sf-compact-label--left:active,\n.sf-compact-label--right:active {\n transform: translateY(-50%) scale(0.98);\n}\n\n/* Mobile adjustments */\n@media (max-width: 768px) {\n .sf-compact-label {\n font-size: 12px;\n padding: 8px 12px;\n }\n\n .sf-compact-label--left {\n right: calc(100% + 12px); /* Slightly less spacing on mobile */\n }\n\n .sf-compact-label--right {\n left: calc(100% + 12px); /* Slightly less spacing on mobile */\n }\n}\n\n/* Very small screens - keep to side with tighter spacing */\n@media (max-width: 480px) {\n .sf-compact-label {\n /* Use most of the available screen width - on 390px wide screen this gives ~270px */\n max-width: calc(100vw - 90px - 20px - 8px - 10px); /* viewport - player - margin - spacing - small buffer */\n /* Keep nowrap - we have plenty of space on mobile screens */\n }\n\n .sf-compact-label--left {\n right: calc(100% + 8px); /* Reduce spacing slightly for mobile */\n }\n\n .sf-compact-label--right {\n left: calc(100% + 8px); /* Reduce spacing slightly for mobile */\n }\n}\n\n\n /* \n * Transitions and animations for Saltfish playlist Player\n */\n\n/* Fade in animation */\n@keyframes sf-fade-in {\n from { opacity: 0; }\n to { opacity: 1; }\n}\n\n.sf-fade-in {\n animation: sf-fade-in 0.3s ease-in-out forwards;\n}\n\n/* Slide in from bottom animation */\n@keyframes sf-slide-in-bottom {\n from { transform: translateY(100%); opacity: 0; }\n to { transform: translateY(0); opacity: 1; }\n}\n\n.sf-slide-in-bottom {\n animation: sf-slide-in-bottom 0.3s cubic-bezier(0.25, 0.8, 0.25, 1) forwards;\n}\n\n/* Slide in from right animation */\n@keyframes sf-slide-in-right {\n from { transform: translateX(100%); opacity: 0; }\n to { transform: translateX(0); opacity: 1; }\n}\n\n.sf-slide-in-right {\n animation: sf-slide-in-right 0.3s cubic-bezier(0.25, 0.8, 0.25, 1) forwards;\n}\n\n/* Scale in animation */\n@keyframes sf-scale-in {\n from { transform: scale(0.8); opacity: 0; }\n to { transform: scale(1); opacity: 1; }\n}\n\n.sf-scale-in {\n animation: sf-scale-in 0.3s cubic-bezier(0.25, 0.8, 0.25, 1) forwards;\n}\n\n/* Scale out animation */\n@keyframes sf-scale-out {\n from { transform: scale(1); opacity: 1; }\n to { transform: scale(0.8); opacity: 0; }\n}\n\n.sf-scale-out {\n animation: sf-scale-out 0.3s cubic-bezier(0.25, 0.8, 0.25, 1) forwards;\n} \n"}}class Xt{static isMobile(){return this.getDeviceInfo().isMobile}static isTablet(){return this.getDeviceInfo().isTablet}static isDesktop(){return this.getDeviceInfo().isDesktop}static isTouchDevice(){return this.getDeviceInfo().isTouchDevice}static getOrientation(){return this.getDeviceInfo().orientation}static getDeviceInfo(){if(this.cachedDeviceInfo)return this.cachedDeviceInfo.orientation=this.detectOrientation(),this.cachedDeviceInfo;const t="undefined"!=typeof navigator?navigator.userAgent:"",e=this.detectTouchSupport(),{width:n,height:i}=this.getScreenDimensions(),s=/iPad|Android(?!.*Mobile)|Tablet|tablet/i,r=/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini|Mobile|mobile|CriOS/i.test(t)&&!s.test(t),a=s.test(t),o=this.getScreenSize(n,i),l="small"===o&&Math.min(n,i)<768,c=r||l&&e,d=a||"medium"===o&&!l&&e&&!c,h={isMobile:c,isTablet:d,isDesktop:!c&&!d,isTouchDevice:e,screenSize:o,orientation:this.detectOrientation(),userAgent:t};return this.cachedDeviceInfo=h,h}static detectTouchSupport(){return"undefined"!=typeof window&&("ontouchstart"in window||navigator.maxTouchPoints>0||navigator.msMaxTouchPoints>0)}static getScreenDimensions(){return"undefined"==typeof window?{width:1920,height:1080}:{width:window.innerWidth||document.documentElement.clientWidth||1920,height:window.innerHeight||document.documentElement.clientHeight||1080}}static getScreenSize(t,e){const n=Math.min(t,e);return n<768?"small":n<1024?"medium":"large"}static detectOrientation(){if("undefined"==typeof window)return"landscape";const{width:t,height:e}=this.getScreenDimensions();return e>t?"portrait":"landscape"}static clearCache(){this.cachedDeviceInfo=null}static onDeviceChange(t){if("undefined"==typeof window)return()=>{};const e=()=>{try{this.clearCache(),t(this.getDeviceInfo())}catch(e){console.warn("DeviceDetector: Error in device change handler:",e)}};return window.addEventListener("orientationchange",e),window.addEventListener("resize",e),()=>{window.removeEventListener("orientationchange",e),window.removeEventListener("resize",e)}}}e(Xt,"cachedDeviceInfo",null);const Wt=Object.freeze(Object.defineProperty({__proto__:null,DeviceDetector:Xt,isDeviceCompatible:t=>{if(!t||"both"===t)return!0;const e=Xt.getDeviceInfo();return"mobile"===t?e.isMobile||e.isTablet:"desktop"===t&&e.isDesktop}},Symbol.toStringTag,{value:"Module"})),jt=class t{constructor(){e(this,"transcriptContainer",null),e(this,"transcriptContent",null),e(this,"ccButton",null),e(this,"isVisible",!0),e(this,"currentTranscript",null),e(this,"chunks",[]),e(this,"videoElement",null),e(this,"timeUpdateListener",null),e(this,"videoManager",null),e(this,"firstWordForceDisplayUntil",0),e(this,"isNewVideo",!1),e(this,"lastDisplayedChunkIndex",-1),e(this,"animationFrameId",null),e(this,"isAnimationLoopActive",!1),e(this,"currentWindowStartIndex",-1),e(this,"currentWindowEndIndex",-1)}setup(t,e,n){this.videoElement=t,this.ccButton=e,this.videoManager=n,this.ccButton.addEventListener("click",this.handleCCButtonClick.bind(this)),this.timeUpdateListener=this.handleTimeUpdate.bind(this),this.videoElement.addEventListener("timeupdate",this.timeUpdateListener)}updateVideoElement(t){this.videoElement&&this.timeUpdateListener&&this.videoElement.removeEventListener("timeupdate",this.timeUpdateListener),this.videoElement=t,this.videoElement&&this.timeUpdateListener&&this.videoElement.addEventListener("timeupdate",this.timeUpdateListener)}loadTranscript(e,n=!0){this.transcriptContent&&(this.transcriptContent.innerHTML=""),this.lastDisplayedChunkIndex=-1,this.currentWindowStartIndex=-1,this.currentWindowEndIndex=-1,this.currentTranscript=e,e?(this.createTranscriptUI(),this.chunks=e.chunks||[],this.isNewVideo=!0,this.firstWordForceDisplayUntil=Date.now()+500,this.setupWordDisplay(),null!==t.userCaptionPreference?(this.isVisible=t.userCaptionPreference,this.isVisible):(this.isVisible=n,this.isVisible),this.updateCCButtonState(!0),this.isVisible?this.showTranscript():this.hideTranscript(),this.chunks.length,this.isVisible):(this.updateCCButtonState(!1),this.hideTranscript())}toggleVisibility(){this.currentTranscript&&(this.isVisible=!this.isVisible,t.userCaptionPreference=this.isVisible,this.isVisible,this.isVisible?(this.showTranscript(),this.startAnimationLoop()):(this.hideTranscript(),this.stopAnimationLoop()),this.updateCCButtonState(!!this.currentTranscript),this.isVisible)}handleCCButtonClick(t){t.preventDefault(),t.stopPropagation(),this.toggleVisibility()}handleTimeUpdate(t){!this.isAnimationLoopActive&&this.isVisible&&this.chunks.length>0&&this.startAnimationLoop()}startAnimationLoop(){if(this.isAnimationLoopActive)return;this.isAnimationLoopActive=!0;const t=()=>{if(!this.currentTranscript||!this.isVisible||!this.videoElement||0===this.chunks.length)return void this.stopAnimationLoop();const e=this.videoElement.currentTime;let n=this.findActiveChunkIndex(e);const i=Date.now();this.isNewVideo&&i<this.firstWordForceDisplayUntil&&this.chunks.length>0?n=0:this.isNewVideo&&i>=this.firstWordForceDisplayUntil&&(this.isNewVideo=!1),this.updateIntelligentWordDisplay(n),this.animationFrameId=requestAnimationFrame(t)};this.animationFrameId=requestAnimationFrame(t)}stopAnimationLoop(){null!==this.animationFrameId&&(cancelAnimationFrame(this.animationFrameId),this.animationFrameId=null),this.isAnimationLoopActive=!1}findActiveChunkIndex(t){if(0===this.chunks.length)return-1;for(let e=0;e<this.chunks.length;e++){const n=this.chunks[e];if(t>=n.start&&t<=n.end)return e}if(t<this.chunks[0].start)return 0;if(t>this.chunks[this.chunks.length-1].end)return this.chunks.length-1;for(let e=0;e<this.chunks.length-1;e++)if(t>this.chunks[e].end&&t<this.chunks[e+1].start){if(this.chunks[e+1].start-t<.1)return e+1;return t-this.chunks[e].end<.1?e:e+1}return-1}handleStateChange(t){if(this.currentTranscript,this.chunks.length,this.currentTranscript&&0!==this.chunks.length)return"waitingForInteraction"===t||"completedWaitingForInteraction"===t?(this.transcriptContent&&(this.transcriptContent.innerHTML=""),void this.stopAnimationLoop()):void(this.isVisible?(this.isVisible,this.showTranscript(),this.startAnimationLoop()):(this.isVisible,this.hideTranscript(),this.stopAnimationLoop()));this.stopAnimationLoop()}updateIntelligentWordDisplay(t){if(!this.transcriptContent)return;if(t===this.lastDisplayedChunkIndex)return;if(!(t>=0&&t<this.chunks.length?this.chunks[t]:null))return this.lastDisplayedChunkIndex=-1,void(this.transcriptContent.innerHTML="");t>=this.currentWindowStartIndex&&t<=this.currentWindowEndIndex&&-1!==this.currentWindowStartIndex?this.updateHighlightInWindow(t):this.createNewWindow(t),this.lastDisplayedChunkIndex=t}updateHighlightInWindow(t){if(!this.transcriptContent)return;const e=this.transcriptContent.querySelectorAll(".sf-transcript__word"),n=t-this.currentWindowStartIndex;e.forEach(((t,e)=>{t.classList.remove("sf-transcript__word--active"),e<=n?t.classList.add("sf-transcript__word--visible"):t.classList.remove("sf-transcript__word--visible")})),e[n]&&e[n].classList.add("sf-transcript__word--active")}createNewWindow(t){if(!this.transcriptContent)return;const e=this.calculateWordWindow(t);this.currentWindowStartIndex=e.startIndex,this.currentWindowEndIndex=e.endIndex;const n=this.transcriptContent.querySelector(".sf-transcript__word-container"),i=()=>{const n=document.createElement("div");n.className="sf-transcript__word-container";const i=t-e.startIndex;for(let s=e.startIndex;s<=e.endIndex;s++){const r=this.chunks[s],a=document.createElement("span");let o="sf-transcript__word";s-e.startIndex<=i&&(o+=" sf-transcript__word--visible"),s===t&&(o+=" sf-transcript__word--active"),a.className=o,a.textContent=r.text,n.appendChild(a)}return n};if(n)n.style.opacity="0",setTimeout((()=>{if(!this.transcriptContent)return;this.transcriptContent.innerHTML="";const t=i();t.style.opacity="0",this.transcriptContent.appendChild(t),requestAnimationFrame((()=>{t.style.opacity="1"}))}),150);else{const t=i();this.transcriptContent.appendChild(t)}}calculateWordWindow(t){if(t<0||t>=this.chunks.length)return{startIndex:-1,endIndex:-1};let e=t,n=t,i=this.chunks[t].text.length;const s=this.chunks[t].text.trim();if(s.endsWith(".")||s.endsWith("!")||s.endsWith("?"))return{startIndex:e,endIndex:n};for(;n-e+1<4&&n+1<this.chunks.length;){const t=this.chunks[n+1].text,e=Math.ceil(1.12*t.length);if(i+e>18)break;n++,i+=e;const s=t.trim();if(s.endsWith(".")||s.endsWith("!")||s.endsWith("?"))break}return{startIndex:e,endIndex:n}}createTranscriptUI(){var t;this.transcriptContainer&&this.transcriptContainer.parentNode&&(this.transcriptContainer.parentNode.removeChild(this.transcriptContainer),this.transcriptContainer=null,this.transcriptContent=null);const e=null==(t=this.videoElement)?void 0:t.closest(".sf-video-container");e&&(this.transcriptContainer=document.createElement("div"),this.transcriptContainer.className="sf-transcript",this.transcriptContainer.classList.add("sf-hidden"),this.transcriptContent=document.createElement("div"),this.transcriptContent.className="sf-transcript__content",this.transcriptContainer&&this.transcriptContent&&(this.transcriptContainer.appendChild(this.transcriptContent),e.appendChild(this.transcriptContainer)))}setupWordDisplay(){this.transcriptContent&&(this.transcriptContent.innerHTML="")}showTranscript(){this.transcriptContainer,this.transcriptContainer&&(this.transcriptContainer.classList.remove("sf-hidden"),this.transcriptContainer.classList.add("sf-transcript--visible"))}hideTranscript(){this.transcriptContainer,this.transcriptContainer&&(this.transcriptContainer.classList.add("sf-hidden"),this.transcriptContainer.classList.remove("sf-transcript--visible"))}updateCCButtonState(t){var e;this.ccButton&&(t?(this.ccButton.classList.remove("sf-hidden"),null==(e=this.videoManager)||e.updateCCButtonIcon(this.isVisible)):this.ccButton.classList.add("sf-hidden"))}reset(){this.stopAnimationLoop(),this.transcriptContent&&(this.transcriptContent.innerHTML=""),this.currentTranscript=null,this.chunks=[],this.isNewVideo=!1,this.firstWordForceDisplayUntil=0,this.lastDisplayedChunkIndex=-1,this.currentWindowStartIndex=-1,this.currentWindowEndIndex=-1,this.isVisible&&this.hideTranscript(),this.updateCCButtonState(!1),this.transcriptContainer=null,this.transcriptContent=null}static resetUserPreference(){t.userCaptionPreference=null}async destroy(){this.stopAnimationLoop(),this.timeUpdateListener&&this.videoElement&&this.videoElement.removeEventListener("timeupdate",this.timeUpdateListener),this.transcriptContainer&&this.transcriptContainer.parentNode&&this.transcriptContainer.parentNode.removeChild(this.transcriptContainer),this.transcriptContainer=null,this.transcriptContent=null,this.ccButton=null,this.videoElement=null,this.timeUpdateListener=null,this.currentTranscript=null,this.isVisible=!1}};e(jt,"userCaptionPreference",null);let qt=jt;class Zt{constructor(t){e(this,"deviceInfo"),this.deviceInfo=t}updateDeviceInfo(t){this.deviceInfo=t}}class Gt extends Zt{getVideoElementConfig(){return{playsInline:!0,muted:!0,controls:!1,preload:"metadata",additionalAttributes:{"webkit-playsinline":"true",playsinline:"true","x-webkit-airplay":"allow"},styles:{width:"100%",height:"100%",objectFit:"cover",backgroundColor:"white"}}}getControlsConfig(){return{buttonMinSize:{width:"44px",height:"44px"},useTouch:!0,progressUpdateInterval:500}}getAutoplayConfig(t){return{shouldStartMuted:!t,enableFallbackLoop:!0,fallbackTimeout:3e3,requiresUserInteraction:!0}}configureVideoElement(t){const e=this.getVideoElementConfig();t.playsInline=e.playsInline,t.muted=e.muted,t.controls=e.controls,t.preload=e.preload,Object.entries(e.additionalAttributes).forEach((([e,n])=>{try{t.setAttribute(e,n)}catch(i){console.warn(`MobilePlaybackHandler: Failed to set attribute ${e}:`,i)}})),Object.entries(e.styles).forEach((([e,n])=>{try{t.style.setProperty(e,n)}catch(i){console.warn(`MobilePlaybackHandler: Failed to set style ${e}:`,i)}}))}configureControlElement(t){const e=this.getControlsConfig();t.style.setProperty("min-width",e.buttonMinSize.width),t.style.setProperty("min-height",e.buttonMinSize.height)}async handlePlayAttempt(t,e){const n=bt().isMuted;t.muted=n,t.loop=!1;try{return await t.play(),!0}catch(i){return t.muted,await this.handleAutoplayFallback(t),!1}}async handleAutoplayFallback(t){t.muted=!0,t.loop=!0,t.playsInline=!0,t.setAttribute("playsinline","true"),t.setAttribute("webkit-playsinline","true");try{await t.play()}catch(e){console.error("MobilePlaybackHandler: All autoplay attempts failed")}}destroy(){}getProgressUpdateFrequency(t){return t?500:16}}class Kt extends Zt{getVideoElementConfig(){return{playsInline:!0,muted:!1,controls:!1,preload:"metadata",additionalAttributes:{},styles:{backgroundColor:"white"}}}getControlsConfig(){return{buttonMinSize:{width:"auto",height:"auto"},useTouch:!1,progressUpdateInterval:16}}getAutoplayConfig(t){return{shouldStartMuted:!1,enableFallbackLoop:!1,fallbackTimeout:5e3,requiresUserInteraction:!1}}configureVideoElement(t){const e=this.getVideoElementConfig();t.playsInline=e.playsInline,t.muted=e.muted,t.controls=e.controls,t.preload=e.preload,Object.entries(e.styles).forEach((([e,n])=>{t.style.setProperty(e,n)}))}configureControlElement(t){}async handlePlayAttempt(t,e){const n=bt().isMuted;t.muted=n,t.loop=!1;try{return await t.play(),!0}catch(i){return t.muted,await this.handleAutoplayFallback(t),!1}}async handleAutoplayFallback(t){t.muted=!0,t.loop=!0;try{await t.play()}catch(e){throw console.error("DesktopPlaybackHandler: All autoplay attempts failed"),new Error("Desktop autoplay completely blocked")}}getProgressUpdateFrequency(t){return 16}destroy(){}}class Jt{constructor(t,n,i){e(this,"container"),e(this,"controlsElement",null),e(this,"progressBar",null),e(this,"muteButton",null),e(this,"ccButton",null),e(this,"deviceHandler"),e(this,"callbacks"),e(this,"updateInterval",null),e(this,"animationFrameId",null),e(this,"lastTimeupdateEvent",0),e(this,"videoElement",null),e(this,"buttonsShownAt90Percent",!1),e(this,"handleDetailedTimeUpdate",(()=>{var t;if(this.lastTimeupdateEvent=Date.now(),this.progressBar&&!1===(null==(t=this.videoElement)?void 0:t.paused)&&this.progressBar.style.setProperty("transition","width 0.1s linear"),this.videoElement&&!this.buttonsShownAt90Percent&&this.videoElement.duration>0){this.videoElement.currentTime/this.videoElement.duration>=.9&&(this.callbacks.on90PercentReached(),this.buttonsShownAt90Percent=!0)}})),e(this,"handleSeeking",(()=>{this.progressBar&&(this.progressBar.style.setProperty("transition","none"),this.updateProgress())})),e(this,"handleSeeked",(()=>{this.progressBar&&this.videoElement&&(this.videoElement.paused||(this.updateProgress(),this.progressBar.offsetWidth,this.progressBar.style.setProperty("transition","width 0.1s linear")))})),e(this,"handleProgressBarClick",(t=>{const e=t.currentTarget;if(!this.videoElement||this.videoElement.duration<=0)return;const n=e.getBoundingClientRect(),i=(t.clientX-n.left)/n.width,s=this.videoElement.duration*i;this.progressBar&&(this.progressBar.style.setProperty("transition","none"),this.progressBar.style.setProperty("width",100*i+"%")),this.callbacks.onSeek(s),t.preventDefault(),t.stopPropagation()})),this.container=t,this.deviceHandler=n,this.callbacks=i}create(t){this.videoElement=t,this.controlsElement=document.createElement("div"),this.controlsElement.className="sf-video-container__controls",this.container.appendChild(this.controlsElement),this.progressBar=document.createElement("div"),this.progressBar.className="sf-video-container__progress",this.controlsElement.appendChild(this.progressBar);const e=this.deviceHandler.getControlsConfig();e.useTouch&&this.controlsElement.addEventListener("touchend",this.handleProgressBarClick),this.controlsElement.addEventListener("click",this.handleProgressBarClick),this.muteButton=document.createElement("button"),this.muteButton.className="sf-video-container__mute-button",this.deviceHandler.configureControlElement(this.muteButton),this.muteButton.innerHTML='\n <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">\n <polygon points="11 5 6 9 2 9 2 15 6 15 11 19 11 5" fill="none"></polygon>\n <path d="M15 9c0.8 0.8 1.5 1.9 1.5 3s-0.7 2.2-1.5 3" stroke="currentColor"></path>\n <path d="M19 7c1.6 1.6 2.5 3.8 2.5 6s-0.9 4.4-2.5 6" stroke="currentColor"></path>\n </svg>\n ',e.useTouch&&this.muteButton.addEventListener("touchend",(t=>{t.preventDefault(),this.toggleMute()})),this.muteButton.addEventListener("click",(t=>{t.preventDefault(),t.stopPropagation(),this.toggleMute()})),this.container.appendChild(this.muteButton),this.updateMuteButtonIcon(),this.ccButton=document.createElement("button"),this.ccButton.className="sf-video-container__cc-button",this.deviceHandler.configureControlElement(this.ccButton),this.updateCCButtonIcon(!1),e.useTouch&&this.ccButton.addEventListener("touchend",(t=>{t.preventDefault()})),this.ccButton.addEventListener("click",(t=>{t.preventDefault()})),this.container.appendChild(this.ccButton),t&&(t.addEventListener("seeking",this.handleSeeking),t.addEventListener("seeked",this.handleSeeked),t.addEventListener("timeupdate",this.handleDetailedTimeUpdate))}updateVideoElement(t){this.videoElement&&(this.videoElement.removeEventListener("seeking",this.handleSeeking),this.videoElement.removeEventListener("seeked",this.handleSeeked),this.videoElement.removeEventListener("timeupdate",this.handleDetailedTimeUpdate)),this.videoElement=t,t&&(t.addEventListener("seeking",this.handleSeeking),t.addEventListener("seeked",this.handleSeeked),t.addEventListener("timeupdate",this.handleDetailedTimeUpdate))}reset(){this.stopProgressTracking(),this.buttonsShownAt90Percent=!1,this.lastTimeupdateEvent=0,this.progressBar&&(this.progressBar.style.setProperty("transition","none"),this.progressBar.style.setProperty("width","0%"))}reset90PercentTrigger(){this.buttonsShownAt90Percent=!1}destroy(){if(this.stopProgressTracking(),this.videoElement&&(this.videoElement.removeEventListener("seeking",this.handleSeeking),this.videoElement.removeEventListener("seeked",this.handleSeeked),this.videoElement.removeEventListener("timeupdate",this.handleDetailedTimeUpdate)),this.controlsElement){this.deviceHandler.getControlsConfig().useTouch&&this.controlsElement.removeEventListener("touchend",this.handleProgressBarClick),this.controlsElement.removeEventListener("click",this.handleProgressBarClick)}this.controlsElement=null,this.progressBar=null,this.muteButton=null,this.ccButton=null,this.videoElement=null}startProgressTracking(){if(this.stopProgressTracking(),!this.videoElement)return;const t=this.videoElement.loop&&this.videoElement.muted,e=this.deviceHandler.getProgressUpdateFrequency(t);if(e>=16){const t=()=>{!this.videoElement||this.videoElement.paused||this.videoElement.ended||this.updateProgress(),this.animationFrameId=requestAnimationFrame(t)};this.animationFrameId=requestAnimationFrame(t)}else{const t=()=>{null===this.updateInterval||!this.videoElement||this.videoElement.paused||this.videoElement.ended||(this.updateProgress(),this.updateInterval=window.setTimeout(t,e))};this.updateInterval=window.setTimeout(t,e)}}stopProgressTracking(){null!==this.updateInterval&&(window.clearInterval(this.updateInterval),this.updateInterval=null),null!==this.animationFrameId&&(cancelAnimationFrame(this.animationFrameId),this.animationFrameId=null)}updateProgressImmediate(t,e){if(!this.progressBar||e<=0)return;const n=t/e*100;this.progressBar.style.setProperty("transition","none"),this.progressBar.style.setProperty("width",`${n}%`)}updateProgress(){if(!this.progressBar||!this.videoElement)return;const t=this.videoElement.currentTime||0,e=this.videoElement.duration||0;if(e>0){const n=t/e*100,i="none"!==this.progressBar.style.getPropertyValue("transition"),s=Date.now()-this.lastTimeupdateEvent;this.progressBar.style.setProperty("transition","none"),this.progressBar.style.setProperty("width",`${n}%`),this.progressBar.offsetWidth,this.videoElement.ended?this.progressBar.style.setProperty("transition","width 0.2s ease-out"):!this.videoElement.paused&&!this.videoElement.seeking&&i&&s<500&&this.progressBar.style.setProperty("transition","width 0.1s linear")}}setMuted(t){bt().setMuted(t),this.updateMuteButtonIcon()}toggleMute(){const t=!bt().isMuted;this.setMuted(t),this.callbacks.onMuteToggle()}getMuted(){return bt().isMuted}updateMuteButtonIcon(){if(!this.muteButton)return;const t=bt().isMuted;this.muteButton.innerHTML=t?'\n <svg width="18" height="18" viewBox="0 0 256 256" fill="currentColor" xmlns="http://www.w3.org/2000/svg">\n <path d="M155.51,24.81a8,8,0,0,0-8.42.88L77.25,80H32A16,16,0,0,0,16,96v64a16,16,0,0,0,16,16H77.25l69.84,54.31A8,8,0,0,0,160,224V32A8,8,0,0,0,155.51,24.81ZM32,96H72v64H32ZM144,207.64,88,164.09V91.91l56-43.55Zm101.66-61.3a8,8,0,0,1-11.32,11.32L216,139.31l-18.34,18.35a8,8,0,0,1-11.32-11.32L204.69,128l-18.35-18.34a8,8,0,0,1,11.32-11.32L216,116.69l18.34-18.35a8,8,0,0,1,11.32,11.32L227.31,128Z"></path>\n </svg>\n ':'\n <svg width="18" height="18" viewBox="0 0 256 256" fill="currentColor" xmlns="http://www.w3.org/2000/svg">\n <path d="M155.51,24.81a8,8,0,0,0-8.42.88L77.25,80H32A16,16,0,0,0,16,96v64a16,16,0,0,0,16,16H77.25l69.84,54.31A8,8,0,0,0,160,224V32A8,8,0,0,0,155.51,24.81ZM32,96H72v64H32ZM144,207.64,88,164.09V91.91l56-43.55Zm54-106.08a40,40,0,0,1,0,52.88,8,8,0,0,1-12-10.58,24,24,0,0,0,0-31.72,8,8,0,0,1,12-10.58ZM248,128a79.9,79.9,0,0,1-20.37,53.34,8,8,0,0,1-11.92-10.67,64,64,0,0,0,0-85.33,8,8,0,1,1,11.92-10.67A79.83,79.83,0,0,1,248,128Z"></path>\n </svg>\n '}updateCCButtonIcon(t){this.ccButton&&(this.ccButton.innerHTML=t?'\n <svg width="18" height="18" viewBox="0 0 256 256" fill="currentColor" xmlns="http://www.w3.org/2000/svg">\n <path d="M224,48H32A16,16,0,0,0,16,64V192a16,16,0,0,0,16,16H224a16,16,0,0,0,16-16V64A16,16,0,0,0,224,48Zm0,144H32V64H224V192ZM118.92,151.71A8,8,0,0,1,116,162.64a40,40,0,1,1,0-69.28,8,8,0,1,1-8,13.85,24,24,0,1,0,0,41.58A8,8,0,0,1,118.92,151.71Zm80,0A8,8,0,0,1,196,162.64a40,40,0,1,1,0-69.28,8,8,0,1,1-8,13.85,24,24,0,1,0,0,41.58A8,8,0,0,1,198.92,151.71Z"></path>\n </svg>\n ':'\n <svg width="18" height="18" viewBox="0 0 256 256" fill="currentColor" xmlns="http://www.w3.org/2000/svg">\n <path d="M224,48H32A16,16,0,0,0,16,64V192a16,16,0,0,0,16,16H224a16,16,0,0,0,16-16V64A16,16,0,0,0,224,48Zm0,144H32V64H224V192ZM118.92,151.71A8,8,0,0,1,116,162.64a40,40,0,1,1,0-69.28,8,8,0,1,1-8,13.85,24,24,0,1,0,0,41.58A8,8,0,0,1,118.92,151.71Zm80,0A8,8,0,0,1,196,162.64a40,40,0,1,1,0-69.28,8,8,0,1,1-8,13.85,24,24,0,1,0,0,41.58A8,8,0,0,1,198.92,151.71Z"></path>\n <line x1="48" y1="48" x2="208" y2="208" stroke="currentColor" stroke-width="16" stroke-linecap="round"/>\n </svg>\n ')}showProgressBar(){if(this.controlsElement){const t=this.controlsElement.closest(".sf-player");null==t||t.classList.contains("sf-player--minimized");this.controlsElement.classList.remove("sf-hidden")}this.progressBar&&(this.progressBar.style.setProperty("transition","none"),this.progressBar.style.setProperty("width","0%"),this.progressBar.offsetWidth,this.progressBar.style.setProperty("transition","width 0.1s linear"))}hideProgressBar(){this.controlsElement&&this.controlsElement.classList.add("sf-hidden")}showMuteButton(){this.muteButton&&this.muteButton.classList.remove("sf-hidden")}hideMuteButton(){this.muteButton&&this.muteButton.classList.add("sf-hidden")}getCCButton(){return this.ccButton}}class Qt{constructor(){e(this,"audioContext",null),e(this,"analyser",null),e(this,"sourceVideo1",null),e(this,"sourceVideo2",null),e(this,"activeSource",null),e(this,"videoElement1",null),e(this,"videoElement2",null),e(this,"dataArray",null),e(this,"animationId",null),e(this,"isInitialized",!1),e(this,"useFallbackMode",!1),e(this,"isPaused",!1),e(this,"fftSize",2048),e(this,"barCount",12),e(this,"smoothingTimeConstant",.75),e(this,"fallbackTime",0),e(this,"zeroDataFrameCount",0),e(this,"maxZeroFramesBeforeFallback",60)}initialize(t){try{if(!this.isInitialized){const t=window.AudioContext||window.webkitAudioContext;this.audioContext=new t,this.analyser=this.audioContext.createAnalyser(),this.analyser.fftSize=this.fftSize,this.analyser.smoothingTimeConstant=this.smoothingTimeConstant;const e=this.analyser.frequencyBinCount;this.dataArray=new Uint8Array(e),this.analyser.connect(this.audioContext.destination),this.isInitialized=!0,this.useFallbackMode=!1,this.zeroDataFrameCount=0}if(this.videoElement1===t)return this.resumeAudioContext(),void this.switchToSource(this.sourceVideo1);if(this.videoElement2===t)return this.resumeAudioContext(),void this.switchToSource(this.sourceVideo2);this.resumeAudioContext();const e=this.audioContext.createMediaElementSource(t);this.videoElement1?this.videoElement2?console.warn("AudioVisualizationManager: More than 2 video elements detected - this should not happen with dual video system"):(this.videoElement2=t,this.sourceVideo2=e,this.switchToSource(e)):(this.videoElement1=t,this.sourceVideo1=e,this.switchToSource(e)),this.zeroDataFrameCount=0}catch(e){console.warn("AudioVisualizationManager: Web Audio API failed, using fallback animation",e),this.isInitialized=!0,this.useFallbackMode=!0}}switchToSource(t){this.activeSource&&this.activeSource!==t&&this.activeSource.disconnect(),t.connect(this.analyser),this.activeSource=t}getBarHeights(){if(this.isPaused)return this.getFlatBarHeights();if(this.useFallbackMode||!this.analyser||!this.dataArray)return this.getFallbackBarHeights();this.analyser.getByteFrequencyData(this.dataArray);const t=this.dataArray.some((t=>t>0));if(!t)return this.zeroDataFrameCount++,this.zeroDataFrameCount>=this.maxZeroFramesBeforeFallback&&(this.useFallbackMode||(console.warn("AudioVisualizationManager: Detected CORS blocking audio analysis after",this.zeroDataFrameCount,"frames, switching to fallback animation"),this.useFallbackMode=!0)),this.getFallbackBarHeights();this.zeroDataFrameCount=0,this.useFallbackMode&&t&&(this.useFallbackMode=!1);const e=Math.floor(this.barCount/2),n=[],i=this.dataArray.length,s=Math.floor(i/this.barCount);for(let a=0;a<e;a++){let t=0;const e=a*s,r=e+s;for(let n=e;n<r&&n<i;n++)t+=this.dataArray[n];const o=t/s/255;n.push(o)}const r=[...n].reverse();r.pop();return r.concat(n)}getFallbackBarHeights(){const t=Math.floor(this.barCount/2),e=[];for(let i=0;i<t;i++)e.push(0);const n=[...e].reverse();n.pop();return n.concat(e)}getFlatBarHeights(){const t=Math.floor(this.barCount/2),e=[];for(let i=0;i<t;i++)e.push(.1);const n=[...e].reverse();n.pop();return n.concat(e)}getAverageAmplitude(){if(this.useFallbackMode||!this.analyser||!this.dataArray)return 0;this.analyser.getByteFrequencyData(this.dataArray);let t=0;for(let n=0;n<this.dataArray.length;n++)t+=this.dataArray[n];const e=t/this.dataArray.length/255;return 0===e?0:e}startVisualization(t){if(!this.isInitialized)return void console.warn("AudioVisualizationManager: Cannot start visualization - not initialized");null!==this.animationId&&this.stopVisualization(),this.audioContext&&"suspended"===this.audioContext.state&&this.audioContext.resume(),this.fallbackTime=0,this.zeroDataFrameCount=0;const e=()=>{this.fallbackTime+=16;const n=this.getBarHeights(),i=this.getAverageAmplitude();t(n,i),this.animationId=requestAnimationFrame(e)};e()}stopVisualization(){null!==this.animationId&&(cancelAnimationFrame(this.animationId),this.animationId=null)}pause(){this.isPaused=!0}resume(){this.isPaused=!1}resumeAudioContext(){this.audioContext&&"suspended"===this.audioContext.state&&this.audioContext.resume().catch((t=>{console.warn("AudioVisualizationManager: Failed to resume AudioContext",t)}))}resetFallbackMode(){this.useFallbackMode&&(this.useFallbackMode=!1,this.zeroDataFrameCount=0)}getIsInitialized(){return this.isInitialized}reset(){if(this.stopVisualization(),this.sourceVideo1)try{this.sourceVideo1.disconnect()}catch(t){}if(this.sourceVideo2)try{this.sourceVideo2.disconnect()}catch(t){}this.videoElement1=null,this.videoElement2=null,this.sourceVideo1=null,this.sourceVideo2=null,this.activeSource=null,this.useFallbackMode=!1,this.isPaused=!1,this.fallbackTime=0,this.zeroDataFrameCount=0}cleanup(){this.stopVisualization(),this.sourceVideo1&&this.sourceVideo1.disconnect(),this.sourceVideo2&&this.sourceVideo2.disconnect(),this.analyser&&this.analyser.disconnect(),this.audioContext&&"closed"!==this.audioContext.state&&this.audioContext.close(),this.audioContext=null,this.analyser=null,this.sourceVideo1=null,this.sourceVideo2=null,this.activeSource=null,this.videoElement1=null,this.videoElement2=null,this.dataArray=null,this.isInitialized=!1,this.useFallbackMode=!1,this.isPaused=!1,this.fallbackTime=0,this.zeroDataFrameCount=0}destroy(){this.cleanup()}}class te{constructor(){e(this,"currentVideo",null),e(this,"nextVideo",null),e(this,"activeVideoIndex",0),e(this,"container",null),e(this,"controls",null),e(this,"transcriptManager"),e(this,"preloadedVideos",new Map),e(this,"audioFallbackOverlay",null),e(this,"audioVisualizationManager"),e(this,"soundbarElement",null),e(this,"currentVideoUrl",""),e(this,"nextVideoUrl",""),e(this,"playbackPositions",new Map),e(this,"completionPolicy","auto"),e(this,"videoEndedCallback",null),e(this,"deviceHandler"),e(this,"deviceChangeCleanup",null),e(this,"hasUserInteracted",!1),e(this,"autoplayFallbackTimeout",null),e(this,"handleVideoEnded",(t=>{const e=t.target,n=this.getActiveVideo();if(e!==n)return;const i=bt();"autoplayBlocked"!==i.currentState&&"idleMode"!==i.currentState?(this.controls&&n&&this.controls.updateProgressImmediate(n.duration,n.duration),n&&n.classList.add("sf-video-container__video--blurred"),"auto"===this.completionPolicy?this.handleAutoVideoEnded():this.handleManualVideoEnded()):i.currentState})),e(this,"handleTimeUpdate",(t=>{const e=t.target;e===this.getActiveVideo()&&Math.floor(e.currentTime)})),e(this,"handleVideoError",(t=>{const e=t.target;e===this.getActiveVideo()&&console.error("VideoManager: Video error",e.error)})),e(this,"handleAutoVideoEnded",(()=>{this.videoEndedCallback&&this.videoEndedCallback()})),e(this,"handleManualVideoEnded",(()=>{this.videoEndedCallback&&this.videoEndedCallback()}));const t=Xt.getDeviceInfo();this.deviceHandler=function(t){return t.isMobile?new Gt(t):new Kt(t)}(t),this.transcriptManager=new qt,this.audioVisualizationManager=new Qt,this.deviceChangeCleanup=Xt.onDeviceChange((t=>{this.deviceHandler.updateDeviceInfo(t)}))}getDeviceInfo(){return Xt.getDeviceInfo()}isMobileDevice(){return this.getDeviceInfo().isMobile}create(t){this.container=document.createElement("div"),this.container.className="sf-video-container",t.appendChild(this.container),this.currentVideo=document.createElement("video"),this.currentVideo.className="sf-video-container__video sf-video-container__video--current",this.currentVideo.crossOrigin="anonymous",this.deviceHandler.configureVideoElement(this.currentVideo),this.container.appendChild(this.currentVideo),this.nextVideo=document.createElement("video"),this.nextVideo.className="sf-video-container__video sf-video-container__video--next sf-hidden",this.nextVideo.crossOrigin="anonymous",this.deviceHandler.configureVideoElement(this.nextVideo),this.container.appendChild(this.nextVideo);bt().isMuted&&(this.currentVideo.muted=!0,this.nextVideo.muted=!0);const e={onSeek:t=>this.seek(t),onMuteToggle:()=>{var t;const e=(null==(t=this.controls)?void 0:t.getMuted())??!1;this.currentVideo&&(this.currentVideo.muted=e),this.nextVideo&&(this.nextVideo.muted=e),!e&&this.audioVisualizationManager.getIsInitialized()&&this.audioVisualizationManager.resetFallbackMode()},on90PercentReached:()=>{if(this.container){const t=new CustomEvent("video90PercentReached",{bubbles:!0,detail:{timestamp:Date.now()}});this.container.dispatchEvent(t)}}};if(this.controls=new Jt(this.container,this.deviceHandler,e),this.controls.create(this.currentVideo),this.addEventListeners(),this.currentVideo&&this.controls){const t=this.controls.getCCButton();t&&this.transcriptManager.setup(this.currentVideo,t,this)}}getActiveVideo(){return 0===this.activeVideoIndex?this.currentVideo:this.nextVideo}getInactiveVideo(){return 0===this.activeVideoIndex?this.nextVideo:this.currentVideo}swapVideos(){const t=this.getActiveVideo(),e=this.getInactiveVideo();if(!t||!e)return;t.pause();const n=bt();e.muted=n.isMuted,t.classList.add("sf-hidden"),e.classList.remove("sf-hidden"),this.activeVideoIndex=0===this.activeVideoIndex?1:0,this.currentVideoUrl=this.nextVideoUrl,this.nextVideoUrl=""}async loadVideo(t){var e;const n=this.getActiveVideo();if(!n)return;if(!t||""===t.trim())throw new Error("Cannot load video: No video URL provided for this step");this.controls&&this.controls.reset90PercentTrigger();const i=bt();n.muted=i.isMuted;try{this.controls&&this.controls.reset();const i=(null==(e=bt().playlistOptions)?void 0:e.persistence)??!0;if(this.currentVideoUrl===t&&n.src&&(n.src===t||n.src.endsWith(t))){if(i){const e=this.playbackPositions.get(t);void 0!==e&&e>0&&Math.abs(n.currentTime-e)>.5&&(n.currentTime=e)}return}i&&this.currentVideoUrl&&n.currentTime>0&&this.playbackPositions.set(this.currentVideoUrl,n.currentTime);if(this.getInactiveVideo()&&this.nextVideoUrl===t){this.swapVideos();const t=this.getActiveVideo();return t&&(this.transcriptManager.updateVideoElement(t),this.controls&&this.controls.updateVideoElement(t)),void(await new Promise((t=>{const e=this.getActiveVideo();if(!e)return t();if(e.readyState>=3)t();else{const n=()=>{e.removeEventListener("canplay",n),t()};e.addEventListener("canplay",n)}})))}this.currentVideoUrl=t;const s=this.preloadedVideos.get(t);if(s){const e=URL.createObjectURL(s);n.src=e,this.preloadedVideos.delete(t)}else n.src=t;n.load(),await new Promise(((e,s)=>{if(!n)return e(void 0);let r;const a=()=>{if(n){if(clearTimeout(r),i){const e=this.playbackPositions.get(t);if(void 0!==e&&e>0){const t=Math.min(e,n.duration-.5);n.currentTime=t}}else n.currentTime=0;this.transcriptManager.updateVideoElement(n),this.controls&&this.controls.updateVideoElement(n),n.removeEventListener("loadeddata",a),n.removeEventListener("error",o),e(void 0)}},o=e=>{clearTimeout(r);const i=e.target,l=null==i?void 0:i.error;console.error("VideoManager: Video load error:",l),n.removeEventListener("loadeddata",a),n.removeEventListener("error",o);const c=new Error(`Video load failed: ${(null==l?void 0:l.message)||"Unknown error"}`);c.videoUrl=t,c.mediaErrorCode=(null==l?void 0:l.code)||null,c.mediaErrorMessage=(null==l?void 0:l.message)||null,c.failureReason="media_error",s(c)};r=window.setTimeout((()=>{console.error("VideoManager: Video load timeout after 10 seconds"),n.removeEventListener("loadeddata",a),n.removeEventListener("error",o);const e=new Error("Video load timeout");e.videoUrl=t,e.mediaErrorCode=null,e.mediaErrorMessage=null,e.failureReason="timeout",s(e)}),1e4),n.addEventListener("loadeddata",a),n.addEventListener("error",o)}))}catch(s){if(console.error("VideoManager: Failed to load video:",s),s&&"object"==typeof s&&"videoUrl"in s)throw s;const e=new Error("Failed to load video");throw e.videoUrl=t,e.mediaErrorCode=null,e.mediaErrorMessage=null,e.failureReason="load_error",e}}preloadNextVideo(t){if(!t||this.preloadedVideos.has(t))return;if(this.currentVideoUrl===t)return;if(this.nextVideoUrl===t)return;const e=this.getInactiveVideo();if(e){this.nextVideoUrl=t,e.src=t,e.load(),e.preload="auto";const n=bt();e.muted=n.isMuted}else fetch(t).then((t=>{if(!t.ok)throw new Error(`Failed to fetch video: ${t.statusText}`);return t.blob()})).then((e=>{this.preloadedVideos.set(t,e)})).catch((e=>{console.error(`VideoManager: Error preloading video ${t}:`,e)}))}play(){var t;const e=this.getActiveVideo();if(!e)return void console.error("VideoManager: No active video element found");e.classList.remove("sf-video-container__video--blurred"),e.ended&&(e.currentTime=0);const n=bt();if(((null==(t=n.playlistOptions)?void 0:t.persistence)??!0)&&this.currentVideoUrl){const t=this.playbackPositions.get(this.currentVideoUrl);t&&Math.abs(e.currentTime-t)>.5&&(e.currentTime=t)}if(e.loop=!1,this.audioVisualizationManager.getIsInitialized()&&this.audioVisualizationManager.resumeAudioContext(),!e.paused)return this.controls&&this.controls.startProgressTracking(),void(this.audioVisualizationManager.getIsInitialized()&&this.audioVisualizationManager.resume());this.deviceHandler.handlePlayAttempt(e,this.hasUserInteracted).then((t=>{e&&(t?(this.controls&&this.controls.startProgressTracking(),this.audioVisualizationManager.getIsInitialized()&&this.audioVisualizationManager.resume()):(n.setAutoplayFallback(),this.isMobileDevice()&&(e.playsInline=!0,e.setAttribute("playsinline","true"),e.setAttribute("webkit-playsinline","true"),setTimeout((()=>{e.paused&&e.play().catch((()=>{}))}),200))))})).catch((()=>{console.warn("VideoManager: Autoplay handler threw error - browser has strict autoplay policy");bt().setAutoplayFallback()}))}pause(){const t=this.getActiveVideo();t&&(t.paused||(t.muted=!0,this.controls&&this.controls.updateProgressImmediate(t.currentTime,t.duration),t.pause(),this.audioVisualizationManager.getIsInitialized()&&this.audioVisualizationManager.pause(),this.controls&&this.controls.stopProgressTracking()))}seek(t){const e=this.getActiveVideo();e&&(this.controls&&e.duration>0&&this.controls.updateProgressImmediate(t,e.duration),e.currentTime=t)}getCurrentTime(){const t=this.getActiveVideo();return t?t.currentTime:0}getDuration(){const t=this.getActiveVideo();return t?t.duration:0}getVideoElement(){return this.getActiveVideo()}reset(){this.controls&&this.controls.reset(),this.preloadedVideos.clear(),this.playbackPositions.clear(),this.currentVideoUrl="",this.nextVideoUrl="",this.activeVideoIndex=0,this.hasUserInteracted=!1,null!==this.autoplayFallbackTimeout&&(window.clearTimeout(this.autoplayFallbackTimeout),this.autoplayFallbackTimeout=null),this.completionPolicy="auto",this.videoEndedCallback=null,this.transcriptManager.reset(),this.hideAudioFallbackOverlay();const t=this.audioVisualizationManager.getIsInitialized();t&&this.audioVisualizationManager.reset(),this.currentVideo&&(t||(this.currentVideo.src=""),this.currentVideo.currentTime=0,this.currentVideo.pause()),this.nextVideo&&(t||(this.nextVideo.src=""),this.nextVideo.currentTime=0,this.nextVideo.pause())}async destroy(){this.removeEventListeners(),this.controls&&(this.controls.destroy(),this.controls=null),this.transcriptManager.destroy(),this.hideAudioFallbackOverlay(),null!==this.autoplayFallbackTimeout&&(window.clearTimeout(this.autoplayFallbackTimeout),this.autoplayFallbackTimeout=null),this.deviceChangeCleanup&&(this.deviceChangeCleanup(),this.deviceChangeCleanup=null),this.container&&this.container.parentNode&&this.container.parentNode.removeChild(this.container),this.currentVideo=null,this.nextVideo=null,this.container=null,this.currentVideoUrl="",this.nextVideoUrl="",this.videoEndedCallback=null}addEventListeners(){const t=this.currentVideo,e=this.nextVideo;t&&(t.addEventListener("ended",this.handleVideoEnded),t.addEventListener("error",this.handleVideoError)),e&&(e.addEventListener("ended",this.handleVideoEnded),e.addEventListener("error",this.handleVideoError))}removeEventListeners(){const t=this.currentVideo,e=this.nextVideo;t&&(t.removeEventListener("ended",this.handleVideoEnded),t.removeEventListener("error",this.handleVideoError)),e&&(e.removeEventListener("ended",this.handleVideoEnded),e.removeEventListener("error",this.handleVideoError))}setMuted(t){this.currentVideo&&(this.currentVideo.muted=t),this.nextVideo&&(this.nextVideo.muted=t),this.controls&&this.controls.setMuted(t),!t&&this.audioVisualizationManager.getIsInitialized()&&this.audioVisualizationManager.resetFallbackMode()}updateCCButtonIcon(t){this.controls&&this.controls.updateCCButtonIcon(t)}isMuted(){var t;return(null==(t=this.controls)?void 0:t.getMuted())??!0}showProgressBar(){this.controls&&this.controls.showProgressBar()}hideProgressBar(){this.controls&&this.controls.hideProgressBar()}showMuteButton(){this.controls&&this.controls.showMuteButton()}hideMuteButton(){this.controls&&this.controls.hideMuteButton()}setCompletionPolicy(t,e){this.completionPolicy=t,this.videoEndedCallback=e||null,this.updateVideoEndedHandler()}updateVideoEndedHandler(){}markUserInteraction(){this.hasUserInteracted||(this.hasUserInteracted=!0,null!==this.autoplayFallbackTimeout&&(window.clearTimeout(this.autoplayFallbackTimeout),this.autoplayFallbackTimeout=null))}hasUserInteractedWith(){return this.hasUserInteracted}resetUserInteraction(){this.hasUserInteracted=!1,null!==this.autoplayFallbackTimeout&&(window.clearTimeout(this.autoplayFallbackTimeout),this.autoplayFallbackTimeout=null)}handleAutoplayFallbackClick(t){this.markUserInteraction(),t.muted=!1,t.loop=!1,t.currentTime=0}loadTranscript(t,e=!0){this.transcriptManager.loadTranscript(t,e)}createSoundbar(){const t=document.createElement("div");t.className="sf-audio-soundbar";for(let e=0;e<11;e++){const n=document.createElement("div");n.className="sf-audio-soundbar__bar",n.dataset.barIndex=e.toString(),t.appendChild(n)}return t}showAudioFallbackOverlay(t,e){if(this.container){if(t&&(this.container.style.setProperty("--sf-audio-poster-url",`url('${t}')`),this.container.classList.add("sf-video-container--audio-fallback")),!this.audioFallbackOverlay){if(this.audioFallbackOverlay=document.createElement("div"),e){this.audioFallbackOverlay.className="sf-audio-fallback-overlay sf-audio-fallback-overlay--avatar";const t=document.createElement("img");t.className="sf-audio-fallback-overlay__avatar",t.src=e,t.alt="Speaker avatar";const n=document.createElement("div");n.className="sf-audio-fallback-overlay__dim",this.audioFallbackOverlay.appendChild(t),this.audioFallbackOverlay.appendChild(n)}else this.audioFallbackOverlay.className="sf-audio-fallback-overlay sf-audio-fallback-overlay--soundbar-only";this.soundbarElement=this.createSoundbar(),this.audioFallbackOverlay.appendChild(this.soundbarElement),this.container.appendChild(this.audioFallbackOverlay)}}else console.warn("VideoManager: Cannot show audio fallback overlay - container not available")}startAudioVisualization(){if(!this.soundbarElement)return;const t=this.getActiveVideo();if(t)try{this.audioVisualizationManager.initialize(t),this.audioVisualizationManager.startVisualization(((t,e)=>{if(!this.soundbarElement)return;this.soundbarElement.querySelectorAll(".sf-audio-soundbar__bar").forEach(((e,n)=>{const i=t[n]||0,s=e,r=Math.max(10,100*i);s.style.height=`${r}%`;const a=180+Math.abs(n-5)/5*120;s.style.backgroundColor=`hsla(${a}, 70%, 60%, 1)`}))}))}catch(e){console.error("VideoManager: Failed to initialize audio visualization",e)}}initializeAudioForVideo(){const t=this.getActiveVideo();if(t)try{this.audioVisualizationManager.initialize(t)}catch(e){console.error("VideoManager: Failed to initialize audio for video",e)}}hideAudioFallbackOverlay(){this.container&&(this.audioVisualizationManager.stopVisualization(),this.container.style.removeProperty("--sf-audio-poster-url"),this.container.classList.remove("sf-video-container--audio-fallback"),this.audioFallbackOverlay&&this.audioFallbackOverlay.parentNode&&(this.audioFallbackOverlay.parentNode.removeChild(this.audioFallbackOverlay),this.audioFallbackOverlay=null),this.soundbarElement=null)}}const ee={tolerance:.3,minSize:1};function ne(t){return t.trim().replace(/\s+/g," ")}function ie(t,e){if(t.tagName.toUpperCase()!==e.tagName.toUpperCase())return!1;return ne(t.textContent||"")===ne(e.textContent)}function se(t,e){const n=t.getBoundingClientRect();return 0===n.width||0===n.height?"zero size":n.width<e.minSize||n.height<e.minSize?`too small (${n.width.toFixed(0)}x${n.height.toFixed(0)})`:null}function re(t,e){const n=t.getBoundingClientRect();return(Math.min(n.width,e.width)/Math.max(n.width,e.width)+Math.min(n.height,e.height)/Math.max(n.height,e.height))/2*100}function ae(t,e,n,i=ee){const s=document.querySelectorAll(t);if(0===s.length)return null;if(e){const t=function(t,e,n){const i=[];for(const s of t)se(s,n)||ie(s,e)&&i.push(s);return 0===i.length?(e.tagName,e.textContent.substring(0,50),e.textContent.length,null):(i.length,i[0])}(s,e,i);if(t)return t;if(!n)return null}if(n)return function(t,e,n,i){const s=100*(1-i.tolerance),r=[];for(const o of e){const t=se(o,i);if(t){r.push({element:o,score:-1,rejection:t});continue}const e=re(o,n);if(e<s){const t=o.getBoundingClientRect();r.push({element:o,score:e,rejection:`size mismatch: expected ~${n.width.toFixed(0)}x${n.height.toFixed(0)}, got ${t.width.toFixed(0)}x${t.height.toFixed(0)}`})}else r.push({element:o,score:e})}r.length,n.width.toFixed(0),n.height.toFixed(0);for(let o=0;o<r.length;o++){const t=r[o],e=t.element.getBoundingClientRect();t.rejection?t.rejection:t.score.toFixed(0);e.width.toFixed(0),e.height.toFixed(0)}const a=r.filter((t=>!t.rejection));if(0===a.length)return null;return a.sort(((t,e)=>e.score-t.score)),a[0].score.toFixed(0),a[0].element}(0,s,n,i);for(const r of s){if(!se(r,i))return r}return s[0]}function oe(t,e,n,i=ee){const s=document.querySelectorAll(t);if(0===s.length)return[];if(e){const t=function(t,e,n){const i=[];for(const s of t)se(s,n)||ie(s,e)&&i.push(s);return i.length>0?i.length:e.tagName,i}(s,e,i);if(t.length>0)return t;if(!n)return[]}if(n){const t=100*(1-i.tolerance),e=[];for(const r of s){if(se(r,i))continue;re(r,n)>=t&&e.push(r)}return e.length>0&&e.length,e}const r=[];for(const a of s){se(a,i)||r.push(a)}return r.length>0?r:Array.from(s)}function le(t,e,n,i=ee){if(se(t,i))return!1;if(e&&ie(t,e))return!0;if(n){const e=100*(1-i.tolerance);return re(t,n)>=e}return!0}function ce(t,e,n,i,s){const r=function(t,e,n){const i=document.querySelectorAll(t);if(0===i.length)return"no_elements";if(e)return Array.from(i).some((t=>t.tagName.toUpperCase()===e.tagName.toUpperCase()))?"text_mismatch":"tag_mismatch";return n?"size_mismatch":"no_elements"}(n,i,s),a={playlistId:t,stepId:e,failureReason:r,selector:n};fetch("https://player.saltfish.ai/element-errors",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(a)}).catch((t=>{console.warn("Failed to report element error:",t)}))}class de{constructor(){e(this,"cursor",null),e(this,"animationFrameId",null),e(this,"animationStartTime",null),e(this,"currentAnimation",null),e(this,"flashlightOverlay",null),e(this,"startX",null),e(this,"startY",null),e(this,"targetX",null),e(this,"targetY",null),e(this,"shouldShowCursor",!1),e(this,"lastCursorX",50),e(this,"lastCursorY",50),e(this,"isFirstAnimation",!0),e(this,"currentTargetElement",null),e(this,"boundScrollHandler",null),e(this,"scrollRafId",null),e(this,"scrollUpdatePending",!1),e(this,"scrollableParents",[]),e(this,"parentScrollHandlers",new Map),e(this,"selectionElement",null),e(this,"isSelectionMode",!1),e(this,"selectionPadding",4),e(this,"labelElement",null),e(this,"labelText",null),e(this,"dragStartX",null),e(this,"dragStartY",null),e(this,"dragEndX",null),e(this,"dragEndY",null),e(this,"dragPhase","move-to-start"),e(this,"dragAnimationStartTime",null),e(this,"TARGET_SPEED",350),e(this,"MIN_ANIMATION_DURATION",600),e(this,"MAX_ANIMATION_DURATION",2e3),e(this,"animationDuration",800),e(this,"totalDistance",0),e(this,"controlPointX",null),e(this,"controlPointY",null),e(this,"targetMutationObserver",null),e(this,"POINTER_HORIZONTAL_OFFSET",16),e(this,"POINTER_VERTICAL_OFFSET",16),e(this,"SELECTION_HORIZONTAL_OFFSET",8),e(this,"SELECTION_VERTICAL_OFFSET",8),e(this,"animationUtils",{validateAnimationState:()=>!this.isAutoplayBlocked()||(this.stopAnimation(),!1),calculateEasedProgress:(t,e)=>{const n=e>0?t/e:1,i=Math.min(n,1);return.5-.5*Math.cos(i*Math.PI)},calculateBezierPoint:(t,e,n,i)=>{const s=1-t;return{x:Math.pow(s,2)*e.x+2*s*t*n.x+Math.pow(t,2)*i.x,y:Math.pow(s,2)*e.y+2*s*t*n.y+Math.pow(t,2)*i.y}},hasSignificantPositionChange:(t,e,n=10)=>{const i=Math.abs(e.x-t.x),s=Math.abs(e.y-t.y);return i>n||s>n}})}getPaddingFromStyles(t){return"number"==typeof(null==t?void 0:t.padding)?t.padding:(null==t?void 0:t.padding)?parseInt(t.padding,10):this.selectionPadding}calculateDistance(t,e,n,i){return Math.sqrt(Math.pow(n-t,2)+Math.pow(i-e,2))}calculateAnimationDuration(t){const e=t/(this.TARGET_SPEED/1e3);return Math.min(Math.max(e,this.MIN_ANIMATION_DURATION),this.MAX_ANIMATION_DURATION)}getCurrentCursorPosition(){return{x:this.lastCursorX,y:this.lastCursorY}}canShowCursor(){return this.shouldShowCursor&&!this.isAutoplayBlocked()}waitForScrollComplete(t,e,n=1e3){let i=null;const s=()=>{null!==i&&clearTimeout(i),i=window.setTimeout((()=>{t.removeEventListener("scroll",s),e()}),100)};t.addEventListener("scroll",s),setTimeout((()=>{t.removeEventListener("scroll",s),null!==i&&clearTimeout(i),e()}),n)}waitForElement(t,e,n,i){this.targetMutationObserver&&(this.targetMutationObserver.disconnect(),this.targetMutationObserver=null);let s=0,r=null,a=!1;const o=()=>{var e;if(a)return;a=!0;const s=yt.getState(),r=null==(e=s.manifest)?void 0:e.id,o=s.currentStepId;r&&o&&ce(r,o,t,n,i)},l=()=>{this.targetMutationObserver&&(this.targetMutationObserver.disconnect(),this.targetMutationObserver=null),null!==r&&(clearInterval(r),r=null)},c=async()=>(s++,s>10?(console.warn(`CursorManager: Stopped waiting for element '${t}' after 10 attempts`),o(),l(),null):this.findElementAndScrollIntoView(t,n,i));this.targetMutationObserver=new MutationObserver((async()=>{if(this.isAutoplayBlocked())return void l();const t=await c();t&&(l(),e(t))})),this.targetMutationObserver.observe(document.body,{childList:!0,subtree:!0}),r=setInterval((()=>{if(!this.targetMutationObserver||this.isAutoplayBlocked())return void l();if(s++,s>10)return console.warn(`CursorManager: Stopped waiting for element '${t}' after 10 attempts`),o(),void l();const r=this.findElement(t,n,i);r&&(l(),e(r))}),1e3)}findScrollableParents(t){const e=[];let n=t.parentElement;for(;n&&n!==document.body;){const t=window.getComputedStyle(n),i=t.overflow,s=t.overflowX,r=t.overflowY;"scroll"!==i&&"auto"!==i&&"scroll"!==s&&"auto"!==s&&"scroll"!==r&&"auto"!==r||(n.scrollHeight>n.clientHeight||n.scrollWidth>n.clientWidth)&&e.push(n),n=n.parentElement}return e}addScrollListenersToParents(t){this.removeScrollListenersFromParents(),this.scrollableParents=this.findScrollableParents(t),this.scrollableParents.forEach((t=>{const e=this.handleScroll.bind(this);this.parentScrollHandlers.set(t,e),t.addEventListener("scroll",e,{passive:!0})}))}removeScrollListenersFromParents(){this.parentScrollHandlers.forEach(((t,e)=>{e.removeEventListener("scroll",t)})),this.parentScrollHandlers.clear(),this.scrollableParents=[]}findElement(t,e,n){if(e||n){const i=ae(t,e,n);return i||null}const i=document.querySelectorAll(t);if(0===i.length)return null;if(1===i.length)return i[0];for(const l of i)if(this.isElementInViewport(l))return l.getBoundingClientRect(),l;const s=window.innerWidth/2,r=window.innerHeight/2;let a=i[0],o=1/0;for(const l of i){const t=l.getBoundingClientRect(),e=t.left+t.width/2,n=t.top+t.height/2,i=Math.sqrt(Math.pow(e-s,2)+Math.pow(n-r,2));i<o&&(o=i,a=l)}return a.getBoundingClientRect(),a}isElementInViewport(t){const e=t.getBoundingClientRect(),n=window.innerHeight||document.documentElement.clientHeight,i=window.innerWidth||document.documentElement.clientWidth;if(!(e.top>=0&&e.bottom<=n&&e.left>=0&&e.right<=i))return!1;const s=this.findScrollableParents(t);for(const r of s){const t=r.getBoundingClientRect();if(!(e.top>=t.top&&e.bottom<=t.bottom&&e.left>=t.left&&e.right<=t.right))return!1}return!0}async scrollElementIntoView(t){return new Promise((e=>{const n=this.findScrollableParents(t),i=t.getBoundingClientRect(),s=window.innerHeight||document.documentElement.clientHeight,r=i.height>s?"start":"center";0===n.length?(t.scrollIntoView({behavior:"smooth",block:r,inline:"center"}),this.waitForScrollComplete(window,e)):this.scrollParentContainersToShowElement(t,n).then((()=>{this.isElementInViewport(t)||t.scrollIntoView({behavior:"smooth",block:r,inline:"center"}),setTimeout((()=>{e()}),200)}))}))}async scrollParentContainersToShowElement(t,e){return new Promise((n=>{let i=0;const s=e.length;if(0===s)return void n();const r=()=>{i++,i>=s&&n()};e.forEach((e=>{const n=t.getBoundingClientRect(),i=e.getBoundingClientRect(),s=e.scrollTop,a=e.scrollLeft;let o;o=n.height>i.height?s+(n.top-i.top):s+(n.top-i.top)-i.height/2+n.height/2;const l=a+(n.left-i.left)-i.width/2+n.width/2;e.scrollTo({top:Math.max(0,o),left:Math.max(0,l),behavior:"smooth"}),this.waitForScrollComplete(e,r,800)}))}))}async findElementAndScrollIntoView(t,e,n){const i=this.findElement(t,e,n);return i?(this.isElementInViewport(i)||await this.scrollElementIntoView(i),i):null}cleanupExistingElements(){document.querySelectorAll(".sf-cursor").forEach((t=>t.remove()));document.querySelectorAll(".sf-cursor-label").forEach((t=>t.remove()));document.querySelectorAll(".sf-selection").forEach((t=>t.remove()));document.querySelectorAll(".sf-flashlight-overlay").forEach((t=>t.remove())),this.cursor=null,this.labelElement=null,this.selectionElement=null,this.flashlightOverlay=null}create(){this.cleanupExistingElements(),this.injectCursorStyles(),this.cursor=document.createElement("div"),this.cursor.className="sf-cursor",this.cursor.innerHTML='\n <svg xmlns="http://www.w3.org/2000/svg" width="40" height="40" viewBox="0 0 24 24" fill="none">\n <defs>\n <filter id="cursor-shadow" x="-50%" y="-50%" width="200%" height="200%">\n <feDropShadow dx="0" dy="1" stdDeviation="1.2" flood-color="rgba(0, 0, 0, 0.22)"/>\n </filter>\n </defs>\n <path d="M3.5 3.5L10.5 20.5L13.3 13.3L20.5 10.5L3.5 3.5Z" fill="#ff7614" stroke="white" stroke-width="0.7" stroke-linejoin="round" stroke-linecap="round" filter="url(#cursor-shadow)" />\n </svg>\n ',this.labelElement=document.createElement("div"),this.labelElement.className="sf-cursor-label",this.selectionElement=document.createElement("div"),this.selectionElement.className="sf-selection",document.body.appendChild(this.cursor),document.body.appendChild(this.labelElement),document.body.appendChild(this.selectionElement),this.flashlightOverlay=document.createElement("div"),this.flashlightOverlay.className="sf-flashlight-overlay",document.body.appendChild(this.flashlightOverlay),this.boundScrollHandler=this.handleScroll.bind(this),window.addEventListener("scroll",this.boundScrollHandler,{passive:!0}),this.lastCursorX=window.innerWidth-50,this.lastCursorY=window.innerHeight-50}injectCursorStyles(){const t="\n .sf-cursor {\n position: fixed;\n top: 0;\n left: 0;\n width: 40px;\n height: 40px;\n z-index: 9999999;\n pointer-events: none;\n display: none;\n will-change: transform;\n transform: var(--sf-cursor-transform, translate(0, 0));\n opacity: var(--sf-cursor-opacity, 1);\n /* Defensive styles to prevent host page CSS interference */\n margin: 0;\n padding: 0;\n border: 0;\n box-sizing: content-box;\n line-height: 0;\n font-size: 0;\n vertical-align: baseline;\n overflow: visible;\n }\n\n .sf-cursor--visible {\n display: block;\n }\n\n .sf-cursor svg {\n display: block;\n width: 100%;\n height: 100%;\n margin: 0;\n padding: 0;\n border: 0;\n }\n\n .sf-selection {\n position: fixed;\n pointer-events: none;\n display: none;\n z-index: 9999998;\n top: 0;\n left: 0;\n border: 2px solid var(--sf-selection-color, #ff7614);\n background: var(--sf-selection-bg-color, rgba(255, 118, 20, 0));\n border-radius: 4px;\n width: var(--sf-selection-width, 0);\n height: var(--sf-selection-height, 0);\n transform: var(--sf-selection-transform, translate(0, 0));\n will-change: transform;\n box-sizing: border-box;\n }\n\n .sf-selection--visible {\n display: block;\n }\n\n .sf-flashlight-overlay {\n position: fixed;\n top: 0;\n left: 0;\n width: 100vw;\n height: 100vh;\n pointer-events: none;\n z-index: 9999997;\n display: none;\n background: var(--sf-flashlight-bg, radial-gradient(circle 150px at 50% 50%, transparent 0%, rgba(0, 0, 0, 0.4) 100%));\n clip-path: var(--sf-flashlight-clip, none);\n }\n\n .sf-flashlight-overlay--visible {\n display: block;\n }\n\n .sf-cursor-label {\n position: fixed;\n top: 0;\n left: 0;\n z-index: 9999999;\n pointer-events: none;\n display: none;\n will-change: transform;\n transform: var(--sf-cursor-label-transform, translate(0, 0));\n opacity: var(--sf-cursor-opacity, 1);\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif;\n font-size: 13px;\n font-weight: 500;\n color: var(--sf-cursor-label-text, #fff);\n background: var(--sf-cursor-label-bg, #ff7614);\n padding: 4px 10px;\n border-radius: 12px;\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);\n white-space: nowrap;\n margin: 0;\n border: 0;\n box-sizing: border-box;\n line-height: 1.4;\n }\n\n .sf-cursor-label--visible {\n display: block;\n }\n ";try{const e=new CSSStyleSheet;e.replaceSync(t),document.adoptedStyleSheets=[...document.adoptedStyleSheets,e]}catch(e){const n=document.createElement("style");n.textContent=t,document.head.appendChild(n)}}handleScroll(){!this.isAutoplayBlocked()&&this.shouldShowCursor&&this.currentTargetElement&&(null!==this.animationFrameId||this.scrollUpdatePending||(this.scrollUpdatePending=!0,this.scrollRafId=requestAnimationFrame((()=>{this.updateCursorPositionOnScroll(),this.scrollUpdatePending=!1,this.scrollRafId=null}))))}updateCursorPositionOnScroll(){var t,e;if(!this.currentTargetElement)return;const n=this.currentTargetElement.getBoundingClientRect();let i,s;if(this.isSelectionMode){const e=this.getPaddingFromStyles(null==(t=this.currentAnimation)?void 0:t.selectionStyles);i=n.right+e+this.SELECTION_HORIZONTAL_OFFSET,s=n.bottom+e+this.SELECTION_VERTICAL_OFFSET}else i=n.left+n.width/2+this.POINTER_HORIZONTAL_OFFSET,s=n.top+n.height/2+this.POINTER_VERTICAL_OFFSET;if(this.show(i,s),this.lastCursorX=i,this.lastCursorY=s,this.selectionElement&&this.isSelectionMode){const t=this.getPaddingFromStyles(null==(e=this.currentAnimation)?void 0:e.selectionStyles),i=Math.floor(n.left-t),s=Math.floor(n.top-t),r=Math.ceil(n.width+2*t),a=Math.ceil(n.height+2*t);this.selectionElement.style.setProperty("--sf-selection-transform",`translate(${i}px, ${s}px)`),this.selectionElement.style.setProperty("--sf-selection-width",`${r}px`),this.selectionElement.style.setProperty("--sf-selection-height",`${a}px`),this.dragStartX=i,this.dragStartY=s,this.dragEndX=i+r,this.dragEndY=s+a,this.updateFlashlightWithCutout(i,s,r,a)}}isAutoplayBlocked(){return"autoplayBlocked"===yt.getState().currentState}setShouldShowCursor(t){if(this.isAutoplayBlocked())return this.shouldShowCursor=!1,void this.hideCursorElements();this.shouldShowCursor=t,t?this.isFirstAnimation||this.show(this.lastCursorX,this.lastCursorY):this.hideCursorElements()}show(t,e){this.canShowCursor()&&(this.lastCursorX=t,this.lastCursorY=e,this.cursor&&(this.cursor.classList.add("sf-cursor--visible"),this.cursor.style.setProperty("--sf-cursor-transform",`translate(${t}px, ${e}px) translate(-50%, -50%)`)),this.labelElement&&this.labelText&&(this.labelElement.classList.add("sf-cursor-label--visible"),this.labelElement.style.setProperty("--sf-cursor-label-transform",`translate(${t+24}px, ${e+8}px)`)),this.flashlightOverlay&&(this.flashlightOverlay.classList.add("sf-flashlight-overlay--visible"),this.flashlightOverlay.style.setProperty("--sf-flashlight-bg",`radial-gradient(circle 150px at ${t}px ${e}px, transparent 0%, rgba(0, 0, 0, 0.4) 100%)`)))}hideCursorElements(){this.cursor&&this.cursor.classList.remove("sf-cursor--visible"),this.labelElement&&this.labelElement.classList.remove("sf-cursor-label--visible"),this.selectionElement&&this.selectionElement.classList.remove("sf-selection--visible"),this.flashlightOverlay&&(this.flashlightOverlay.classList.remove("sf-flashlight-overlay--visible"),this.resetFlashlightOverlay())}resetFlashlightOverlay(){if(!this.flashlightOverlay)return;this.flashlightOverlay.style.setProperty("--sf-flashlight-clip","none");const t=this.lastCursorX,e=this.lastCursorY;this.flashlightOverlay.style.setProperty("--sf-flashlight-bg",`radial-gradient(circle 150px at ${t}px ${e}px, transparent 0%, rgba(0, 0, 0, 0.4) 100%)`)}async animate(t){if(this.isAutoplayBlocked())return;if(this.stopAnimation(),this.removeScrollListenersFromParents(),this.currentTargetElement=null,this.isSelectionMode=!1,this.resetFlashlightOverlay(),this.selectionElement&&this.selectionElement.classList.remove("sf-selection--visible"),!(null==t?void 0:t.targetSelector))return void console.warn("CursorManager: No targetSelector provided in animation");if(await new Promise((t=>setTimeout(t,_t))),this.isAutoplayBlocked())return;const e=await this.findElementAndScrollIntoView(t.targetSelector,t.expectedElement,t.expectedSize);if(!e)return console.warn("CursorManager: Target element not found in animate:",t.targetSelector),this.setShouldShowCursor(!1),this.hideCursorElements(),void this.waitForElement(t.targetSelector,(()=>this.animate(t)),t.expectedElement,t.expectedSize);this.setShouldShowCursor(!0),this.currentTargetElement=e,this.addScrollListenersToParents(e);const n=e.getBoundingClientRect();this.isFirstAnimation?(this.startX=window.innerWidth-50,this.startY=window.innerHeight-50,this.isFirstAnimation=!1):(this.startX=this.lastCursorX,this.startY=this.lastCursorY);const i={...t,mode:t.mode||"selection"};if(this.isSelectionMode="selection"===i.mode,this.isSelectionMode)return void this.handleSelectionMode(i,n);this.targetX=n.left+n.width/2+this.POINTER_HORIZONTAL_OFFSET,this.targetY=n.top+n.height/2+this.POINTER_VERTICAL_OFFSET,this.selectionElement&&this.selectionElement.classList.remove("sf-selection--visible"),null!==this.targetX&&null!==this.targetY&&null!==this.startX&&null!==this.startY?(this.totalDistance=this.calculateDistance(this.startX,this.startY,this.targetX,this.targetY),this.animationDuration=this.calculateAnimationDuration(this.totalDistance)):(this.totalDistance=100,this.animationDuration=this.MIN_ANIMATION_DURATION),this.calculateControlPoint(),this.currentAnimation={...i};const s=null!==this.startX?this.startX:0,r=null!==this.startY?this.startY:0;this.show(s,r),this.animationStartTime=performance.now(),this.animationFrameId=requestAnimationFrame(this.unifiedAnimationFrame.bind(this))}handleSelectionMode(t,e){const n=this.getPaddingFromStyles(t.selectionStyles);this.dragStartX=Math.floor(e.left-n),this.dragStartY=Math.floor(e.top-n),this.dragEndX=Math.ceil(e.right+n),this.dragEndY=Math.ceil(e.bottom+n),this.dragPhase="move-to-start",this.targetX=this.dragStartX+this.SELECTION_HORIZONTAL_OFFSET,this.targetY=this.dragStartY+this.SELECTION_VERTICAL_OFFSET,null!==this.targetX&&null!==this.targetY&&null!==this.startX&&null!==this.startY?(this.totalDistance=this.calculateDistance(this.startX,this.startY,this.targetX,this.targetY),this.animationDuration=this.calculateAnimationDuration(this.totalDistance)):(this.totalDistance=100,this.animationDuration=this.MIN_ANIMATION_DURATION),this.selectionElement&&(t.selectionStyles&&(t.selectionStyles.borderColor&&this.selectionElement.style.setProperty("--sf-selection-border-color",t.selectionStyles.borderColor),t.selectionStyles.borderWidth&&this.selectionElement.style.setProperty("--sf-selection-border-width",t.selectionStyles.borderWidth),t.selectionStyles.borderRadius&&this.selectionElement.style.setProperty("--sf-selection-border-radius",t.selectionStyles.borderRadius)),this.selectionElement.classList.remove("sf-selection--visible")),this.calculateControlPoint(),this.currentAnimation={...t};const i=null!==this.startX?this.startX:0,s=null!==this.startY?this.startY:0;this.show(i,s),this.animationStartTime=performance.now(),this.animationFrameId=requestAnimationFrame(this.unifiedAnimationFrame.bind(this))}updateDragCoordinatesFromElement(){var t;if(!this.currentTargetElement)return;const e=this.currentTargetElement.getBoundingClientRect(),n=this.getPaddingFromStyles(null==(t=this.currentAnimation)?void 0:t.selectionStyles);this.dragStartX=Math.floor(e.left-n),this.dragStartY=Math.floor(e.top-n),this.dragEndX=Math.ceil(e.right+n),this.dragEndY=Math.ceil(e.bottom+n)}updateSelectionRectangle(t,e){if(!this.selectionElement)return;const n=Math.ceil(Math.abs(t-this.SELECTION_HORIZONTAL_OFFSET-this.dragStartX)),i=Math.ceil(Math.abs(e-this.SELECTION_VERTICAL_OFFSET-this.dragStartY)),s=Math.floor(Math.min(this.dragStartX,t-this.SELECTION_HORIZONTAL_OFFSET)),r=Math.floor(Math.min(this.dragStartY,e-this.SELECTION_VERTICAL_OFFSET));this.selectionElement.style.setProperty("--sf-selection-transform",`translate(${s}px, ${r}px)`),this.selectionElement.style.setProperty("--sf-selection-width",`${n}px`),this.selectionElement.style.setProperty("--sf-selection-height",`${i}px`),this.selectionElement.classList.add("sf-selection--visible"),this.updateFlashlightWithCutout(s,r,n,i)}validatePointerState(){return null!==this.animationStartTime&&null!==this.currentAnimation&&null!==this.startX&&null!==this.startY&&null!==this.targetX&&null!==this.targetY&&null!==this.controlPointX&&null!==this.controlPointY}validateSelectionState(){return!(!this.animationStartTime||!this.currentAnimation)&&("move-to-start"===this.dragPhase?null!==this.startX&&null!==this.startY&&null!==this.targetX&&null!==this.targetY&&null!==this.controlPointX&&null!==this.controlPointY:"dragging"!==this.dragPhase||null!==this.dragAnimationStartTime&&null!==this.dragStartX&&null!==this.dragStartY&&null!==this.dragEndX&&null!==this.dragEndY)}completePointerAnimation(){this.show(this.targetX,this.targetY),this.lastCursorX=this.targetX,this.lastCursorY=this.targetY,this.click(),setTimeout((()=>{this.stopAnimation()}),400)}completeMoveToStartPhase(){this.show(this.targetX,this.targetY),this.lastCursorX=this.targetX,this.lastCursorY=this.targetY,this.dragPhase="dragging",this.dragAnimationStartTime=performance.now();const t=this.calculateDistance(this.dragStartX+this.SELECTION_HORIZONTAL_OFFSET,this.dragStartY+this.SELECTION_VERTICAL_OFFSET,this.dragEndX+this.SELECTION_HORIZONTAL_OFFSET,this.dragEndY+this.SELECTION_VERTICAL_OFFSET);if(this.animationDuration=this.calculateAnimationDuration(t),this.cursor){const t=this.lastCursorX,e=this.lastCursorY;this.cursor.style.setProperty("--sf-cursor-transform",`translate(${t}px, ${e}px) translate(-50%, -50%) scale(0.9)`),this.cursor.style.setProperty("--sf-cursor-opacity","0.9")}this.selectionElement&&(this.selectionElement.style.setProperty("--sf-selection-transform",`translate(${this.dragStartX}px, ${this.dragStartY}px)`),this.selectionElement.style.setProperty("--sf-selection-width","0px"),this.selectionElement.style.setProperty("--sf-selection-height","0px"),this.selectionElement.classList.add("sf-selection--visible"))}completeDraggingPhase(){if(this.dragPhase="release",this.cursor){const t=this.lastCursorX,e=this.lastCursorY;this.cursor.style.setProperty("--sf-cursor-transform",`translate(${t}px, ${e}px) translate(-50%, -50%)`),this.cursor.style.setProperty("--sf-cursor-opacity","1")}null!==this.animationFrameId&&(cancelAnimationFrame(this.animationFrameId),this.animationFrameId=null),this.animationStartTime=null,this.dragAnimationStartTime=null}handleMoveToStartPhase(t){if(this.currentTargetElement){this.updateDragCoordinatesFromElement();const e={x:this.targetX,y:this.targetY};this.targetX=this.dragStartX+this.SELECTION_HORIZONTAL_OFFSET,this.targetY=this.dragStartY+this.SELECTION_VERTICAL_OFFSET;if(this.animationUtils.hasSignificantPositionChange(e,{x:this.targetX,y:this.targetY})){const e=this.getCurrentCursorPosition();this.startX=e.x,this.startY=e.y,this.calculateControlPoint(),this.totalDistance=this.calculateDistance(this.startX,this.startY,this.targetX,this.targetY),this.animationDuration=this.calculateAnimationDuration(this.totalDistance),this.animationStartTime=t}}const e=t-this.animationStartTime;if(e>=this.animationDuration)return void this.completeMoveToStartPhase();const n=this.animationUtils.calculateEasedProgress(e,this.animationDuration),i=this.animationUtils.calculateBezierPoint(n,{x:this.startX,y:this.startY},{x:this.controlPointX,y:this.controlPointY},{x:this.targetX,y:this.targetY});this.show(i.x,i.y)}handleDraggingPhase(t){this.currentTargetElement&&this.updateDragCoordinatesFromElement();const e=t-this.dragAnimationStartTime,n=Math.min(e/this.animationDuration,1),i=.5-.5*Math.cos(n*Math.PI),s=this.dragStartX+(this.dragEndX-this.dragStartX)*i+this.SELECTION_HORIZONTAL_OFFSET,r=this.dragStartY+(this.dragEndY-this.dragStartY)*i+this.SELECTION_VERTICAL_OFFSET;this.show(s,r),this.updateSelectionRectangle(s,r),n>=1&&this.completeDraggingPhase()}handlePointerAnimation(t){if(!this.validatePointerState())return console.warn("CursorManager: Animation frame missing essential data"),void this.stopAnimation();const e=t-this.animationStartTime;if(this.currentTargetElement){const e=this.currentTargetElement.getBoundingClientRect(),n={x:this.targetX,y:this.targetY};if(this.targetX=e.left+e.width/2+this.POINTER_HORIZONTAL_OFFSET,this.targetY=e.top+e.height/2+this.POINTER_VERTICAL_OFFSET,this.animationUtils.hasSignificantPositionChange(n,{x:this.targetX,y:this.targetY})){const e=this.getCurrentCursorPosition();this.startX=e.x,this.startY=e.y,this.calculateControlPoint(),this.totalDistance=this.calculateDistance(this.startX,this.startY,this.targetX,this.targetY),this.animationDuration=this.calculateAnimationDuration(this.totalDistance),this.animationStartTime=t}}if(e>=this.animationDuration)return void this.completePointerAnimation();const n=this.animationUtils.calculateEasedProgress(e,this.animationDuration),i=this.animationUtils.calculateBezierPoint(n,{x:this.startX,y:this.startY},{x:this.controlPointX,y:this.controlPointY},{x:this.targetX,y:this.targetY});this.show(i.x,i.y),this.animationFrameId=requestAnimationFrame(this.unifiedAnimationFrame.bind(this))}handleSelectionAnimation(t){if(this.validateSelectionState()){switch(this.dragPhase){case"move-to-start":this.handleMoveToStartPhase(t);break;case"dragging":this.handleDraggingPhase(t)}"release"!==this.dragPhase&&(this.animationFrameId=requestAnimationFrame(this.unifiedAnimationFrame.bind(this)))}else this.stopAnimation()}unifiedAnimationFrame(t){this.animationUtils.validateAnimationState()&&(this.isSelectionMode?this.handleSelectionAnimation(t):this.handlePointerAnimation(t))}updateFlashlightWithCutout(t,e,n,i){if(!this.flashlightOverlay)return;const s=window.innerWidth,r=window.innerHeight,a=`path(evenodd, "M 0 0 L ${s} 0 L ${s} ${r} L 0 ${r} Z M ${t+4} ${e} L ${t+n-4} ${e} A 4 4 0 0 1 ${t+n} ${e+4} L ${t+n} ${e+i-4} A 4 4 0 0 1 ${t+n-4} ${e+i} L ${t+4} ${e+i} A 4 4 0 0 1 ${t} ${e+i-4} L ${t} ${e+4} A 4 4 0 0 1 ${t+4} ${e} Z")`;this.flashlightOverlay.style.setProperty("--sf-flashlight-clip",a);const o=this.lastCursorX,l=this.lastCursorY;this.flashlightOverlay.style.setProperty("--sf-flashlight-bg",`radial-gradient(circle 150px at ${o}px ${l}px, transparent 0%, rgba(0, 0, 0, 0.4) 100%)`)}calculateControlPoint(){if(!(this.startX&&this.startY&&this.targetX&&this.targetY))return void console.warn("CursorManager: Missing start or target position for control point calculation",{startX:this.startX,startY:this.startY,targetX:this.targetX,targetY:this.targetY});const t=(this.startX+this.targetX)/2,e=(this.startY+this.targetY)/2,n=Math.sqrt(Math.pow(this.targetX-this.startX,2)+Math.pow(this.targetY-this.startY,2));this.totalDistance=n;const i=.2*n,s=(Math.random()-.5)*i*2,r=this.targetX-this.startX,a=-(this.targetY-this.startY),o=r,l=Math.sqrt(a*a+o*o);if(0===l)this.controlPointX=t+5,this.controlPointY=e+5;else{const n=a/l,i=o/l;this.controlPointX=t+n*s,this.controlPointY=e+i*s}}async moveToElement(t,e,n){if(!this.canShowCursor())return;if(this.stopAnimation(),this.removeScrollListenersFromParents(),this.currentTargetElement=null,this.isSelectionMode=!1,this.resetFlashlightOverlay(),this.isAutoplayBlocked())return;const i=await this.findElementAndScrollIntoView(t);if(!i)return console.warn("CursorManager: Target element not found:",t),this.setShouldShowCursor(!1),this.hideCursorElements(),void this.waitForElement(t,(()=>this.moveToElement(t,e,n)));this.currentTargetElement=i,this.addScrollListenersToParents(i);const s={targetSelector:t,mode:e||"selection",selectionStyles:n};this.animate(s)}click(){if(this.canShowCursor()&&this.cursor){const t=this.lastCursorX,e=this.lastCursorY;this.cursor.style.setProperty("--sf-cursor-transform",`translate(${t}px, ${e}px) translate(-50%, -50%) scale(0.8)`),this.cursor.style.setProperty("--sf-cursor-opacity","0.8"),setTimeout((()=>{if(this.cursor){if(!this.canShowCursor())return void this.hideCursorElements();this.cursor.style.setProperty("--sf-cursor-transform",`translate(${t}px, ${e}px) translate(-50%, -50%)`),this.cursor.style.setProperty("--sf-cursor-opacity","1")}}),300)}}stopAnimation(){if(null!==this.animationFrameId&&(cancelAnimationFrame(this.animationFrameId),this.animationFrameId=null),this.animationStartTime=null,this.currentAnimation=null,this.controlPointX=null,this.controlPointY=null,this.dragPhase="move-to-start",this.dragAnimationStartTime=null,this.cursor){const t=this.lastCursorX,e=this.lastCursorY;this.cursor.style.setProperty("--sf-cursor-transform",`translate(${t}px, ${e}px) translate(-50%, -50%)`),this.cursor.style.setProperty("--sf-cursor-opacity","1")}this.resetFlashlightOverlay(),this.selectionElement&&this.selectionElement.classList.remove("sf-selection--visible")}resetFirstAnimation(){this.isFirstAnimation=!0}reset(){this.stopAnimation(),this.currentAnimation=null,this.animationStartTime=null,this.startX=null,this.startY=null,this.targetX=null,this.targetY=null,this.currentTargetElement=null,this.isFirstAnimation=!0,this.shouldShowCursor=!1,this.cursor&&this.cursor.classList.remove("sf-cursor--visible"),this.isSelectionMode=!1,this.selectionElement&&this.selectionElement.classList.remove("sf-selection--visible"),this.dragStartX=null,this.dragStartY=null,this.dragEndX=null,this.dragEndY=null,this.dragPhase="move-to-start",this.dragAnimationStartTime=null,null!==this.scrollRafId&&(cancelAnimationFrame(this.scrollRafId),this.scrollRafId=null),this.scrollUpdatePending=!1,this.removeScrollListenersFromParents(),this.scrollableParents=[]}async destroy(){this.stopAnimation(),this.boundScrollHandler&&(window.removeEventListener("scroll",this.boundScrollHandler),this.boundScrollHandler=null),this.removeScrollListenersFromParents(),null!==this.scrollRafId&&(cancelAnimationFrame(this.scrollRafId),this.scrollRafId=null),this.scrollUpdatePending=!1,this.cursor&&this.cursor.parentNode&&(this.cursor.remove(),this.cursor=null),this.labelElement&&this.labelElement.parentNode&&(this.labelElement.remove(),this.labelElement=null),this.labelText=null,this.selectionElement&&this.selectionElement.parentNode&&(this.selectionElement.remove(),this.selectionElement=null),this.flashlightOverlay&&this.flashlightOverlay.parentNode&&(this.flashlightOverlay.remove(),this.flashlightOverlay=null),this.isFirstAnimation=!0,this.shouldShowCursor=!1,this.currentTargetElement=null,this.isSelectionMode=!1,this.targetMutationObserver&&(this.targetMutationObserver.disconnect(),this.targetMutationObserver=null),document.documentElement.style.removeProperty("--sf-cursor-x"),document.documentElement.style.removeProperty("--sf-cursor-y")}setColor(t){if(this.cursor){const e=this.cursor.querySelector("svg");if(e){const n=e.querySelector("path");n?n.setAttribute("fill",t):console.warn("[CursorManager.setColor] No path found in SVG")}else console.warn("[CursorManager.setColor] No SVG found in cursor")}else console.warn("[CursorManager.setColor] No cursor element");if(this.selectionElement){this.selectionElement.style.setProperty("--sf-selection-color",t);const e=this.colorToRgba(t,0);this.selectionElement.style.setProperty("--sf-selection-bg-color",e)}if(this.labelElement){this.labelElement.style.setProperty("--sf-cursor-label-bg",t);const e=this.getContrastingTextColor(t);this.labelElement.style.setProperty("--sf-cursor-label-text",e)}}getContrastingTextColor(t){const e=this.parseColorToRgb(t);if(!e)return"#fff";return(299*e.r+587*e.g+114*e.b)/1e3>150?"#333":"#fff"}parseColorToRgb(t){const e=document.createElement("div");e.style.color=t,document.body.appendChild(e);const n=window.getComputedStyle(e).color;document.body.removeChild(e);const i=n.match(/rgba?\((\d+),\s*(\d+),\s*(\d+)/);return i?{r:parseInt(i[1],10),g:parseInt(i[2],10),b:parseInt(i[3],10)}:null}colorToRgba(t,e){const n=document.createElement("div");n.style.color=t,document.body.appendChild(n);const i=window.getComputedStyle(n).color;document.body.removeChild(n);const s=i.match(/rgba?\((\d+),\s*(\d+),\s*(\d+)/);if(s){return`rgba(${s[1]}, ${s[2]}, ${s[3]}, ${e})`}return t}setLabel(t){var e;this.labelText=t,this.labelElement&&(t?(this.labelElement.textContent=t,(null==(e=this.cursor)?void 0:e.classList.contains("sf-cursor--visible"))&&this.labelElement.classList.add("sf-cursor-label--visible")):(this.labelElement.textContent="",this.labelElement.classList.remove("sf-cursor-label--visible")))}}const he=["utm_source","utm_medium","utm_campaign","utm_term","utm_content","utm_id","gclid","gclsrc","gad_source","dclid","gbraid","wbraid","fbclid","msclkid","li_fat_id","twclid","ttclid","ref","_ga","_gl"];function ue(t){if(!t)return t;try{let e;e=t.startsWith("/")||!t.includes("://")?new URL(t,window.location.origin):new URL(t);const n=function(){const t=new Map;try{const e=new URL(window.location.href);for(const n of he){const i=e.searchParams.get(n);null!==i&&t.set(n,i)}t.size>0&&(t.size,Array.from(t.keys()).join(", "))}catch(e){}return t}();if(0===n.size)return t;let i=0;for(const[t,s]of n)e.searchParams.has(t)||(e.searchParams.set(t,s),i++);return i>0?e.toString():t}catch(e){return t}}class pe{constructor(){e(this,"container",null),e(this,"buttons",[]),e(this,"buttonContainer",null),e(this,"scrollIndicator",null),e(this,"storeUnsubscribe",null),e(this,"storageManager",gt.getInstance()),e(this,"handleVideo90PercentReached",(t=>{this.showButtonsAt90Percent()}))}create(t){this.container=t,this.storeUnsubscribe=vt.subscribe(((t,e)=>{t.isMinimized!==(null==e?void 0:e.isMinimized)&&this.updateButtonPositions()})),t.addEventListener("video90PercentReached",this.handleVideo90PercentReached)}createButtons(t){if(!this.container)return;this.clearButtons(),this.buttonContainer=document.createElement("div");const e=t.length>4;let n="sf-choice-buttons-container";e&&(n+=" sf-choice-buttons-container--scrollable"),this.buttonContainer.className=n,t.length,this.updateCenterPlayButtonPosition(t.length),this.container.appendChild(this.buttonContainer),e&&(this.scrollIndicator=document.createElement("div"),this.scrollIndicator.className="sf-scroll-indicator",this.scrollIndicator.innerHTML='\n <svg width="16" height="16" viewBox="0 0 16 16" fill="currentColor">\n <path d="M8 12l-4-4h8l-4 4z"/>\n </svg>\n ',this.container.appendChild(this.scrollIndicator)),t.forEach((t=>{const e=document.createElement("button");e.textContent=t.text,e.dataset.buttonId=t.id,e.className=`sf-choice-button sf-choice-button--${t.action.type}`,t.style&&Object.entries(t.style).forEach((([t,n])=>{e.style.setProperty(`--custom-${t}`,String(n))})),e.addEventListener("click",(async e=>{await this.handleButtonClick(e,t)})),this.buttonContainer&&(this.buttonContainer.appendChild(e),this.buttons.push(e),t.id)})),e&&this.buttonContainer&&this.setupScrollIndicator(this.buttonContainer);bt().isMinimized&&this.buttonContainer.classList.add("sf-hidden")}showButtonsAt90Percent(){this.buttons.length>0&&(this.buttons.forEach(((t,e)=>{t.classList.add("sf-show-button")})),this.scrollIndicator&&this.scrollIndicator.classList.add("sf-show-scroll-indicator"))}setupScrollIndicator(t){if(!this.scrollIndicator)return;t.addEventListener("scroll",(()=>{if(!this.scrollIndicator)return;t.scrollHeight-t.scrollTop-t.clientHeight<zt?this.scrollIndicator.classList.add("sf-scroll-indicator--hidden"):this.scrollIndicator.classList.remove("sf-scroll-indicator--hidden")}))}updateCenterPlayButtonPosition(t){if(!this.container)return;const e=this.container.querySelector(".sf-player__center-play-button");if(e)if(t>0){let n;n=t>4?176:t*36+(t-1)*8,e.style.setProperty("--sf-button-container-height",`${n}px`),e.classList.add("sf-player__center-play-button--with-buttons")}else e.style.removeProperty("--sf-button-container-height"),e.classList.remove("sf-player__center-play-button--with-buttons")}clearButtons(){this.updateCenterPlayButtonPosition(0),this.buttons.forEach((t=>{t.parentElement&&t.parentElement.removeChild(t)})),this.buttonContainer&&this.buttonContainer.parentElement&&this.buttonContainer.parentElement.removeChild(this.buttonContainer),this.scrollIndicator&&this.scrollIndicator.parentElement&&this.scrollIndicator.parentElement.removeChild(this.scrollIndicator),this.buttons=[],this.buttonContainer=null,this.scrollIndicator=null}updateButtonPositions(){if(!this.buttonContainer||0===this.buttons.length)return;if(bt().isMinimized)return this.buttonContainer.classList.add("sf-hidden"),void(this.scrollIndicator&&this.scrollIndicator.classList.add("sf-hidden"));this.buttonContainer.classList.remove("sf-hidden"),this.scrollIndicator&&this.scrollIndicator.classList.remove("sf-hidden")}async handleButtonClick(t,e){var n,i,s,r,a,o;e.id,t.preventDefault(),t.stopPropagation();const l=bt();switch(e.action.type){case"next":l.play();break;case"goto":if(e.action.url){e.action.target,e.action.url,await this.flushAnalytics();const t=bt();if(t.manifest){vt.setState((t=>{t.currentStepId=e.action.target,t.manifest&&(t.progress[t.manifest.id]={...t.progress[t.manifest.id],lastStepId:e.action.target,lastProgressAt:Date.now(),lastVisited:(new Date).toISOString()})}));try{if(e.action.target,(null==(n=t.config)?void 0:n.token)&&(null==(i=t.user)?void 0:i.id)&&!(null==(s=t.user)?void 0:s.__isAnonymous)){const n=`https://player.saltfish.ai/clients/${t.config.token}/users/${t.user.id}/playlists/${t.manifest.id}`,i=await fetch(n,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({status:"in_progress",currentStepId:e.action.target})});i.ok?e.action.target:(i.statusText,i.status)}}catch(c){console.error("InteractionManager: Full error:",c)}if((null==(r=t.playlistOptions)?void 0:r.persistence)??!0){const n=null==(a=t.user)?void 0:a.id,i=bt();if(this.storageManager.setProgress(i.progress,n),e.action.target,null==(o=t.user)?void 0:o.__isAnonymous){const n=this.storageManager.getAnonymousUserData();n&&(n.watchedPlaylists=n.watchedPlaylists||{},n.watchedPlaylists[t.manifest.id]={status:"in_progress",currentStepId:e.action.target,timestamp:Date.now(),lastProgressAt:Date.now()},this.storageManager.setAnonymousUserData(n),e.action.target)}}}const l=ue(e.action.url);window.location.href=l}else e.action.target,l.goToStep(e.action.target);break;case"url":if(e.action.target,await this.flushAnalytics(),"completedWaitingForInteraction"===l.currentState)l.completePlaylist(),await new Promise((t=>setTimeout(t,It)));else{this.isCurrentStepLast(l)&&(l.goToStep("completed"),await new Promise((t=>setTimeout(t,It))))}const t=ue(e.action.target);window.open(t,"_blank");const{SaltfishPlayer:d}=await Promise.resolve().then((()=>Ve)),h=d.getInstance();h&&h.destroy();break;case"playlist":e.action.target;try{await this.flushAnalytics(),l.completePlaylist(),await new Promise((t=>setTimeout(t,It)));const{SaltfishPlayer:t}=await Promise.resolve().then((()=>Ve)),n=t.getInstance();n&&(e.action.target,await n.startPlaylist(e.action.target))}catch(c){console.error(`InteractionManager: Error starting playlist "${e.action.target}":`,c),e.action.target}break;default:e.action.type}if(l.manifest){const t={buttonId:e.id,actionType:e.action.type,actionTarget:e.action.target};JSON.stringify(t)}}isCurrentStepLast(t){if(!t.manifest||!t.currentStepId||!t.manifest.steps)return!1;const e=t.manifest.steps;return e.findIndex((e=>e.id===t.currentStepId))===e.length-1}async flushAnalytics(){try{const{SaltfishPlayer:t}=await Promise.resolve().then((()=>Ve)),e=t.getInstance(),n=e;if(e&&n.analyticsManager){const t=n.analyticsManager;"function"==typeof t.flush&&await t.flush()}}catch(t){}}reset(){this.clearButtons(),this.buttonContainer=null,this.scrollIndicator=null,this.container&&this.container.removeEventListener("video90PercentReached",this.handleVideo90PercentReached)}destroy(){this.storeUnsubscribe&&(this.storeUnsubscribe(),this.storeUnsubscribe=null),this.container&&this.container.removeEventListener("video90PercentReached",this.handleVideo90PercentReached),this.clearButtons(),this.container=null}}class me{constructor(t){e(this,"eventManager",null),t&&this.setEventManager(t)}setEventManager(t){this.eventManager=t,this.subscribeToEvents()}}class ge extends me{constructor(t){super(t),e(this,"config",null),e(this,"user",null),e(this,"eventQueue",[]),e(this,"isSending",!1),e(this,"flushInterval",null),e(this,"sessionId",null),e(this,"analyticsEnabled",!0)}subscribeToEvents(){this.eventManager&&(this.eventManager.on("playerPaused",(t=>{const e=bt(),n=this.getRunId();(null==e?void 0:e.manifest)&&e.currentStepId&&n&&this.trackEvent({type:"playerPaused",playlistId:e.manifest.id,stepId:e.currentStepId,runId:n,timestamp:Date.now()})})),this.eventManager.on("playerResumed",(t=>{const e=bt(),n=this.getRunId();(null==e?void 0:e.manifest)&&e.currentStepId&&n&&this.trackEvent({type:"playerResumed",playlistId:e.manifest.id,stepId:e.currentStepId,runId:n,timestamp:Date.now()})})),this.eventManager.on("stepStarted",(t=>{t.step.id,this.trackStepStarted(t.playlist.id,t.step.id)})),this.eventManager.on("stepEnded",(t=>{t.step.id,this.trackStepComplete(t.playlist.id,t.step.id)})),this.eventManager.on("playlistEnded",(t=>{t.playlist.id,this.trackPlaylistComplete(t.playlist.id)})),this.eventManager.on("error",(t=>{t.playlistId&&this.trackError(t.playlistId,t.error,t.stepId,t.errorType,t.videoUrl,t.mediaErrorCode,t.mediaErrorMessage,t.failureReason)})),this.eventManager.on("playerMinimized",(t=>{const e=bt(),n=this.getRunId();(null==e?void 0:e.manifest)&&e.currentStepId&&n&&this.trackEvent({type:"playerMinimized",playlistId:e.manifest.id,stepId:e.currentStepId,runId:n,timestamp:Date.now()})})),this.eventManager.on("playerMaximized",(t=>{const e=bt(),n=this.getRunId();(null==e?void 0:e.manifest)&&e.currentStepId&&n&&this.trackEvent({type:"playerMaximized",playlistId:e.manifest.id,stepId:e.currentStepId,runId:n,timestamp:Date.now()})})))}initialize(t,e){this.config=t,this.analyticsEnabled=!1!==t.enableAnalytics,e&&(this.sessionId=e),this.analyticsEnabled&&(this.flushInterval=window.setInterval((()=>{this.flushEvents()}),Mt))}setUser(t){this.user=t}trackPlaylistStart(t){if(!this.analyticsEnabled)return;const e=this.getRunId();e&&this.trackEvent({type:"playlistStart",playlistId:t,runId:e,timestamp:Date.now()})}trackPlaylistComplete(t){if(!this.analyticsEnabled)return;const e=this.getRunId();e&&this.trackEvent({type:"playlistComplete",playlistId:t,runId:e,timestamp:Date.now()})}trackStepStarted(t,e){if(!this.analyticsEnabled)return;const n=this.getRunId();n&&this.trackEvent({type:"stepStarted",playlistId:t,stepId:e,runId:n,timestamp:Date.now()})}trackStepComplete(t,e){if(!this.analyticsEnabled)return;const n=this.getRunId();n&&this.trackEvent({type:"stepComplete",playlistId:t,stepId:e,runId:n,timestamp:Date.now()})}trackInteraction(t,e,n){if(!this.analyticsEnabled)return;const i=this.getRunId();i&&this.trackEvent({type:"interaction",playlistId:t,stepId:e,runId:i,timestamp:Date.now(),data:n})}trackError(t,e,n,i,s,r,a,o){if(!this.analyticsEnabled)return;const l=this.getRunId();l&&this.trackEvent({type:"error",playlistId:t,stepId:n,runId:l,timestamp:Date.now(),data:{message:e.message,stack:e.stack,errorType:i||"unknown",videoUrl:s||null,mediaErrorCode:r||null,mediaErrorMessage:a||null,failureReason:o||"unknown"}})}trackEvent(t){this.analyticsEnabled&&(this.eventQueue.push(t),this.eventQueue.length>=10&&this.flushEvents())}async flush(){await this.flushEvents()}async flushEvents(){if(!this.isSending&&0!==this.eventQueue.length&&this.config&&this.analyticsEnabled){this.isSending=!0;try{const t=[...this.eventQueue];this.eventQueue=[];const e={token:this.config.token,sessionId:this.sessionId,user:this.user,events:t},n=await fetch("https://player.saltfish.ai/analytics",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(e)});if(!n.ok)throw this.eventQueue=[...t,...this.eventQueue],new Error(`Failed to send analytics events: ${n.statusText}`)}catch(t){console.error("Failed to send analytics events:",t)}finally{this.isSending=!1}}}destroy(){this.analyticsEnabled&&this.flushEvents(),null!==this.flushInterval&&(clearInterval(this.flushInterval),this.flushInterval=null),this.eventManager&&(this.eventManager=null),this.config=null,this.user=null,this.eventQueue=[],this.sessionId=null,this.analyticsEnabled=!0}getRunId(){try{return Le.getInstance().getRunId()}catch(t){return null}}}class fe{constructor(t){e(this,"sessionId"),e(this,"currentRunId",null),e(this,"storageManager"),this.storageManager=t||gt.getInstance(),this.sessionId=this.getOrCreateSession(),this.sessionId}getOrCreateSession(){if("undefined"==typeof window)return this.generateUniqueId();const t=this.storageManager.getSession();if(t){if(Date.now()-t.lastActivity<Tt)return t.sessionId,this.updateSessionActivity(t.sessionId),t.sessionId}const e=this.generateUniqueId();return this.updateSessionActivity(e),e}updateSessionActivity(t){if("undefined"==typeof window)return;const e={sessionId:t,lastActivity:Date.now()};this.storageManager.setSession(e)}generateUniqueId(){return"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,(function(t){const e=16*Math.random()|0;return("x"===t?e:3&e|8).toString(16)}))}getSessionId(){return this.updateSessionActivity(this.sessionId),this.sessionId}startNewRun(){return this.currentRunId=this.generateUniqueId(),this.currentRunId,this.updateSessionActivity(this.sessionId),this.currentRunId}getCurrentRunId(){return this.currentRunId}endCurrentRun(){this.currentRunId&&(this.currentRunId,this.currentRunId=null)}expireSession(){"undefined"!=typeof window&&(this.storageManager.clearSession(),this.sessionId),this.sessionId=this.generateUniqueId(),this.updateSessionActivity(this.sessionId),this.currentRunId=null,this.sessionId}destroy(){this.updateSessionActivity(this.sessionId),this.endCurrentRun()}}class ye{constructor(){e(this,"activeTransitions",new Map),e(this,"waitingForInteraction",!1),e(this,"isStateMachineValidating",!1),e(this,"triggerManager",null),e(this,"beforeUnloadHandler",null),e(this,"handleURLChange",(()=>{if(this.isStateMachineValidating)return;const t=Array.from(this.activeTransitions.entries()).filter((([t,e])=>{var n;return"url-path"===(null==(n=e.data)?void 0:n.type)}));let e=!1;if(t.length>0)for(const[n,i]of t)if(i.data&&this.isURLPathMatch(i.data.pattern)){e=!0;break}if(!e){if(!this.validateCurrentStepUrl())return}if(this.triggerManager&&this.triggerManager.evaluateAllTriggers(),e)for(const[n,i]of t){if(!i.data)continue;const{pattern:t,nextStepId:e}=i.data;if(this.isURLPathMatch(t)){gt.getInstance().clearPendingNavigation(),this.triggerTransition(e);break}}})),window.addEventListener("popstate",this.handleURLChange),this.monitorHistoryChanges()}setTriggerManager(t){this.triggerManager=t}monitorHistoryChanges(){const t=history.pushState,e=history.replaceState;history.pushState=(...e)=>{t.apply(history,e),this.handleURLChange()},history.replaceState=(...t)=>{e.apply(history,t),this.handleURLChange()}}setupTransitions(t,e=!1,n=!1){this.cleanupTransitions(),t.id,t.transitions.forEach((t=>{switch(t.type){case"dom-click":this.setupDOMClickTransition(t);break;case"timeout":n||this.setupTimeoutTransition(t,e);break;case"url-path":this.setupURLPathTransition(t);break;case"dom-element-visible":this.setupDOMElementVisibleTransition(t);break;default:t.type}}))}setupDOMClickTransition(t){if(!t.target)return;const e=t.target,n=t.nextStep,i=`dom-click-${e}-${Date.now()}`,s=new Map;let r=null;const a=t=>{0!==t.length&&(t.length,t.forEach((t=>{if(s.has(t))return;const e=async t=>{const e=t.target;if(this.willCauseHardRefresh(e)){t.preventDefault(),t.stopImmediatePropagation();await this.triggerTransitionWithProgress(n)&&this.reDispatchClick(t)}else this.triggerTransition(n)};s.set(t,e),t.addEventListener("click",e,{capture:!0})})))},o=t.expectedElement||t.expectedSize?oe(e,t.expectedElement,t.expectedSize):Array.from(document.querySelectorAll(e));a(o),r=new MutationObserver((n=>{for(const i of n)"childList"===i.type&&i.addedNodes.forEach((n=>{if(n.nodeType===Node.ELEMENT_NODE){const i=n;i.matches(e)&&(!t.expectedElement&&!t.expectedSize||le(i,t.expectedElement,t.expectedSize))&&a([i]);const s=i.querySelectorAll(e);if(s.length>0){const e=t.expectedElement||t.expectedSize?Array.from(s).filter((e=>le(e,t.expectedElement,t.expectedSize))):Array.from(s);e.length>0&&(e.length,a(e))}}}))})),r.observe(document.body,{childList:!0,subtree:!0}),this.activeTransitions.set(i,{handlers:s,cleanup:()=>{s.forEach(((t,e)=>{e.removeEventListener("click",t,{capture:!0})})),s.clear(),r&&(r.disconnect(),r=null)},data:{type:"dom-click",pattern:e,nextStepId:n}})}setupTimeoutTransition(t,e){const n=t.nextStep,i=t.timeout||0,s=`timeout-${i}-${Date.now()}`;let r=null;e?this.triggerTransition(n):r=window.setTimeout((()=>{this.triggerTransition(n)}),i),this.activeTransitions.set(s,{handlers:new Map,cleanup:()=>{null!==r&&(clearTimeout(r),r=null)},data:{type:"timeout",pattern:"",nextStepId:n}})}setupURLPathTransition(t){if(!t.target)return;const e=t.target,n=t.nextStep;this.savePendingNavigation(e,n),this.setupBeforeUnloadHandler(e,n);if(this.isURLPathMatch(e)){this.triggerTransition(n);const t=5;let e=0;const i=()=>{if(e>=t)return;e++;const s=bt();"waitingForInteraction"===s.currentState||"playing"===s.currentState?(s.currentState,this.triggerTransition(n)):e<t&&(s.currentState,setTimeout(i,Ct))};setTimeout(i,Ct)}const i=`url-path-${Date.now()}`,s=window.setInterval((()=>{this.isURLPathMatch(e)&&(clearInterval(s),gt.getInstance().clearPendingNavigation(),this.triggerTransition(n))}),kt);this.activeTransitions.set(i,{handlers:new Map,cleanup:()=>{clearInterval(s)},data:{type:"url-path",pattern:e,nextStepId:n}})}savePendingNavigation(t,e){const n=bt();if(!n.manifest)return;gt.getInstance().setPendingNavigation({playlistId:n.manifest.id,nextStepId:e,urlPattern:t,timestamp:Date.now()})}setupBeforeUnloadHandler(t,e){this.removeBeforeUnloadHandler(),this.beforeUnloadHandler=()=>{this.savePendingNavigation(t,e)},window.addEventListener("beforeunload",this.beforeUnloadHandler)}removeBeforeUnloadHandler(){this.beforeUnloadHandler&&(window.removeEventListener("beforeunload",this.beforeUnloadHandler),this.beforeUnloadHandler=null)}isURLPathMatch(t){if(!t)return!1;const e=window.location.href,n=window.location.pathname,i=t.replace(/[.*+?^${}()|[\]\\]/g,"\\$&").replace(/\\\*/g,".*"),s=new RegExp(i),r=s.test(e),a=s.test(n);return r||a}handleUrlRequirementFailure(t,e){e.pattern,e.matchType,this.cleanupTransitions();const n=window._saltfishPlayer;n&&"function"==typeof n.destroy&&n.destroy()}validateCurrentStepUrl(){const t=bt(),e=t.manifest,n=t.currentStepId;if(!e||!n)return!0;const i=e.steps.find((t=>t.id===n));if(!i||!i.urlRequirement)return!0;const s=Bt(i.urlRequirement);return s||this.handleUrlRequirementFailure(n,i.urlRequirement),s}triggerTransition(t){var e;const n=bt(),i=n.currentState;n.currentStepId;const s=n.isMinimized;"playing"!==i&&"waitingForInteraction"!==i||s||(this.cleanupTransitions(),n.goToStep?n.goToStep(t):null==(e=n.goToStep)||e.call(n,t))}async triggerTransitionWithProgress(t){const e=bt(),n=e.currentState;e.currentStepId;const i=e.isMinimized;if("playing"!==n&&"waitingForInteraction"!==n)return!1;if(i)return!1;try{return this.triggerTransition(t),await new Promise((t=>setTimeout(t,It))),!0}catch(s){return!1}}cleanupTransitions(){this.activeTransitions.forEach((t=>{t.cleanup()})),this.activeTransitions.clear(),this.waitingForInteraction=!1,this.removeBeforeUnloadHandler()}setWaitingForInteraction(t){this.waitingForInteraction=t}isWaitingForInteraction(){return this.waitingForInteraction}reset(){this.cleanupTransitions()}startStateMachineValidation(){this.isStateMachineValidating=!0}endStateMachineValidation(){this.isStateMachineValidating=!1}destroy(){this.cleanupTransitions(),window.removeEventListener("popstate",this.handleURLChange)}setupDOMElementVisibleTransition(t){if(!t.target)return;const e=t.target,n=t.nextStep,i=`dom-visible-${e}-${Date.now()}`;let s=null,r=null,a=null,o=null;const l=t=>{s||(a=t,s=new IntersectionObserver((t=>{t.forEach((t=>{var e;if(t.isIntersecting,t.intersectionRatio.toFixed(2),t.target.outerHTML.substring(0,100),t.isIntersecting&&t.target===a){const s=window.getComputedStyle(t.target);if(!("0"!==s.opacity&&"none"!==s.display&&"visible"===s.visibility&&"none"!==s.pointerEvents))return;this.triggerTransition(n),null==(e=this.activeTransitions.get(i))||e.cleanup(),this.activeTransitions.delete(i)}else if(t.target===a){const e=t.target.getBoundingClientRect();e.top.toFixed(0),e.left.toFixed(0),e.bottom.toFixed(0),e.right.toFixed(0),e.width.toFixed(0),e.height.toFixed(0)}}))}),{root:null,rootMargin:"0px",threshold:0}),s.observe(t),r&&(r.disconnect(),r=null))},c=t.expectedElement||t.expectedSize?ae(e,t.expectedElement,t.expectedSize):document.querySelector(e);c?l(c):(r=new MutationObserver((n=>{for(const i of n)if("childList"===i.type&&i.addedNodes.forEach((n=>{if(n.nodeType===Node.ELEMENT_NODE){const i=n;if(i.matches(e)&&(!t.expectedElement&&!t.expectedSize||le(i,t.expectedElement,t.expectedSize)))return void l(i);const s=t.expectedElement||t.expectedSize?ae(e,t.expectedElement,t.expectedSize):i.querySelector(e);if(s)return void l(s)}})),!r)break})),r.observe(document.body,{childList:!0,subtree:!0}),o=window.setInterval((()=>{if(!r)return void(o&&clearInterval(o));const n=t.expectedElement||t.expectedSize?ae(e,t.expectedElement,t.expectedSize):document.querySelector(e);n&&n.offsetWidth>0&&n.offsetHeight>0&&(o&&clearInterval(o),o=null,l(n))}),1e3)),this.activeTransitions.set(i,{handlers:new Map,cleanup:()=>{s&&(s.disconnect(),s=null),r&&(r.disconnect(),r=null),o&&(clearInterval(o),o=null),a=null},data:{type:"dom-element-visible",pattern:e,nextStepId:n}})}reDispatchClick(t){const e=t.target;if(e&&e instanceof HTMLElement)try{setTimeout((()=>{e.tagName,e.id&&e.id,e.className&&e.className.split(" ").join(".");const n=new MouseEvent("click",{bubbles:!0,cancelable:!0,view:window,button:t.button||0,buttons:t.buttons||1,clientX:t.clientX||0,clientY:t.clientY||0,ctrlKey:t.ctrlKey||!1,shiftKey:t.shiftKey||!1,altKey:t.altKey||!1,metaKey:t.metaKey||!1});e.dispatchEvent(n)}),10)}catch(n){}}willCauseHardRefresh(t){try{if("A"===t.tagName&&t.hasAttribute("href")){const e=t.getAttribute("href");if(!e)return!1;const n=new URL(e,window.location.href),i=new URL(window.location.href);if(n.origin!==i.origin)return n.origin,i.origin,!0;const s=t.getAttribute("target");return!(!s||"_self"===s)||("mailto:"===n.protocol||"tel:"===n.protocol||"sms:"===n.protocol||"javascript:"===n.protocol)&&(n.protocol,!0)}const e=t.closest("form");if(e&&e.hasAttribute("action")){const t=e.getAttribute("action");if(t&&"#"!==t&&""!==t)return!1}return t.tagName,!1}catch(e){return!1}}}class ve{constructor(){e(this,"triggeredPlaylists",[]),e(this,"triggeredPlaylistsSet",new Set),e(this,"isMonitoring",!1),e(this,"elementClickedListeners",new Map),e(this,"clickedElements",new Set),e(this,"elementVisibleObservers",new Map),e(this,"visibleElements",new Set)}registerTriggers(t){this.triggeredPlaylists=t.filter((t=>(t.hasTriggers??t.autoStart??!1)&&t.triggers)),this.triggeredPlaylists.length,this.triggeredPlaylists.forEach((t=>{var e,n,i,s;t.id,null==(e=t.triggers)||e.url,null==(n=t.triggers)||n.elementClicked,null==(i=t.triggers)||i.elementVisible,null==(s=t.triggers)||s.maxVisits})),this.setupElementClickListeners(),this.setupElementVisibleObservers()}startMonitoring(){this.isMonitoring||(this.isMonitoring=!0,this.evaluateAllTriggers())}stopMonitoring(){this.isMonitoring=!1}evaluateAllTriggers(){if(this.isMonitoring&&0!==this.triggeredPlaylists.length)for(const t of this.triggeredPlaylists){if(this.evaluatePlaylistTrigger(t)){t.id;break}}}evaluatePlaylistTrigger(t){if(!t.triggers)return!1;const{triggers:e}=t,n=t.id;if(this.triggeredPlaylistsSet.has(n))return!1;if(!bt().user)return!1;const i=[],s=this.getWatchedPlaylists(),r=this.evaluateMaxVisitsCondition(e.maxVisits,n,s);i.push(r);const a=this.evaluateURLCondition(e);i.push(a),e.url;const o=this.evaluatePlaylistSeenCondition(e.playlistSeen,s);i.push(o),JSON.stringify(e.playlistSeen);const l=this.evaluatePlaylistNotSeenCondition(e.playlistNotSeen,s);i.push(l),JSON.stringify(e.playlistNotSeen);const c=this.evaluateElementClickCondition(e.elementClicked);i.push(c),e.elementClicked;const d=this.evaluateElementVisibleCondition(e.elementVisible);i.push(d),e.elementVisible;const h=this.evaluateUserAttributesCondition(e.userAttributes);i.push(h),JSON.stringify(e.userAttributes);const u=this.applyOperators(i,e.operators);return e.operators.join(", "),!!u&&(this.triggerPlaylist(n),!0)}getWatchedPlaylists(){var t,e;const n=bt();if((null==(t=n.userData)?void 0:t.watchedPlaylists)&&Object.keys(n.userData.watchedPlaylists).length>0)return n.userData.watchedPlaylists;const i=gt.getInstance().getProgress(null==(e=n.user)?void 0:e.id);if(!i)return{};const s={};for(const r of Object.keys(i))s[r]={status:"in_progress",timestamp:Date.now()};return JSON.stringify(Object.keys(s)),s}evaluateMaxVisitsCondition(t,e,n){if(null===t)return!0;const i=n&&n[e];return((null==i?void 0:i.visitCount)??("completed"===(null==i?void 0:i.status)||"dismissed"===(null==i?void 0:i.status)?1:0))<t}normalizeUrl(t){return t.endsWith("/")&&t.lastIndexOf("/")>t.indexOf("://")+2?t.slice(0,-1):t}evaluateURLCondition(t){let e=t.url;if(!e)return!0;const n=this.normalizeUrl(window.location.href.split("#")[0]),i=window.location.pathname;if("regex"===t.urlMatchType)try{const t=new RegExp(e),s=t.test(n),r=t.test(i);return s||r}catch(c){return!1}"contains"!==t.urlMatchType||e.includes("*")||(e="*"+e+"*");const s=e.includes("*");s||t.urlMatchType&&"exact"!==t.urlMatchType&&"contains"!==t.urlMatchType||(e=this.normalizeUrl(e));let r=e.replace(/[.*+?^${}()|[\]\\]/g,"\\$&").replace(/\\\*/g,".*");s||(r="^"+r+"$");const a=new RegExp(r),o=a.test(n),l=a.test(i);return t.url,t.urlMatchType,o||l}evaluatePlaylistSeenCondition(t,e){if(!t||0===t.length)return!0;if(!e)return!1;for(const n of t){const t=e[n];if(!t||"completed"!==t.status&&"in_progress"!==t.status)return!1}return!0}evaluatePlaylistNotSeenCondition(t,e){if(!t||0===t.length)return!0;if(!e)return!0;for(const n of t){const t=e[n];if(t&&("completed"===t.status||"in_progress"===t.status))return!1}return!0}evaluateElementClickCondition(t){if(!t)return!0;return this.clickedElements.has(t)}evaluateElementVisibleCondition(t){if(!t)return!0;return this.visibleElements.has(t)}evaluateUserAttributesCondition(t){if(!t||0===t.length)return!0;const e=bt().user;if(!e)return!1;for(const n of t){const{attributeKey:t,attributeType:i,operator:s,value:r}=n,a=e[t];if(null==a)return!1;if(!this.compareValues(a,r,i,s))return!1}return!0}compareValues(t,e,n,i){try{switch(n){case"string":{const n=String(t),s=e;return this.applyOperator(n,s,i)}case"boolean":{const n="boolean"==typeof t?t:"true"===String(t).toLowerCase(),s="true"===e.toLowerCase();return"equals"===i?n===s:"notEquals"===i&&n!==s}case"int":{const n="number"==typeof t?t:parseFloat(String(t)),s=parseFloat(e);return!isNaN(n)&&!isNaN(s)&&this.applyOperator(n,s,i)}case"date":{const n=t instanceof Date?t:new Date(String(t)),s=new Date(e);return!isNaN(n.getTime())&&!isNaN(s.getTime())&&this.applyOperator(n.getTime(),s.getTime(),i)}default:return!1}}catch(s){return!1}}applyOperator(t,e,n){switch(n){case"equals":return t===e;case"notEquals":return t!==e;case"greaterThan":return t>e;case"lessThan":return t<e;default:return!1}}setupElementClickListeners(){this.clearElementClickListeners(),this.triggeredPlaylists.forEach((t=>{var e;(null==(e=t.triggers)?void 0:e.elementClicked)&&this.setupElementClickListener(t.id,t.triggers.elementClicked,t.triggers.elementClickedExpectedElement,t.triggers.elementClickedExpectedSize)}))}setupElementClickListener(t,e,n,i){try{const s=n||i?ae(e,n,i):document.querySelector(e);if(!s)return;if(!this.triggeredPlaylists.find((e=>e.id===t)))return;const r=t=>{t.preventDefault(),t.stopPropagation(),this.clickedElements.add(e),this.evaluateAllTriggers()};s.addEventListener("click",r);const a=`${t}-${e}`;this.elementClickedListeners.set(a,{element:s,listener:r,selector:e})}catch(s){}}clearElementClickListeners(){this.elementClickedListeners.forEach((({element:t,listener:e})=>{try{t.removeEventListener("click",e)}catch(n){console.error("TriggerManager: Error removing element click listener:",n)}})),this.elementClickedListeners.clear()}setupElementVisibleObservers(){this.clearElementVisibleObservers(),this.triggeredPlaylists.forEach((t=>{var e;(null==(e=t.triggers)?void 0:e.elementVisible)&&this.setupElementVisibleObserver(t.id,t.triggers.elementVisible,t.triggers.elementVisibleExpectedElement,t.triggers.elementVisibleExpectedSize)}))}setupElementVisibleObserver(t,e,n,i){try{const s=`${t}-${e}`;if(this.elementVisibleObservers.has(s))return;const r=t=>{const n=new IntersectionObserver((t=>{t.forEach((t=>{if(t.isIntersecting,t.intersectionRatio.toFixed(2),t.isIntersecting){const n=window.getComputedStyle(t.target);if(!("0"!==n.opacity&&"none"!==n.display&&"visible"===n.visibility&&"none"!==n.pointerEvents))return;this.visibleElements.add(e),this.evaluateAllTriggers()}else this.visibleElements.has(e)&&this.visibleElements.delete(e)}))}),{root:null,rootMargin:"0px",threshold:0});n.observe(t);const i=this.elementVisibleObservers.get(s);i?(i.mutationObserver&&i.mutationObserver.disconnect(),this.elementVisibleObservers.set(s,{observer:n,mutationObserver:null,selector:e})):this.elementVisibleObservers.set(s,{observer:n,mutationObserver:null,selector:e})},a=n||i?ae(e,n,i):document.querySelector(e);if(a)r(a);else{const t=new MutationObserver((t=>{for(const s of t)"childList"===s.type&&s.addedNodes.forEach((t=>{if(t.nodeType===Node.ELEMENT_NODE){const s=t;if(s.matches(e))(!n&&!i||le(s,n,i))&&r(s);else{const t=n||i?ae(e,n,i):s.querySelector(e);t&&r(t)}}}))}));t.observe(document.body,{childList:!0,subtree:!0}),this.elementVisibleObservers.set(s,{observer:null,mutationObserver:t,selector:e})}}catch(s){}}clearElementVisibleObservers(){this.elementVisibleObservers.forEach((({observer:t,mutationObserver:e})=>{try{t&&t.disconnect(),e&&e.disconnect()}catch(n){console.error("TriggerManager: Error removing element visibility observer:",n)}})),this.elementVisibleObservers.clear()}applyOperators(t,e){return 0!==t.length&&(1===t.length?t[0]:e&&0!==e.length&&e.includes("OR")?t.some((t=>t)):t.every((t=>t)))}async triggerPlaylist(t){this.triggeredPlaylistsSet.add(t);try{const e=window._saltfishPlayer;e&&"function"==typeof e.startPlaylist&&await e.startPlaylist(t,{_triggeredByTriggerManager:!0})}catch(e){this.triggeredPlaylistsSet.delete(t)}}resetTriggeredPlaylists(){this.triggeredPlaylistsSet.clear()}getTriggeredPlaylists(){return Array.from(this.triggeredPlaylistsSet)}markPlaylistAsTriggered(t){this.triggeredPlaylistsSet.has(t)||this.triggeredPlaylistsSet.add(t)}destroy(){this.stopMonitoring(),this.clearElementClickListeners(),this.clearElementVisibleObservers(),this.triggeredPlaylists=[],this.triggeredPlaylistsSet.clear(),this.clickedElements.clear(),this.visibleElements.clear()}}class be extends me{constructor(t){super(t)}subscribeToEvents(){this.eventManager&&this.eventManager.on("playlistStarted",(t=>{this.trackTestParticipation(t.playlist.id)}))}initializeTests(t){bt().setABTests(t)}assignUserToTests(t,e,n){var i,s;const r=bt(),a=r.abTests||[],o={...e};for(const l of a){const e=l.testType||"percentage";if("userList"!==e&&o[l.id])continue;let a=!1;if("userList"===e){a=!(!0===(null==(s=null==(i=r.user)?void 0:i.userData)?void 0:s.__isAnonymous))&&!0===(null==n?void 0:n[l.id])}else a=this.isUserInTest(t,l);o[l.id]={testId:l.id,assigned:a,assignedAt:Date.now()},l.name}return r.setABTestAssignments(o),o}isUserInTest(t,e){if(!e.percentage)return!1;const n=`${t}_${e.id}`;let i=0;for(let s=0;s<n.length;s++){i=(i<<5)-i+n.charCodeAt(s),i|=0}return Math.abs(i)%100<e.percentage}getFilteredPlaylists(t){const e=bt(),n=e.abTests||[],i=e.abTestAssignments||{};if(0===n.length)return t;const s=new Set;for(const a of n){const t=i[a.id];t&&t.assigned||(s.add(a.playlistId),a.playlistId,a.name)}const r=t.filter((t=>!s.has(t.id)));return t.length,r.length,r}trackTestParticipation(t){var e;const n=bt(),i=n.abTests||[],s=n.abTestAssignments||{},r=i.find((e=>e.playlistId===t));if(!r)return;const a=s[r.id];a&&a.assigned&&(r.testType,r.name,this.eventManager&&this.eventManager.trigger("abTestParticipation",{testId:r.id,testName:r.name,testType:r.testType||"percentage",playlistId:t,userId:null==(e=n.user)?void 0:e.id,timestamp:Date.now()}))}getAssignmentsForBackend(){return bt().abTestAssignments||{}}isPlaylistAvailable(t){const e=bt(),n=e.abTests||[],i=e.abTestAssignments||{},s=n.find((e=>e.playlistId===t));if(!s)return!0;const r=i[s.id];return r&&r.assigned}getActiveTestInfo(){const t=bt(),e=t.abTests||[],n=t.abTestAssignments||{};return e.map((t=>{var e;return{testId:t.id,testName:t.name,testType:t.testType||"percentage",assigned:(null==(e=n[t.id])?void 0:e.assigned)||!1}}))}}class we{constructor(){e(this,"listeners",new Map)}on(t,e){this.listeners.has(t)||this.listeners.set(t,new Set),this.listeners.get(t).add(e)}off(t,e){const n=this.listeners.get(t);return!!n&&n.delete(e)}trigger(t,e){const n=this.listeners.get(t);n&&0!==n.size&&("timestamp"in e||(e.timestamp=Date.now()),n.forEach((n=>{try{n(e)}catch(i){console.error(`Error in ${t} event handler:`,i)}})))}removeAllListeners(){this.listeners.clear()}getListenerCount(t){const e=this.listeners.get(t);return e?e.size:0}}class Se{async loadManifest(t){const{manifestPath:e,playlistOptions:n,savedProgress:i}=t;try{const t=await this.fetchManifest(e);this.validateManifest(t);const s=this.determineStartStep(t,n,i);return t.id,{manifest:t,startStepId:s}}catch(s){const t=s instanceof Error?s.message:"Unknown error";throw G("[PlaylistLoader] Failed to load manifest:",s),new Error(`Unable to load playlist manifest: ${t}`)}}async fetchManifest(t){try{const e=await fetch(t);if(e.status,e.statusText,!e.ok)throw new Error(`HTTP ${e.status}: ${e.statusText}`);return await e.json()}catch(e){throw G("[PlaylistLoader] Fetch/parse failed:",e),G("[PlaylistLoader] Manifest path:",t),new Error(`Failed to fetch manifest from "${t}": ${e instanceof Error?e.message:"Unknown error"}`)}}validateManifest(t){if(!t)throw new Error("Manifest is null or undefined");if("object"!=typeof t)throw new Error("Manifest must be an object");const e=t,n=["id","startStep","steps"];for(const s of n)if(!(s in e))throw new Error(`Manifest missing required field: ${s}`);if(!Array.isArray(e.steps))throw new Error("Manifest steps must be an array");const i=e.steps;if(0===i.length)throw new Error("Manifest must contain at least one step");if(!i.some((t=>"object"==typeof t&&null!==t&&"id"in t&&t.id===e.startStep)))throw new Error(`Start step '${e.startStep}' not found in steps array`);for(const s of i){if("object"!=typeof s||null===s)throw new Error("Each step must be an object");const t=s;if(!t.id)throw new Error("Each step must have an id");if(!t.transitions||!Array.isArray(t.transitions))throw new Error(`Step '${t.id}' must have transitions array`)}}determineStartStep(t,e,n){const i=e.persistence??t.isPersistent??!0,s=t.id,r=!0===e._triggeredByTriggerManager;let a=t.startStep;const o=this.checkPendingNavigation(t);if(o)return o.nextStepId,o.nextStepId;if(e.startNodeId){t.steps.find((t=>t.id===e.startNodeId))?(e.startNodeId,a=e.startNodeId):e.startNodeId}else if(r)a=t.startStep;else if(i&&n&&n[s]){const e=n[s];if("completed"===e.status)a=t.startStep;else{const{isValid:n,ageMs:i}=St(e);if(n){const n=e.currentStepId||e.lastStepId;if(n){t.steps.find((t=>t.id===n))&&(a=n)}}else a=t.startStep}}return a}checkPendingNavigation(t){const e=gt.getInstance(),n=e.getPendingNavigation();if(!n)return null;if(n.playlistId!==t.id)return n.playlistId,null;const i=Date.now()-n.timestamp;if(i>At)return e.clearPendingNavigation(),null;if(!this.isURLPathMatch(n.urlPattern))return n.urlPattern,e.clearPendingNavigation(),null;return t.steps.find((t=>t.id===n.nextStepId))?(n.nextStepId,Math.round(i/1e3),e.clearPendingNavigation(),n):(n.nextStepId,e.clearPendingNavigation(),null)}isURLPathMatch(t){if(!t)return!1;const e=window.location.href,n=window.location.pathname,i=t.replace(/[.*+?^${}()|[\]\\]/g,"\\$&").replace(/\\\*/g,".*"),s=new RegExp(i);return s.test(e)||s.test(n)}}class Ee extends me{constructor(t,n){super(t),e(this,"isUpdatingWatchedPlaylists",!1),e(this,"playlistLoader"),e(this,"storageManager"),this.playlistLoader=new Se,this.storageManager=n||gt.getInstance()}subscribeToEvents(){this.eventManager&&(this.eventManager.on("playlistStarted",(t=>{t.playlist.id,this.updateWatchedPlaylistStatus(t.playlist.id,"in_progress")})),this.eventManager.on("playlistEnded",(t=>{t.playlist.id,this.updateWatchedPlaylistStatus(t.playlist.id,"completed").catch((e=>{console.error(`PlaylistManager: Error in updateWatchedPlaylistStatus for playlist ${t.playlist.id}:`,e)}))})),this.eventManager.on("playlistDismissed",(t=>{t.playlist.id,this.updateWatchedPlaylistStatus(t.playlist.id,"dismissed")})),this.eventManager.on("stepStarted",(t=>{t.step.id,this.updateWatchedPlaylistStatus(t.playlist.id,"in_progress",t.step.id)})))}async updateWatchedPlaylistStatus(t,e,n){var i,s,r,a,o,l;if(!this.isUpdatingWatchedPlaylists){this.isUpdatingWatchedPlaylists=!0;try{const d=bt(),h=d.userData||{},u=h.watchedPlaylists||{},p=u[t],m=null==p?void 0:p.status,g=(null==p?void 0:p.visitCount)??0,f=("completed"===e||"dismissed"===e)&&m!==e,y={status:e,currentStepId:"completed"===e?null:n||d.currentStepId||null,timestamp:Date.now(),lastProgressAt:Date.now(),visitCount:f?g+1:g},v={...u,[t]:y};if(d.setUserData({...h,watchedPlaylists:v}),!(null==(i=null==d?void 0:d.config)?void 0:i.token)||!(null==(s=null==d?void 0:d.user)?void 0:s.id)||(null==(r=null==d?void 0:d.user)?void 0:r.__isAnonymous))return null==(a=null==d?void 0:d.config)||a.token,null==(o=null==d?void 0:d.user)||o.id,null==(l=null==d?void 0:d.user)||l.__isAnonymous,void this.updateAnonymousUserWatchedPlaylists(t,e,n||d.currentStepId||null);const b=`https://player.saltfish.ai/clients/${d.config.token}/users/${d.user.id}/playlists/${t}`;try{const t=await fetch(b,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({status:e,currentStepId:n||d.currentStepId||null})});if(!t.ok)throw new Error(`Failed to update watched playlist status: ${t.statusText} (${t.status})`)}catch(c){console.error(`PlaylistManager: Error updating watched playlist status for ${t}:`,c)}}finally{this.isUpdatingWatchedPlaylists=!1}}}updateAnonymousUserWatchedPlaylists(t,e,n){if("undefined"==typeof window)return;let i=this.storageManager.getAnonymousUserData()||{userId:"anonymous",userData:{},watchedPlaylists:{},timestamp:Date.now()};i.watchedPlaylists||(i.watchedPlaylists={});const s=i.watchedPlaylists[t],r=null==s?void 0:s.status,a=(null==s?void 0:s.visitCount)??0,o=("completed"===e||"dismissed"===e)&&r!==e;i.watchedPlaylists[t]={status:e,currentStepId:n||null,timestamp:Date.now(),lastProgressAt:Date.now(),visitCount:o?a+1:a},i.timestamp=Date.now(),this.storageManager.setAnonymousUserData(i)}async load(t,e){var n;try{const i=bt();if(!i)throw new Error("Store not available");const s=(null==(n=i.userData)?void 0:n.watchedPlaylists)||i.progress,r=await this.playlistLoader.loadManifest({manifestPath:t,playlistOptions:e,savedProgress:s}),{manifest:a,startStepId:o}=r,l=a.steps.find((t=>t.id===o));i.setManifest(a,o),l&&i.sendStateMachineEvent({type:"MANIFEST_LOADED",step:l})}catch(i){const t=bt(),e=i instanceof Error?i:new Error("Unknown error loading manifest");t?t.setError(e):console.error("[PlaylistManager] Cannot set error: Store not available",e)}}destroy(){this.eventManager&&(this.eventManager=null)}}class xe{constructor(t){e(this,"button"),e(this,"playerElement"),this.playerElement=t,this.button=document.createElement("button"),this.button.className="sf-player__minimize-button",this.button.innerHTML='\n <svg width="20" height="20" viewBox="0 0 256 256" fill="currentColor" xmlns="http://www.w3.org/2000/svg">\n <path d="M205.66,194.34a8,8,0,0,1-11.32,11.32L128,139.31,61.66,205.66a8,8,0,0,1-11.32-11.32L116.69,128,50.34,61.66A8,8,0,0,1,61.66,50.34L128,116.69l66.34-66.35a8,8,0,0,1,11.32,11.32L139.31,128Z"></path>\n </svg>\n ',this.button.addEventListener("click",this.handleClick.bind(this)),this.playerElement.appendChild(this.button),this.updateVisibility(bt().isMinimized)}handleClick(){const t=bt(),e=!t.isMinimized;e?t.minimize():t.maximize(),e?this.minimize():this.maximize()}minimize(){this.button.innerHTML='\n <svg width="18" height="18" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">\n <path d="M12 5v14M5 12h14" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>\n </svg>\n '}maximize(){this.button.innerHTML='\n <svg width="20" height="20" viewBox="0 0 256 256" fill="currentColor" xmlns="http://www.w3.org/2000/svg">\n <path d="M205.66,194.34a8,8,0,0,1-11.32,11.32L128,139.31,61.66,205.66a8,8,0,0,1-11.32-11.32L116.69,128,50.34,61.66A8,8,0,0,1,61.66,50.34L128,116.69l66.34-66.35a8,8,0,0,1,11.32,11.32L139.31,128Z"></path>\n </svg>\n '}updateVisibility(t){t?this.button.classList.add("sf-hidden"):this.button.classList.remove("sf-hidden")}destroy(){this.button.removeEventListener("click",this.handleClick.bind(this)),this.button.remove()}}class Me{constructor(t,n){e(this,"playButton"),e(this,"container"),e(this,"videoManager",null),this.container=t,this.videoManager=n||null,this.createButton()}createButton(){this.playButton=document.createElement("button"),this.playButton.className="sf-controls-container__play-button",this.playButton.innerHTML='\n <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">\n <path d="M8 5v14l11-7z" fill="currentColor"/>\n </svg>\n ',this.playButton.addEventListener("click",this.handlePlayClick.bind(this)),this.container.appendChild(this.playButton)}handlePlayClick(t){t&&t.stopPropagation();const e=bt();if("autoplayBlocked"===e.currentState)if(this.videoManager){this.videoManager.markUserInteraction(),this.videoManager.setMuted(!1);const t=this.videoManager.getVideoElement();t&&(t.loop=!1,t.currentTime=0)}else{const t=this.playButton.closest(".sf-player");if(t){const e=t.querySelector(".sf-video-container__video");e&&(e.muted=!1,e.loop=!1,e.currentTime=0)}}else this.videoManager?this.videoManager.markUserInteraction():console.warn("PlayPauseButton: VideoManager not available, falling back to store play");"paused"!==e.currentState&&"waitingForInteraction"!==e.currentState&&"autoplayBlocked"!==e.currentState||e.play()}destroy(){this.playButton.removeEventListener("click",this.handlePlayClick.bind(this)),this.playButton.remove()}}class Ie{constructor(t){e(this,"button"),e(this,"playerElement"),this.playerElement=t,this.button=document.createElement("button"),this.button.className="sf-player__exit-button",this.button.innerHTML='\n <svg width="18" height="18" viewBox="0 0 256 256" fill="currentColor" xmlns="http://www.w3.org/2000/svg">\n <path d="M205.66,194.34a8,8,0,0,1-11.32,11.32L128,139.31,61.66,205.66a8,8,0,0,1-11.32-11.32L116.69,128,50.34,61.66A8,8,0,0,1,61.66,50.34L128,116.69l66.34-66.35a8,8,0,0,1,11.32,11.32L139.31,128Z"></path>\n </svg>\n ',this.button.addEventListener("click",this.handleClick.bind(this)),this.playerElement.appendChild(this.button),this.updateVisibility(bt().isMinimized)}handleClick(t){t.stopPropagation();bt().sendStateMachineEvent({type:"EXIT"})}updateVisibility(t){t?this.button.classList.remove("sf-hidden"):this.button.classList.add("sf-hidden")}destroy(){this.button.removeEventListener("click",this.handleClick.bind(this)),this.button.remove()}}class Pe{constructor(t,n={}){e(this,"errorOverlay"),e(this,"container"),e(this,"options"),e(this,"isVisible",!1),this.container=t,this.options=n,this.createErrorDisplay()}createErrorDisplay(){this.errorOverlay=document.createElement("div"),this.errorOverlay.className=ct,this.errorOverlay.classList.add("sf-hidden");const t=document.createElement("div");t.className=ht;const e=document.createElement("p");e.className=ut,e.textContent=this.options.message||"Unable to load content",t.appendChild(e),this.errorOverlay.appendChild(t),this.container.appendChild(this.errorOverlay)}show(t){t&&this.updateOptions(t),this.errorOverlay.classList.remove("sf-hidden"),this.isVisible=!0,requestAnimationFrame((()=>{this.errorOverlay.classList.add(dt)}))}hide(){this.isVisible&&(this.errorOverlay.classList.remove(dt),setTimeout((()=>{this.errorOverlay.classList.add("sf-hidden"),this.isVisible=!1}),300))}updateOptions(t){if(this.options={...this.options,...t},void 0!==t.message){const e=this.errorOverlay.querySelector(`.${ut}`);e&&(e.textContent=t.message||"Unable to load content")}}static getErrorMessage(t,e){const n=(t instanceof Error?t.message:t).toLowerCase();return"video"===e||n.includes("video")||n.includes("cannot load video")?n.includes("no video url")||n.includes("video url provided")?"This step doesn't have a video to play":"Unable to load video content":"network"===e||n.includes("network")||n.includes("fetch")?"Connection issue detected":"playlist"===e||n.includes("playlist")?"Unable to load playlist":"initialization"===e||n.includes("token")||n.includes("initialize")?"Setup issue detected":"Unable to load content"}isShowing(){return this.isVisible}destroy(){this.errorOverlay&&this.errorOverlay.remove()}}class Ce{constructor(t){e(this,"container"),e(this,"spinnerElement",null),this.container=t}show(){this.spinnerElement?this.spinnerElement.classList.remove("sf-hidden"):(this.spinnerElement=document.createElement("div"),this.spinnerElement.className=`${pt}`,this.spinnerElement.innerHTML='\n <div class="sf-loading-spinner__content">\n <div class="sf-loading-spinner__icon">\n <svg width="60" height="60" viewBox="0 0 60 60" fill="none" xmlns="http://www.w3.org/2000/svg">\n \x3c!-- Static Saltfish logo in center --\x3e\n <g transform="translate(10, 10) scale(0.656)">\n <g clip-path="url(#saltfish-clip)">\n <path d="M61.0002 30.1906C61.0002 46.8644 47.4834 60.3812 30.8097 60.3812C14.136 60.3812 27.1659 46.8644 27.1659 30.1906C27.1659 13.5168 14.136 0 30.8097 0C47.4834 0 61.0002 13.5168 61.0002 30.1906Z" fill="black" fill-opacity="0.9"/>\n <path d="M24.13 29.8618C24.13 40.3565 15.6978 48.8642 5.29602 48.8642C-5.10576 48.8642 3.02294 40.3565 3.02294 29.8618C3.02294 19.3671 -5.10576 10.8594 5.29602 10.8594C15.6978 10.8594 24.13 19.3671 24.13 29.8618Z" fill="black" fill-opacity="0.9"/>\n </g>\n <defs>\n <clipPath id="saltfish-clip">\n <rect width="61" height="61" fill="white"/>\n </clipPath>\n </defs>\n </g>\n \n \x3c!-- Animated circular ring around logo --\x3e\n <circle cx="30" cy="30" r="28" \n stroke="black" stroke-width="2" \n fill="none" stroke-linecap="round"\n stroke-dasharray="8 6" stroke-opacity="0.3">\n <animateTransform attributeName="transform" \n type="rotate" \n values="0 30 30;360 30 30" \n dur="2s" \n repeatCount="indefinite"/>\n </circle>\n </svg>\n </div>\n <div class="sf-loading-spinner__text">Loading playlist...</div>\n </div>\n ',this.container.appendChild(this.spinnerElement))}hide(){this.spinnerElement&&this.spinnerElement.classList.add("sf-hidden")}updateMessage(t){if(this.spinnerElement){const e=this.spinnerElement.querySelector(".sf-loading-spinner__text");e&&(e.textContent=t)}}destroy(){this.spinnerElement&&(this.spinnerElement.remove(),this.spinnerElement=null)}}class _e{constructor(t){e(this,"shadowDOMManager"),e(this,"playerRoot",null),e(this,"playerElement",null),e(this,"minimizeButton",null),e(this,"exitButton",null),e(this,"playPauseButton",null),e(this,"errorDisplay",null),e(this,"loadingSpinner",null),e(this,"compactLabel",null),e(this,"playbackButtonsVisible",!1),e(this,"playButton",null),e(this,"centerPlayButton",null),e(this,"videoManager",null),e(this,"storeUnsubscribe",null),this.shadowDOMManager=t}createPlayerUI(t,e,n){if(this.videoManager=t,this.playerElement&&this.reset(),!this.playerRoot&&(this.shadowDOMManager.create(),this.playerRoot=this.shadowDOMManager.getRootElement(),!this.playerRoot))return void console.error("Failed to create player root element");this.playerElement=this.createPlayerElement(this.playerRoot),this.minimizeButton=new xe(this.playerElement),this.exitButton=new Ie(this.playerElement),t.create(this.playerElement);const i=this.createControlsContainer(this.playerElement);this.playPauseButton=new Me(i,t),this.createSaltfishLogo(this.playerElement),this.setupVideoContainerClickHandler(),e.create(),n.create(this.playerElement),this.initializeButtonManagement();const s=bt();this.handleMinimizeStateChange(s.isMinimized)}setupVideoContainerClickHandler(){var t;const e=null==(t=this.playerElement)?void 0:t.querySelector(".sf-video-container");e&&e.addEventListener("click",(t=>{var e;const n=bt();if(n.isMinimized)return t.stopPropagation(),void this.handleMinimizeClick();const i=t.target;if("BUTTON"===i.tagName||i.closest("button")||i.closest(".sf-controls-container"))return;const s=null==(e=this.playerElement)?void 0:e.classList.contains("sf-player--compact");"playing"===n.currentState?n.pause():!s||"idleMode"!==n.currentState&&"autoplayBlocked"!==n.currentState&&"paused"!==n.currentState||(this.handleAutoplayFallbackInteraction("compact bubble click"),n.play())}))}updatePosition(){var t;if(!this.playerRoot||!this.playerElement)return void console.warn("UIManager: updatePosition called but playerRoot or playerElement is null",{playerRoot:!!this.playerRoot,playerElement:!!this.playerElement});const e=bt();let n=(null==(t=e.playlistOptions)?void 0:t.position)||"bottom-right";if(e.currentStepId&&e.manifest){const t=e.manifest.steps.find((t=>t.id===e.currentStepId));(null==t?void 0:t.position)&&(n=t.position)}"bottom-left"!==n&&"bottom-right"!==n&&(console.warn(`UIManager: Invalid position "${n}", defaulting to bottom-right`),n="bottom-right"),this.playerRoot.classList.remove("sf-player-root--bottom-left","sf-player-root--bottom-right"),"bottom-left"===n?this.playerRoot.classList.add("sf-player-root--bottom-left"):this.playerRoot.classList.add("sf-player-root--bottom-right"),e.isMinimized?this.playerElement.classList.add(at):this.playerElement.classList.remove(at)}handleMinimizeClick(){if(!this.playerElement)return;const t=bt(),e=!t.isMinimized;e?t.minimize():t.maximize(),e?this.minimizeButton.minimize():this.minimizeButton.maximize()}handleMinimizeStateChange(t){this.exitButton&&this.exitButton.updateVisibility(t),this.minimizeButton&&this.minimizeButton.updateVisibility(t)}getPlayerElement(){return this.playerElement}getPlayerRoot(){return this.playerRoot}showError(t,e,n){if(!this.playerElement)return void console.warn("UIManager: Cannot show error display - player element not available");const i=Pe.getErrorMessage(t,e);this.errorDisplay||(this.errorDisplay=new Pe(this.playerElement,{message:i,...n})),this.errorDisplay.show({message:i,...n})}hideError(){this.errorDisplay&&this.errorDisplay.hide()}isErrorDisplayVisible(){var t;return(null==(t=this.errorDisplay)?void 0:t.isShowing())||!1}showLoading(t){this.playerElement?(this.loadingSpinner||(this.loadingSpinner=new Ce(this.playerElement)),this.loadingSpinner.show(),t&&this.loadingSpinner.updateMessage(t)):console.warn("UIManager: Cannot show loading spinner - player element not available")}hideLoading(){this.loadingSpinner&&this.loadingSpinner.hide()}updateLoadingMessage(t){this.loadingSpinner&&this.loadingSpinner.updateMessage(t)}showPlayer(){this.playerElement&&this.playerElement.classList.add("sf-player--visible")}createPlayerElement(t){const e=document.createElement("div");return e.className=rt,t.appendChild(e),e}createControlsContainer(t){const e=document.createElement("div");return e.className=ot,t.appendChild(e),e}createSaltfishLogo(t){var e;if(!1===(null==(e=bt().config)?void 0:e.showLogo))return;const n=document.createElement("div");n.className=lt,n.innerHTML='\n <svg viewBox="0 0 41 15" fill="none" xmlns="http://www.w3.org/2000/svg">\n <path d="M8.42034 7.49991C8.42034 9.67502 6.65707 11.4383 4.48196 11.4383C2.30685 11.4383 4.00664 9.67502 4.00664 7.49991C4.00664 5.3248 2.30685 3.56152 4.48196 3.56152C6.65707 3.56152 8.42034 5.3248 8.42034 7.49991Z" fill="white"/>\n <path d="M3.53097 7.43198C3.53097 8.96956 2.29707 10.216 0.774969 10.216C-0.747128 10.216 0.442349 8.96956 0.442349 7.43198C0.442349 5.8944 -0.747128 4.64795 0.774969 4.64795C2.29707 4.64795 3.53097 5.8944 3.53097 7.43198Z" fill="white"/>\n <path d="M15.0603 10.628C13.8603 10.628 12.9803 9.892 12.9803 8.372L13.6043 8.292C13.6043 9.492 14.1803 10.044 15.0603 10.044C15.8603 10.044 16.3243 9.612 16.3243 8.972C16.3243 8.252 15.8363 7.988 15.0603 7.788C13.7003 7.436 13.2523 6.996 13.2523 6.196C13.2523 5.396 13.9403 4.772 14.9803 4.772C16.0203 4.772 16.6923 5.396 16.6923 6.436L16.0683 6.516C16.0683 5.796 15.6203 5.356 14.9803 5.356C14.3403 5.356 13.8763 5.636 13.8763 6.196C13.8763 6.756 14.2843 7.004 15.0603 7.204C16.3723 7.548 16.9483 8.012 16.9483 8.972C16.9483 9.932 16.2603 10.628 15.0603 10.628ZM19.182 10.628C18.542 10.628 17.83 10.228 17.83 9.428C17.83 8.548 18.462 8.212 19.494 8.076C19.966 8.012 20.638 7.956 20.414 7.38C20.27 7.004 19.734 6.956 19.494 6.956C18.854 6.956 18.534 7.236 18.534 7.716L17.91 7.636C17.91 6.756 18.774 6.372 19.494 6.372C20.214 6.372 21.022 6.692 21.022 7.652V10.5H20.438V9.7C20.262 10.22 19.798 10.628 19.182 10.628ZM18.454 9.46C18.454 9.78 18.782 10.044 19.182 10.044C19.822 10.044 20.438 9.596 20.438 8.476V8.26C20.286 8.476 19.91 8.596 19.374 8.66C18.742 8.748 18.454 9.06 18.454 9.46ZM22.3044 10.5V4.82H22.9284V10.5H22.3044ZM25.6789 10.5C24.9909 10.5 24.6469 10.204 24.6469 9.508V7.084H23.9669V6.5H24.6469V5.292L25.1909 5.212V6.5H26.2309V7.084H25.1909V9.34C25.1909 9.836 25.3829 9.916 25.7749 9.916H26.2309V10.5H25.6789ZM27.7094 6.052C27.7094 5.116 28.0934 4.82 28.7814 4.82H29.3334V5.404H28.8774C28.4454 5.404 28.2934 5.484 28.2934 6.22V6.5H29.3334V7.084H28.2934V10.5H27.7094V7.084H27.0294V6.5H27.7094V6.052ZM30.2805 10.5V6.5H30.9045V10.5H30.2805ZM30.2165 5.86V5.108H30.9685V5.86H30.2165ZM33.7678 10.628C32.8078 10.628 32.0078 10.06 32.0078 9.02L32.5918 8.94C32.5918 9.66 33.2078 10.044 33.7678 10.044C34.3278 10.044 34.7678 9.86 34.7678 9.38C34.7678 8.9 34.4558 8.772 33.9998 8.708L33.2958 8.612C32.6638 8.524 32.2318 8.092 32.2318 7.532C32.2318 6.812 32.8478 6.372 33.7278 6.372C34.6078 6.372 35.1678 6.892 35.1678 7.612L34.5838 7.692C34.5838 7.212 34.2878 6.956 33.7278 6.956C33.2478 6.956 32.8558 7.132 32.8558 7.532C32.8558 7.852 33.0718 7.996 33.5438 8.068L34.1518 8.156C34.8558 8.26 35.3918 8.66 35.3918 9.38C35.3918 10.1 34.7278 10.628 33.7678 10.628ZM38.9252 7.868C38.9252 7.148 38.5812 6.956 38.1012 6.956C37.6212 6.956 36.9812 7.276 36.9812 8.636V10.5H36.3572V4.9H36.9812V7.364C37.1092 6.812 37.5652 6.372 38.3012 6.372C39.1812 6.372 39.5492 6.988 39.5492 7.868V10.5H38.9252V7.868Z" fill="white"/>\n </svg>\n ',t.appendChild(n),n.addEventListener("click",(t=>{var e;t.stopPropagation();const n=bt();"playing"===n.currentState&&n.pause();const i=null==(e=n.config)?void 0:e.token;i?window.open(`https://www.saltfish.ai/demos?clientId=${i}`,"_blank"):(console.warn("UIManager: No token available, falling back to saltfish.ai homepage"),window.open("https://www.saltfish.ai/","_blank"))}))}initializeButtonManagement(){this.playerElement&&this.videoManager?(this.storeUnsubscribe=vt.subscribe((t=>{this.updatePlayPauseButton(t.currentState)})),this.playButton=this.playerElement.querySelector(".sf-controls-container__play-button"),this.centerPlayButton=this.playerElement.querySelector(".sf-player__center-play-button"),this.centerPlayButton||this.createCenterPlayButton(),this.playButton||console.error("UIManager: Failed to find play button during initialization"),this.centerPlayButton):console.error("UIManager: Cannot initialize button management - missing player element or video manager")}displayPlaybackButtons(t){this.playbackButtonsVisible!==t&&(this.playbackButtonsVisible=t)}updatePlayPauseButton(t){this.playButton&&this.playButton.classList.add("sf-hidden"),!this.centerPlayButton&&this.playerElement&&(this.centerPlayButton=this.playerElement.querySelector(".sf-player__center-play-button"),this.centerPlayButton||this.createCenterPlayButton()),this.centerPlayButton&&("playing"===t||"completed"===t?(this.centerPlayButton.classList.remove("sf-player__center-play-button--visible"),this.centerPlayButton.classList.remove("sf-player__center-play-button--prominent")):(this.centerPlayButton.classList.add("sf-player__center-play-button--visible"),"autoplayBlocked"===t||"idleMode"===t?this.centerPlayButton.classList.add("sf-player__center-play-button--prominent"):this.centerPlayButton.classList.remove("sf-player__center-play-button--prominent")))}handleAutoplayFallbackInteraction(t){var e;const n=bt();if("autoplayBlocked"===n.currentState||"idleMode"===n.currentState)if(n.currentState,this.videoManager){this.videoManager.markUserInteraction(),this.videoManager.setMuted(!1);const t=this.videoManager.getVideoElement();t&&(t.loop=!1,t.currentTime=0)}else{const t=null==(e=this.playerElement)?void 0:e.querySelector(".sf-video-container__video");t&&(t.muted=!1,t.loop=!1,t.currentTime=0)}else this.videoManager&&this.videoManager.markUserInteraction()}createCenterPlayButton(){this.playerElement&&(this.centerPlayButton=document.createElement("button"),this.centerPlayButton.className="sf-player__center-play-button",this.centerPlayButton.innerHTML='\n <svg class="sf-player__center-play-button__play-icon" width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">\n <path d="M8 5v14l11-7z" fill="currentColor"/>\n </svg>\n <svg class="sf-player__center-play-button__pause-icon" width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">\n <path d="M6 4h4v16H6V4zm8 0h4v16h-4V4z" fill="currentColor"/>\n </svg>\n <svg class="sf-player__center-play-button__replay-icon" width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">\n <path d="M12 5V1L7 6l5 5V7c3.31 0 6 2.69 6 6s-2.69 6-6 6-6-2.69-6-6H4c0 4.42 3.58 8 8 8s8-3.58 8-8-3.58-8-8-8z" fill="currentColor"/>\n </svg>\n ',this.playerElement.appendChild(this.centerPlayButton),this.centerPlayButton.addEventListener("click",(t=>{t.stopPropagation(),t.preventDefault();const e=bt();this.handleAutoplayFallbackInteraction("center play button"),"paused"===e.currentState||"waitingForInteraction"===e.currentState||"completedWaitingForInteraction"===e.currentState||"autoplayBlocked"===e.currentState||"idleMode"===e.currentState||"error"===e.currentState?e.play():"playing"===e.currentState&&e.pause()})))}showCompactLabel(t){var e;if(!this.playerRoot||!t)return;this.hideCompactLabel();const n=bt();let i=(null==(e=n.playlistOptions)?void 0:e.position)||"bottom-right";if(n.currentStepId&&n.manifest){const t=n.manifest.steps.find((t=>t.id===n.currentStepId));(null==t?void 0:t.position)&&(i=t.position)}const s="bottom-right"===i?"sf-compact-label--left":"sf-compact-label--right";this.compactLabel=document.createElement("div"),this.compactLabel.className=`sf-compact-label ${s}`,this.compactLabel.textContent=t,this.compactLabel.style.cursor="pointer",this.compactLabel.style.pointerEvents="auto",this.compactLabel.addEventListener("click",(t=>{t.stopPropagation(),t.preventDefault();const e=bt();this.handleAutoplayFallbackInteraction("compact label"),"paused"!==e.currentState&&"waitingForInteraction"!==e.currentState&&"completedWaitingForInteraction"!==e.currentState&&"autoplayBlocked"!==e.currentState&&"idleMode"!==e.currentState&&"error"!==e.currentState||e.play()})),this.playerRoot.appendChild(this.compactLabel)}hideCompactLabel(){this.compactLabel&&this.compactLabel.parentNode&&(this.compactLabel.parentNode.removeChild(this.compactLabel),this.compactLabel=null)}reset(){this.minimizeButton&&(this.minimizeButton.destroy(),this.minimizeButton=null),this.exitButton&&(this.exitButton.destroy(),this.exitButton=null),this.playPauseButton&&(this.playPauseButton.destroy(),this.playPauseButton=null),this.errorDisplay&&(this.errorDisplay.destroy(),this.errorDisplay=null),this.loadingSpinner&&(this.loadingSpinner.destroy(),this.loadingSpinner=null),this.hideCompactLabel(),this.playerElement&&this.playerElement.parentNode&&this.playerElement.parentNode.removeChild(this.playerElement),this.playerRoot=null,this.playerElement=null}enablePlayButtonProminent(){this.centerPlayButton&&this.centerPlayButton.classList.add("sf-player__center-play-button--prominent")}disablePlayButtonProminent(){this.centerPlayButton&&this.centerPlayButton.classList.remove("sf-player__center-play-button--prominent")}destroy(){this.minimizeButton&&(this.minimizeButton.destroy(),this.minimizeButton=null),this.exitButton&&(this.exitButton.destroy(),this.exitButton=null),this.playPauseButton&&(this.playPauseButton.destroy(),this.playPauseButton=null),this.errorDisplay&&(this.errorDisplay.destroy(),this.errorDisplay=null),this.loadingSpinner&&(this.loadingSpinner.destroy(),this.loadingSpinner=null),this.storeUnsubscribe&&(this.storeUnsubscribe(),this.storeUnsubscribe=null),this.playbackButtonsVisible=!1,this.playButton=null,this.centerPlayButton=null,this.videoManager=null,this.shadowDOMManager.remove(),this.playerRoot=null,this.playerElement=null}}const ke=class t{constructor(t){e(this,"currentStepId",null),e(this,"stepTimeoutId",null),e(this,"destroyCallback",null),this.destroyCallback=t}update(t){const{currentStepId:e,currentState:n}=t;this.currentStepId;if(!("playing"===n||"waitingForInteraction"===n||"paused"===n||"autoplayBlocked"===n))return this.stepTimeoutId,void this.clearStepTimeout();const i=e!==this.currentStepId,s=null===this.stepTimeoutId;(i||s)&&(i&&this.currentStepId,this.setStepTimeout(e))}setStepTimeout(e){this.clearStepTimeout(),e&&(this.currentStepId=e,this.stepTimeoutId=window.setTimeout((()=>{this.destroyPlayer()}),t.STEP_TIMEOUT_MS))}clearStepTimeout(){null!==this.stepTimeoutId&&(this.currentStepId,window.clearTimeout(this.stepTimeoutId),this.stepTimeoutId=null)}setDestroyCallback(t){this.destroyCallback=t}destroyPlayer(){if(this.destroyCallback)try{this.destroyCallback()}catch(t){}}reset(){this.clearStepTimeout(),this.currentStepId=null}destroy(){this.clearStepTimeout(),this.currentStepId=null,this.destroyCallback=null}};e(ke,"STEP_TIMEOUT_MS",Pt);let Te=ke;class Ae{createManagers(){const t=gt.getInstance(),e=new fe(t),n=new Yt,i=new te,s=new we,r=new ge(s),a=new Ee(s,t),o=new be(s),l=new de,c=new pe,d=new ye,h=new ve,u=new Te((()=>{}));d.setTriggerManager(h);return{shadowDOMManager:n,videoManager:i,cursorManager:l,interactionManager:c,analyticsManager:r,sessionManager:e,transitionManager:d,triggerManager:h,abTestManager:o,eventManager:s,playlistManager:a,stepTimeoutManager:u,uiManager:new _e(n),storageManager:t}}resetManagers(t){try{t.videoManager.reset&&t.videoManager.reset(),t.cursorManager.reset&&t.cursorManager.reset(),t.interactionManager.reset&&t.interactionManager.reset(),t.transitionManager.reset&&t.transitionManager.reset(),t.uiManager.reset&&t.uiManager.reset(),t.stepTimeoutManager.reset&&t.stepTimeoutManager.reset()}catch(e){console.error("ManagerFactory: Error resetting managers:",e)}}destroyManagers(t){try{t.transitionManager.destroy(),t.triggerManager.destroy(),t.videoManager.destroy(),t.cursorManager.destroy(),t.interactionManager.destroy(),t.analyticsManager.destroy(),t.sessionManager.destroy(),t.playlistManager.destroy(),t.stepTimeoutManager.destroy(),t.uiManager.destroy()}catch(e){console.error("ManagerFactory: Error destroying managers:",e)}}}const ze=class t{constructor(){if(e(this,"playerInitializationService"),e(this,"userManagementService"),e(this,"playlistOrchestrator"),e(this,"stateMachineActionHandler"),e(this,"managerOrchestrator"),e(this,"managerFactory"),e(this,"isInitialized",!1),t.instance)throw new Error("SaltfishPlayer is a singleton. Use getInstance()");this.managerFactory=new Ae;const n=this.managerFactory.createManagers();this.playerInitializationService=new Lt(n),this.userManagementService=new Ot(n),this.playlistOrchestrator=new Ft(n),this.stateMachineActionHandler=new Ut(n),this.managerOrchestrator=new $t(n),this.userManagementService.setPlayerInitializationService(this.playerInitializationService),this.playerInitializationService.setUserManagementService(this.userManagementService),this.playerInitializationService.setPlaylistOrchestrator(this.playlistOrchestrator),this.playlistOrchestrator.setUserManagementService(this.userManagementService),this.playlistOrchestrator.setManagerOrchestrator(this.managerOrchestrator),this.playlistOrchestrator.setPlayerInitializationService(this.playerInitializationService),this.playlistOrchestrator.setStateMachineActionHandler(this.stateMachineActionHandler),this.stateMachineActionHandler.setDestroyCallback((()=>this.destroy())),n.stepTimeoutManager.setDestroyCallback((()=>this.destroy())),vt.subscribe((()=>this.managerOrchestrator.handleStoreChanges())),this.stateMachineActionHandler.registerStateMachineActions()}static getInstance(){return t.instance||(t.instance=new t),t.instance}getSessionId(){return this.managerOrchestrator.getManagers().sessionManager.getSessionId()}getRunId(){return this.managerOrchestrator.getManagers().sessionManager.getCurrentRunId()}async initialize(t){if(this.isInitialized)console.warn("Saltfish playlist Player is already initialized");else try{await this.playerInitializationService.initialize(t),this.isInitialized=!0,this.managerOrchestrator.setInitialized(!0),"undefined"!=typeof window&&(window._saltfishPlayer=this,window._cursorManager=this.getManagers().cursorManager)}catch(e){throw e}}identifyUser(t,e){this.userManagementService.identifyUser(t,e)}async identifyAnonymous(t){await this.userManagementService.identifyAnonymous(t)}async startPlaylist(t,e){await this.playlistOrchestrator.startPlaylist(t,e)}resetPlaylist(){this.playlistOrchestrator.resetPlaylist()}destroy(){if(this.isInitialized)try{this.managerOrchestrator.destroyAll(),this.isInitialized=!1}catch(t){console.error("SaltfishPlayer: Error during destruction:",t),this.isInitialized=!1}else console.warn("Saltfish playlist Player is not initialized")}on(t,e){this.managerOrchestrator.getManagers().eventManager.on(t,e)}off(t,e){return this.managerOrchestrator.getManagers().eventManager.off(t,e)}get videoManager(){return this.managerOrchestrator.getManagers().videoManager}getManagers(){return this.managerOrchestrator.getManagers()}getServices(){return{playerInitializationService:this.playerInitializationService,userManagementService:this.userManagementService,playlistOrchestrator:this.playlistOrchestrator,stateMachineActionHandler:this.stateMachineActionHandler,managerOrchestrator:this.managerOrchestrator}}};e(ze,"instance",null);let Le=ze;const Ve=Object.freeze(Object.defineProperty({__proto__:null,SaltfishPlayer:Le},Symbol.toStringTag,{value:"Module"})),Oe="0.3.65";const De=function(){const t=Le.getInstance();let e=!1,n=!1,i=null;const s=[],r={init:r=>{if(n)return q("Saltfish already initialized"),Promise.resolve();if(e&&i)return i;const a={enableAnalytics:!0,..."string"==typeof r?{token:r}:r};return q(`Saltfish initialized: analytics=${a.enableAnalytics}`),e=!0,i=t.initialize(a).then((()=>(n=!0,e=!1,(async()=>{if(0!==s.length)for(;s.length>0;){const e=s.shift();if(e)try{await e()}catch(t){G("Error executing queued command:",t)}}})()))).catch((t=>{throw e=!1,t("Saltfish initialization failed:",t),t})),i},identify:(i,r)=>{n||!e?t.identifyUser(i,r):s.push((async()=>{t.identifyUser(i,r)}))},identifyAnonymous:i=>{n||!e?t.identifyAnonymous(i):s.push((async()=>{t.identifyAnonymous(i)}))},startPlaylist:(r,a)=>!n&&e?new Promise(((e,n)=>{s.push((async()=>{try{await t.startPlaylist(r,a),e()}catch(i){n(i)}})),i&&i.catch(n)})):t.startPlaylist(r,a),on:(e,n)=>{t.on(e,n)},off:(e,n)=>t.off(e,n),resetPlaylist:()=>{n||e?n||!e?t.resetPlaylist():s.push((async()=>{t.resetPlaylist()})):Z("Cannot reset playlist - Saltfish not initialized")},destroy:()=>{n||e?(e||(n=!1,e=!1,i=null,s.length=0),t.destroy(),n=!1,e=!1,i=null):Z("Cannot destroy - Saltfish not initialized")},getSessionId:()=>t.getSessionId(),getRunId:()=>t.getRunId(),version:()=>Oe};return r.__dev__={getDeviceInfo:()=>Xt.getDeviceInfo()},r}();if("undefined"!=typeof window&&"undefined"!=typeof document&&!document.querySelector('meta[name="saltfish-player-loaded"]')){const t=document.createElement("meta");t.name="saltfish-player-loaded",t.content="true",document.head.appendChild(t)}return"undefined"!=typeof window&&(window.saltfish=De),De}));
|
|
7
|
+
!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):(t="undefined"!=typeof globalThis?globalThis:t||self).SaltfishplaylistPlayer=e()}(this,(function(){"use strict";var t=Object.defineProperty,e=(e,n,i)=>((e,n,i)=>n in e?t(e,n,{enumerable:!0,configurable:!0,writable:!0,value:i}):e[n]=i)(e,"symbol"!=typeof n?n+"":n,i);const n={},i=t=>{let e;const i=new Set,s=(t,n)=>{const s="function"==typeof t?t(e):t;if(!Object.is(s,e)){const t=e;e=(null!=n?n:"object"!=typeof s||null===s)?s:Object.assign({},e,s),i.forEach((n=>n(e,t)))}},r=()=>e,a={setState:s,getState:r,getInitialState:()=>o,subscribe:t=>(i.add(t),()=>i.delete(t)),destroy:()=>{"production"!==(n?"production":void 0)&&console.warn("[DEPRECATED] The `destroy` method will be unsupported in a future version. Instead use unsubscribe function returned by subscribe. Everything will be garbage-collected if store is garbage-collected."),i.clear()}},o=e=t(s,r,a);return a};var s=Symbol.for("immer-nothing"),r=Symbol.for("immer-draftable"),a=Symbol.for("immer-state");function o(t,...e){throw new Error(`[Immer] minified error nr: ${t}. Full error at: https://bit.ly/3cXEKWf`)}var l=Object.getPrototypeOf;function c(t){return!!t&&!!t[a]}function d(t){var e;return!!t&&(u(t)||Array.isArray(t)||!!t[r]||!!(null==(e=t.constructor)?void 0:e[r])||y(t)||v(t))}var h=Object.prototype.constructor.toString();function u(t){if(!t||"object"!=typeof t)return!1;const e=l(t);if(null===e)return!0;const n=Object.hasOwnProperty.call(e,"constructor")&&e.constructor;return n===Object||"function"==typeof n&&Function.toString.call(n)===h}function p(t,e){0===m(t)?Reflect.ownKeys(t).forEach((n=>{e(n,t[n],t)})):t.forEach(((n,i)=>e(i,n,t)))}function m(t){const e=t[a];return e?e.type_:Array.isArray(t)?1:y(t)?2:v(t)?3:0}function g(t,e){return 2===m(t)?t.has(e):Object.prototype.hasOwnProperty.call(t,e)}function f(t,e,n){const i=m(t);2===i?t.set(e,n):3===i?t.add(n):t[e]=n}function y(t){return t instanceof Map}function v(t){return t instanceof Set}function b(t){return t.copy_||t.base_}function w(t,e){if(y(t))return new Map(t);if(v(t))return new Set(t);if(Array.isArray(t))return Array.prototype.slice.call(t);const n=u(t);if(!0===e||"class_only"===e&&!n){const e=Object.getOwnPropertyDescriptors(t);delete e[a];let n=Reflect.ownKeys(e);for(let i=0;i<n.length;i++){const s=n[i],r=e[s];!1===r.writable&&(r.writable=!0,r.configurable=!0),(r.get||r.set)&&(e[s]={configurable:!0,writable:!0,enumerable:r.enumerable,value:t[s]})}return Object.create(l(t),e)}{const e=l(t);if(null!==e&&n)return{...t};const i=Object.create(e);return Object.assign(i,t)}}function S(t,e=!1){return x(t)||c(t)||!d(t)||(m(t)>1&&(t.set=t.add=t.clear=t.delete=E),Object.freeze(t),e&&Object.entries(t).forEach((([t,e])=>S(e,!0)))),t}function E(){o(2)}function x(t){return Object.isFrozen(t)}var M,I={};function P(t){const e=I[t];return e||o(0),e}function C(){return M}function _(t,e){e&&(P("Patches"),t.patches_=[],t.inversePatches_=[],t.patchListener_=e)}function k(t){T(t),t.drafts_.forEach(z),t.drafts_=null}function T(t){t===M&&(M=t.parent_)}function A(t){return M={drafts_:[],parent_:M,immer_:t,canAutoFreeze_:!0,unfinalizedDrafts_:0}}function z(t){const e=t[a];0===e.type_||1===e.type_?e.revoke_():e.revoked_=!0}function L(t,e){e.unfinalizedDrafts_=e.drafts_.length;const n=e.drafts_[0];return void 0!==t&&t!==n?(n[a].modified_&&(k(e),o(4)),d(t)&&(t=V(e,t),e.parent_||D(e,t)),e.patches_&&P("Patches").generateReplacementPatches_(n[a].base_,t,e.patches_,e.inversePatches_)):t=V(e,n,[]),k(e),e.patches_&&e.patchListener_(e.patches_,e.inversePatches_),t!==s?t:void 0}function V(t,e,n){if(x(e))return e;const i=e[a];if(!i)return p(e,((s,r)=>O(t,i,e,s,r,n))),e;if(i.scope_!==t)return e;if(!i.modified_)return D(t,i.base_,!0),i.base_;if(!i.finalized_){i.finalized_=!0,i.scope_.unfinalizedDrafts_--;const e=i.copy_;let s=e,r=!1;3===i.type_&&(s=new Set(e),e.clear(),r=!0),p(s,((s,a)=>O(t,i,e,s,a,n,r))),D(t,e,!1),n&&t.patches_&&P("Patches").generatePatches_(i,n,t.patches_,t.inversePatches_)}return i.copy_}function O(t,e,n,i,s,r,a){if(c(s)){const a=V(t,s,r&&e&&3!==e.type_&&!g(e.assigned_,i)?r.concat(i):void 0);if(f(n,i,a),!c(a))return;t.canAutoFreeze_=!1}else a&&n.add(s);if(d(s)&&!x(s)){if(!t.immer_.autoFreeze_&&t.unfinalizedDrafts_<1)return;V(t,s),e&&e.scope_.parent_||"symbol"==typeof i||!Object.prototype.propertyIsEnumerable.call(n,i)||D(t,s)}}function D(t,e,n=!1){!t.parent_&&t.immer_.autoFreeze_&&t.canAutoFreeze_&&S(e,n)}var F={get(t,e){if(e===a)return t;const n=b(t);if(!g(n,e))return function(t,e,n){var i;const s=N(e,n);return s?"value"in s?s.value:null==(i=s.get)?void 0:i.call(t.draft_):void 0}(t,n,e);const i=n[e];return t.finalized_||!d(i)?i:i===U(t.base_,e)?(H(t),t.copy_[e]=$(i,t)):i},has:(t,e)=>e in b(t),ownKeys:t=>Reflect.ownKeys(b(t)),set(t,e,n){const i=N(b(t),e);if(null==i?void 0:i.set)return i.set.call(t.draft_,n),!0;if(!t.modified_){const i=U(b(t),e),o=null==i?void 0:i[a];if(o&&o.base_===n)return t.copy_[e]=n,t.assigned_[e]=!1,!0;if(((s=n)===(r=i)?0!==s||1/s==1/r:s!=s&&r!=r)&&(void 0!==n||g(t.base_,e)))return!0;H(t),R(t)}var s,r;return t.copy_[e]===n&&(void 0!==n||e in t.copy_)||Number.isNaN(n)&&Number.isNaN(t.copy_[e])||(t.copy_[e]=n,t.assigned_[e]=!0),!0},deleteProperty:(t,e)=>(void 0!==U(t.base_,e)||e in t.base_?(t.assigned_[e]=!1,H(t),R(t)):delete t.assigned_[e],t.copy_&&delete t.copy_[e],!0),getOwnPropertyDescriptor(t,e){const n=b(t),i=Reflect.getOwnPropertyDescriptor(n,e);return i?{writable:!0,configurable:1!==t.type_||"length"!==e,enumerable:i.enumerable,value:n[e]}:i},defineProperty(){o(11)},getPrototypeOf:t=>l(t.base_),setPrototypeOf(){o(12)}},B={};function U(t,e){const n=t[a];return(n?b(n):t)[e]}function N(t,e){if(!(e in t))return;let n=l(t);for(;n;){const t=Object.getOwnPropertyDescriptor(n,e);if(t)return t;n=l(n)}}function R(t){t.modified_||(t.modified_=!0,t.parent_&&R(t.parent_))}function H(t){t.copy_||(t.copy_=w(t.base_,t.scope_.immer_.useStrictShallowCopy_))}p(F,((t,e)=>{B[t]=function(){return arguments[0]=arguments[0][0],e.apply(this,arguments)}})),B.deleteProperty=function(t,e){return B.set.call(this,t,e,void 0)},B.set=function(t,e,n){return F.set.call(this,t[0],e,n,t[0])};function $(t,e){const n=y(t)?P("MapSet").proxyMap_(t,e):v(t)?P("MapSet").proxySet_(t,e):function(t,e){const n=Array.isArray(t),i={type_:n?1:0,scope_:e?e.scope_:C(),modified_:!1,finalized_:!1,assigned_:{},parent_:e,base_:t,draft_:null,copy_:null,revoke_:null,isManual_:!1};let s=i,r=F;n&&(s=[i],r=B);const{revoke:a,proxy:o}=Proxy.revocable(s,r);return i.draft_=o,i.revoke_=a,o}(t,e);return(e?e.scope_:C()).drafts_.push(n),n}function Y(t){if(!d(t)||x(t))return t;const e=t[a];let n;if(e){if(!e.modified_)return e.base_;e.finalized_=!0,n=w(t,e.scope_.immer_.useStrictShallowCopy_)}else n=w(t,!0);return p(n,((t,e)=>{f(n,t,Y(e))})),e&&(e.finalized_=!1),n}var X=new class{constructor(t){this.autoFreeze_=!0,this.useStrictShallowCopy_=!1,this.produce=(t,e,n)=>{if("function"==typeof t&&"function"!=typeof e){const n=e;e=t;const i=this;return function(t=n,...s){return i.produce(t,(t=>e.call(this,t,...s)))}}let i;if("function"!=typeof e&&o(6),void 0!==n&&"function"!=typeof n&&o(7),d(t)){const s=A(this),r=$(t,void 0);let a=!0;try{i=e(r),a=!1}finally{a?k(s):T(s)}return _(s,n),L(i,s)}if(!t||"object"!=typeof t){if(i=e(t),void 0===i&&(i=t),i===s&&(i=void 0),this.autoFreeze_&&S(i,!0),n){const e=[],s=[];P("Patches").generateReplacementPatches_(t,i,e,s),n(e,s)}return i}o(1)},this.produceWithPatches=(t,e)=>{if("function"==typeof t)return(e,...n)=>this.produceWithPatches(e,(e=>t(e,...n)));let n,i;return[this.produce(t,e,((t,e)=>{n=t,i=e})),n,i]},"boolean"==typeof(null==t?void 0:t.autoFreeze)&&this.setAutoFreeze(t.autoFreeze),"boolean"==typeof(null==t?void 0:t.useStrictShallowCopy)&&this.setUseStrictShallowCopy(t.useStrictShallowCopy)}createDraft(t){d(t)||o(8),c(t)&&(t=function(t){c(t)||o(10);return Y(t)}(t));const e=A(this),n=$(t,void 0);return n[a].isManual_=!0,T(e),n}finishDraft(t,e){const n=t&&t[a];n&&n.isManual_||o(9);const{scope_:i}=n;return _(i,e),L(void 0,i)}setAutoFreeze(t){this.autoFreeze_=t}setUseStrictShallowCopy(t){this.useStrictShallowCopy_=t}applyPatches(t,e){let n;for(n=e.length-1;n>=0;n--){const i=e[n];if(0===i.path.length&&"replace"===i.op){t=i.value;break}}n>-1&&(e=e.slice(n+1));const i=P("Patches").applyPatches_;return c(t)?i(t,e):this.produce(t,(t=>i(t,e)))}},W=X.produce;X.produceWithPatches.bind(X),X.setAutoFreeze.bind(X),X.setUseStrictShallowCopy.bind(X),X.applyPatches.bind(X),X.createDraft.bind(X),X.finishDraft.bind(X);const j=t=>(e,n,i)=>(i.setState=(t,n,...i)=>{const s="function"==typeof t?W(t):t;return e(s,n,...i)},t(i.setState,n,i));function q(t,e){void 0!==e?console.info(t,e):console.info(t)}function Z(t,e){console.warn(t)}function G(t,e){void 0!==e?console.error(t,e):console.error(t)}class K{constructor(t,n){e(this,"currentState"),e(this,"config"),e(this,"context"),e(this,"actionHandlers",{}),this.config=t,this.currentState=t.initial,this.context=n,this.setupDefaultActions(),this.runEntryActions(this.currentState)}setupDefaultActions(){this.actionHandlers={...this.actionHandlers,logStateEntry:t=>{this.currentState},logErrorEvent:(t,e)=>{"ERROR"===(null==e?void 0:e.type)&&e.error.message},logStepTransition:(t,e)=>{"TRANSITION_TO_STEP"===(null==e?void 0:e.type)&&e.step.id},logErrorRecovery:()=>{}}}registerActions(t){this.actionHandlers={...this.actionHandlers,...t},Object.keys(t).join(", ")}executeAction(t,e){if("string"==typeof t){const n=this.actionHandlers[t];n&&n(this.context,e)}else t(this.context,e)}send(t){const e=this.config.states[this.currentState].on[t.type];if(!e)return t.type,this.currentState,this.currentState;this.currentState,e.target,t.type,this.runExitActions(this.currentState),this.updateContextFromEvent(t),e.actions&&e.actions.forEach((e=>this.executeAction(e,t)));this.currentState;return this.currentState=e.target,this.runEntryActions(this.currentState),this.currentState,this.currentState}updateContextFromEvent(t){"TRANSITION_TO_STEP"===t.type||"MANIFEST_LOADED"===t.type||"VIDEO_FINISHED_WAIT"===t.type?this.context.currentStep=t.step:"ERROR"===t.type&&(this.context.error=t.error)}getState(){return this.currentState}getContext(){return this.context}updateContext(t){const e=t(this.context);this.context={...this.context,...e}}runEntryActions(t){const e=this.config.states[t];e.entry&&e.entry.forEach((t=>this.executeAction(t)))}runExitActions(t){const e=this.config.states[t];e.exit&&e.exit.forEach((t=>this.executeAction(t)))}}const J={initial:"idle",states:{idle:{on:{INITIALIZE:{target:"idle"},LOAD_MANIFEST:{target:"loading"}},entry:["logStateEntry"]},loading:{on:{MANIFEST_LOADED:{target:"paused"},ERROR:{target:"error",actions:["logErrorEvent"]}},entry:["logStateEntry","showLoadingState"],exit:["hideLoadingState"]},playing:{on:{PAUSE:{target:"paused"},MINIMIZE:{target:"minimized"},VIDEO_FINISHED_WAIT:{target:"waitingForInteraction"},AUTOPLAY_FALLBACK:{target:"autoplayBlocked"},TRANSITION_TO_STEP:{target:"playing",actions:["logStepTransition"]},ERROR:{target:"error"},COMPLETE_PLAYLIST:{target:"completed"},COMPLETE_PLAYLIST_WAITING_FOR_INTERACTION:{target:"completedWaitingForInteraction"}},entry:["logStateEntry","startVideoPlayback","showVideoControls","hidePlayButton"],exit:["pauseVideoPlayback"]},paused:{on:{PLAY:{target:"playing"},START_IDLE_MODE:{target:"idleMode"},MINIMIZE:{target:"minimized"},TRANSITION_TO_STEP:{target:"playing",actions:["logStepTransition"]}},entry:["logStateEntry","pauseVideoPlayback","showPlayButton"]},minimized:{on:{MAXIMIZE:{target:"playing"},EXIT:{target:"closing"}},entry:["logStateEntry","pauseVideoPlayback"]},waitingForInteraction:{on:{PLAY:{target:"playing"},PAUSE:{target:"paused"},MINIMIZE:{target:"minimized"},COMPLETE_PLAYLIST:{target:"completed"},COMPLETE_PLAYLIST_WAITING_FOR_INTERACTION:{target:"completedWaitingForInteraction"},TRANSITION_TO_STEP:{target:"playing",actions:["logStepTransition"]}},entry:["logStateEntry","showPlayButton"]},autoplayBlocked:{on:{PLAY:{target:"playing"},TRANSITION_TO_STEP:{target:"playing"},MINIMIZE:{target:"minimized"}},entry:["logStateEntry","enterCompactMode","startMutedLoopedVideo","hideVideoControls","showPlayButton","enablePlayButtonProminent"],exit:["disablePlayButtonProminent","showVideoControls","exitCompactMode"]},idleMode:{on:{PLAY:{target:"playing"},TRANSITION_TO_STEP:{target:"playing"},MINIMIZE:{target:"minimized"}},entry:["logStateEntry","startIdleModeVideo","hideVideoControls","showPlayButton","enablePlayButtonProminent"],exit:["disablePlayButtonProminent","showVideoControls","exitCompactMode"]},error:{on:{INITIALIZE:{target:"idle"},PLAY:{target:"playing",actions:["logErrorRecovery"]},AUTOPLAY_FALLBACK:{target:"autoplayBlocked"}},entry:["logStateEntry","handleError","showPlayButton"],exit:["hideError"]},completedWaitingForInteraction:{on:{COMPLETE_PLAYLIST:{target:"completed"},INITIALIZE:{target:"idle"},TRANSITION_TO_STEP:{target:"playing",actions:["logStepTransition"]},PLAY:{target:"playing"},MINIMIZE:{target:"minimized"}},entry:["logStateEntry","showPlayButton"]},completed:{on:{INITIALIZE:{target:"idle"}},entry:["logStateEntry","trackPlaylistComplete"]},closing:{on:{},entry:["logStateEntry","triggerPlaylistDismissed"]}}},Q="saltfish_progress",tt="saltfish_session",et="saltfish_anonymous_user_data",nt="saltfish_pending_navigation",it="https://player.saltfish.ai",st="https://studio-api.saltfish.ai/studio/flows2/share",rt="sf-player",at="sf-player--minimized",ot="sf-controls-container",lt="sf-player__logo",ct="sf-error-display",dt="sf-error-display--visible",ht="sf-error-display__content",ut="sf-error-display__message",pt="sf-loading-spinner",mt=class t{constructor(){e(this,"isLocalStorageAvailable"),this.isLocalStorageAvailable=this.checkLocalStorageAvailability(),this.isLocalStorageAvailable}static getInstance(){return t.instance||(t.instance=new t),t.instance}static resetInstance(){t.instance=null}checkLocalStorageAvailability(){if("undefined"==typeof window)return!1;try{const t="__storage_test__";return localStorage.setItem(t,"test"),localStorage.removeItem(t),!0}catch(t){return!1}}safeGetItem(t){if(!this.isLocalStorageAvailable)return null;try{const e=localStorage.getItem(t);return null===e?null:JSON.parse(e)}catch(e){return this.safeClearItem(t),null}}safeSetItem(t,e){if(!this.isLocalStorageAvailable)return!1;try{return localStorage.setItem(t,JSON.stringify(e)),!0}catch(n){if(n instanceof DOMException&&22===n.code){this.clearOldData();try{return localStorage.setItem(t,JSON.stringify(e)),!0}catch(i){}}return!1}}safeClearItem(t){if(this.isLocalStorageAvailable)try{localStorage.removeItem(t)}catch(e){}}clearOldData(){this.safeClearItem(tt)}getProgress(t){const e=this.safeGetItem(Q);return e?t&&e.userId&&e.userId!==t?(e.userId,null):e.playlists||null:null}setProgress(t,e){const n={userId:e,playlists:t};return this.safeSetItem(Q,n)}clearProgress(){this.safeClearItem(Q)}getSession(){return this.safeGetItem(tt)}setSession(t){return this.safeSetItem(tt,t)}clearSession(){this.safeClearItem(tt)}getAnonymousUserData(){return this.safeGetItem(et)}setAnonymousUserData(t){return this.safeSetItem(et,t)}clearAnonymousUserData(){this.safeClearItem(et)}getPendingNavigation(){return this.safeGetItem(nt)}setPendingNavigation(t){return t.nextStepId,t.urlPattern,this.safeSetItem(nt,t)}clearPendingNavigation(){this.safeClearItem(nt)}clearAll(){this.clearProgress(),this.clearSession(),this.clearAnonymousUserData(),this.clearPendingNavigation()}};e(mt,"instance",null);let gt=mt;const ft=gt.getInstance(),yt=i(j(((t,e)=>{let n=new K(J,{currentStep:null,error:null});const i=t=>n.send(t);return{config:null,user:null,userData:null,currentState:n.getState(),manifest:null,currentStepId:null,isMinimized:!1,position:null,progress:{},error:null,playlistOptions:null,backendPlaylists:[],isAdmin:!1,isMuted:!1,abTests:[],abTestAssignments:{},initialize:async e=>{t((t=>{t.config=e,t.currentState=i({type:"INITIALIZE"})}))},setPlaylistOptions:e=>{t((t=>{if(t.playlistOptions=e,e.position){const n="bottom-left"===e.position||"bottom-right"===e.position?e.position:"bottom-right";t.position={x:0,y:0},t.playlistOptions={...e,position:n}}}))},identifyUser:(e,n)=>{const i={id:e,...n};t((t=>{t.user=i}))},setUserData:e=>{t((t=>{t.userData=e}))},setManifest:(e,n)=>{t((t=>{t.manifest=e,t.currentStepId=n;const s=e.steps.find((t=>t.id===n));t.currentState=i(s?{type:"MANIFEST_LOADED",step:s}:{type:"ERROR",error:new Error(`Start step '${n}' not found in manifest`)})}))},play:()=>{const{currentState:n}=e();t((t=>{t.currentState=i({type:"PLAY"})}))},pause:()=>{const{currentState:n}=e();t((t=>{t.currentState=i({type:"PAUSE"})}))},minimize:()=>{const{currentState:n}=e();t((t=>{"playing"===t.currentState&&(t.currentState=i({type:"PAUSE"})),t.currentState=i({type:"MINIMIZE"}),t.isMinimized=!0}))},maximize:()=>{t((t=>{t.currentState=i({type:"MAXIMIZE"}),t.isMinimized=!1}))},goToStep:n=>{const{manifest:s}=e();if("completed"!==n){if(s&&s.steps.some((t=>t.id===n))){const e=s.steps.find((t=>t.id===n));t((t=>{var r,a,o;t.currentStepId=n,e&&(t.currentState=i({type:"TRANSITION_TO_STEP",step:e}),(t.position||(null==(r=t.playlistOptions)?void 0:r.position))&&(t.position={x:0,y:0})),t.progress[s.id]={...t.progress[s.id],lastStepId:n,lastVisited:(new Date).toISOString()};if((null==(a=t.playlistOptions)?void 0:a.persistence)??!0){const e=null==(o=t.user)?void 0:o.id;ft.setProgress(t.progress,e)}}))}}else t((t=>{t.currentState=i({type:"COMPLETE_PLAYLIST"})}))},reset:()=>{t((t=>{t.config=null,t.user=null,t.userData=null,t.currentState=n.getState(),t.manifest=null,t.currentStepId=null,t.isMinimized=!1,t.position=null,t.progress={},t.error=null,n=new K(J,{currentStep:null,error:null})}))},setError:e=>{t((t=>{t.currentState=i({type:"ERROR",error:e}),t.error=e}))},setAutoplayFallback:()=>{t((t=>{t.currentState=i({type:"AUTOPLAY_FALLBACK"})}))},setIdleMode:()=>{t((t=>{t.currentState=i({type:"START_IDLE_MODE"})}))},setMuted:e=>{t((t=>{t.isMuted=e}))},setBackendPlaylists:e=>{t((t=>{t.backendPlaylists=e}))},setIsAdmin:e=>{t((t=>{t.isAdmin=e}))},completePlaylist:()=>{t((t=>{t.currentState=i({type:"COMPLETE_PLAYLIST"})}))},resetForNewPlaylist:()=>{t((t=>{const e=t.config,i=t.user,s=t.userData,r=t.progress;t.manifest=null,t.currentStepId=null,t.isMinimized=!1,t.position=null,t.error=null,t.playlistOptions=null,n=new K(J,{currentStep:null,error:null}),t.currentState=n.getState(),t.config=e,t.user=i,t.userData=s,t.progress=r}))},loadPlaylistProgress:(e,n)=>{t((t=>{t.progress[e]=n}))},registerStateMachineActions:t=>{n.registerActions(t)},sendStateMachineEvent:e=>{t((t=>{t.currentState=i(e)}))},updateProgressWithCompletion:(e,n)=>{t((t=>{var s,r;t.currentState=i({type:"COMPLETE_PLAYLIST_WAITING_FOR_INTERACTION"}),t.progress[e]={...t.progress[e],lastStepId:n,lastVisited:(new Date).toISOString(),completedWaitingForInteraction:!0};if((null==(s=t.playlistOptions)?void 0:s.persistence)??!0){const e=null==(r=t.user)?void 0:r.id;ft.setProgress(t.progress,e)}}))},setABTests:e=>{t((t=>{t.abTests=e}))},setABTestAssignments:e=>{t((t=>{t.abTestAssignments=e}))},getFilteredPlaylists:()=>{const t=e(),n=t.backendPlaylists||[],i=t.abTests||[],s=t.abTestAssignments||{};if(0===i.length)return n;const r=new Set;for(const e of i){const t=s[e.id];t&&t.assigned||r.add(e.playlistId)}return n.filter((t=>!r.has(t.id)))}}}))),vt={getState:()=>yt.getState(),setState:yt.setState,subscribe:yt.subscribe,destroy:yt.destroy};function bt(){try{return vt.getState()}catch(t){throw new Error(`[storeUtils] Failed to access Saltfish store: ${t}`)}}function wt(t){if(!t)return null;if(t.lastProgressAt&&"object"==typeof t.lastProgressAt&&"_seconds"in t.lastProgressAt&&"_nanoseconds"in t.lastProgressAt){const e=t.lastProgressAt;return 1e3*e._seconds+Math.floor(e._nanoseconds/1e6)}return t.timestamp&&"number"==typeof t.timestamp?t.timestamp:t.lastProgressAt&&"number"==typeof t.lastProgressAt?t.lastProgressAt:null}function St(t,e=6e3){const n=wt(t);if(!n)return{isValid:!1,ageMs:null,timestampMs:null};const i=Date.now()-n;return{isValid:i<=e,ageMs:i,timestampMs:n}}class Et{static handle(t,e={},n={}){var i;const s={...this.DEFAULT_OPTIONS,...n},r=this.normalizeError(t,e);if(s.shouldLog&&this.logError(r,e,s.severity),s.shouldUpdateStore&&this.updateStore(r),s.shouldTriggerEvent&&this.triggerErrorEvent(r,e,null==(i=e.component)?void 0:i.toLowerCase()),s.shouldDestroy&&this.destroyPlayer(),s.shouldThrow)throw r;return r}static handleInitializationError(t,e={}){return this.handle(t,{...e,component:"Initialization"},{severity:"critical",shouldLog:!0,shouldUpdateStore:!0,shouldDestroy:!0,shouldThrow:!0})}static handlePlaylistError(t,e={}){return this.handle(t,{...e,component:"Playlist"},{severity:"error",shouldLog:!0,shouldUpdateStore:!0,shouldTriggerEvent:!0})}static handleVideoError(t,e={}){return this.handle(t,{...e,component:"Video"},{severity:"error",shouldLog:!0,shouldUpdateStore:!0,shouldTriggerEvent:!0})}static handleNetworkError(t,e={}){return this.handle(t,{...e,component:"Network"},{severity:"warning",shouldLog:!0,shouldTriggerEvent:!0})}static handleWarning(t,e={}){return this.handle(t,e,{severity:"warning",shouldLog:!0,shouldThrow:!1})}static handleCleanupError(t,e={}){return this.handle(t,{...e,component:"Cleanup"},{severity:"warning",shouldLog:!0,shouldThrow:!1})}static normalizeError(t,e){if(t instanceof Error)return t;if("string"==typeof t)return new Error(t);const n=String(t&&"object"==typeof t&&"message"in t?t.message:t);return new Error(`Unknown error in ${e.component||"application"}: ${n}`)}static formatErrorMessage(t,e){const n=[];return e.component&&n.push(`[${e.component}]`),e.method&&n.push(`${e.method}:`),n.push(t.message),n.join(" ")}static logError(t,e,n){const i=this.formatErrorMessage(t,e),s={error:{name:t.name,message:t.message,stack:t.stack},context:e,severity:n,timestamp:(new Date).toISOString()};switch(n){case"info":break;case"warning":console.warn(i,s);break;case"error":case"critical":console.error(i,s)}}static updateStore(t){try{bt().setError(t)}catch(e){console.error("Failed to update store with error:",e)}}static triggerErrorEvent(t,e,n){var i,s;try{const r=bt();if("undefined"!=typeof window&&window._saltfishPlayer){const a=window._saltfishPlayer;a&&a.eventManager&&a.eventManager.trigger("error",{timestamp:Date.now(),playlistId:e.playlistId||(null==(i=r.manifest)?void 0:i.id),stepId:e.stepId||r.currentStepId,error:t,errorType:e.errorType||n||(null==(s=e.component)?void 0:s.toLowerCase())||"unknown"})}}catch(r){console.error("Failed to trigger error event:",r)}}static destroyPlayer(){try{if("undefined"!=typeof window&&window._saltfishPlayer){const t=window._saltfishPlayer;t&&"function"==typeof t.destroy&&t.destroy()}}catch(t){console.error("Failed to destroy player during error handling:",t)}}static createError(t,e={}){const n=new Error(this.formatErrorMessage(new Error(t),e));return e.component&&(n.component=e.component),e.method&&(n.method=e.method),e.playlistId&&(n.playlistId=e.playlistId),e.stepId&&(n.stepId=e.stepId),n}static isRecoverable(t){if(t.message.includes("fetch")||t.message.includes("network")||t.message.includes("timeout"))return!0;return[/autoplay.*blocked/i,/video.*failed.*load/i,/manifest.*not.*found/i].some((e=>e.test(t.message)))}static async safeExecute(t,e={},n={}){try{return await t()}catch(i){return this.handle(i,e,n),null}}}e(Et,"DEFAULT_OPTIONS",{severity:"error",shouldLog:!0,shouldThrow:!1,shouldUpdateStore:!1,shouldTriggerEvent:!1,shouldDestroy:!1});class xt{detectShareIdFromUrl(){try{const t=window.location.href,e=/saltfish-share-id=([^&#]*)/,n=t.match(e);if(n&&n[1]){const t=n[1];return t}return null}catch(t){return null}}async fetchShareData(t){try{const e=await fetch(`${st}/${t}`,{method:"GET",headers:{"Content-Type":"application/json"}});if(!e.ok)throw new Error(`Share API returned status ${e.status}`);const n=await e.json();if(!n.flowId)throw new Error("Share API response missing flowId");return n.shareId,n.flowId,n.createdBy,n}catch(e){throw Et.handleInitializationError(e,{component:"ShareLinkService",method:"fetchShareData",additionalData:{shareId:t}})}}async shouldAutoStartSharePlaylist(){try{const t=this.detectShareIdFromUrl();if(!t)return null;const e=await this.fetchShareData(t);return e.flowId,e.isGlobal,e}catch(t){return null}}}const Mt=3e4,It=100,Pt=12e4,Ct=500,_t=500,kt=5e3,Tt=18e5,At=6e4,zt=10;class Lt{constructor(t){e(this,"managers"),e(this,"userManagementService"),e(this,"playlistOrchestrator"),e(this,"shareLinkService"),e(this,"lastConfig",null),this.managers=t,this.shareLinkService=new xt}setUserManagementService(t){this.userManagementService=t}setPlaylistOrchestrator(t){this.playlistOrchestrator=t}getLastConfig(){return this.lastConfig}async initialize(t){var e;try{const n=await fetch(`${it}/validate-token`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({token:t.token,playerVersion:"0.2.73"})}),i=await n.json();if(!i.isValid)throw Et.handleInitializationError(i.error||"Token validation failed",{component:"PlayerInitializationService",method:"initialize",additionalData:{token:(null==(e=t.token)?void 0:e.substring(0,10))+"..."}});const s={...t,showLogo:!1!==i.showLogo};this.lastConfig=s;const r=bt();if(r.initialize(s),this.managers.analyticsManager.initialize(t,this.managers.sessionManager.getSessionId()),i.isAdmin&&r.setIsAdmin&&r.setIsAdmin(!0),i.playlists&&Array.isArray(i.playlists)&&r.setBackendPlaylists)i.playlists,r.setBackendPlaylists(i.playlists),i.playlists.length>0?this.managers.triggerManager.registerTriggers(i.playlists):i.isAdmin,i.abTests&&Array.isArray(i.abTests)&&(i.abTests,this.managers.abTestManager.initializeTests(i.abTests));else if(!i.isAdmin)throw Et.handleInitializationError("Backend validation successful, but no playlists array provided in the response. Cannot initialize player.",{component:"PlayerInitializationService",method:"initialize",additionalData:{responseData:i}});this.managers.eventManager.trigger("initialized",{timestamp:Date.now()})}catch(n){throw Et.handleInitializationError(n,{component:"PlayerInitializationService",method:"initialize"})}}async fetchUserData(t,e){var n;try{const i=bt();if(!(null==(n=i.config)?void 0:n.token))return void Et.handleWarning("Cannot fetch user data: Token not available",{component:"PlayerInitializationService",method:"fetchUserData",userId:t});const s=await fetch(`https://player.saltfish.ai/clients/${i.config.token}/users/${t}`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({userData:e})});if(!s.ok){await s.text();return s.status,void s.statusText}const r=await s.json();if(r.success){i.setUserData({watchedPlaylists:r.watchedPlaylists||{},language:r.language});const e=r.userListAssignments||{},n=r.abTestAssignments||{};this.managers.abTestManager.assignUserToTests(t,n,e),this.managers.eventManager.trigger("userDataLoaded",{timestamp:Date.now(),userId:t,userData:{watchedPlaylists:r.watchedPlaylists||{}}}),this.userManagementService&&this.userManagementService.resolveUserDataLoaded();const s=await this.checkAndResumeFromPendingNavigation();if(!(s||await this.checkAndResumeInProgressPlaylist(r.watchedPlaylists||{}))){const t=await this.shareLinkService.shouldAutoStartSharePlaylist();t&&this.playlistOrchestrator?(t.flowId,await this.playlistOrchestrator.startPlaylist(t.flowId,{once:!1,position:"bottom-right",_startedFromShareLink:!0,_isGlobalShare:t.isGlobal})):this.managers.triggerManager.startMonitoring()}}else this.userManagementService&&this.userManagementService.resolveUserDataLoaded()}catch(i){Et.handleNetworkError(i,{component:"PlayerInitializationService",method:"fetchUserData",userId:t}),this.userManagementService&&this.userManagementService.resolveUserDataLoaded()}}async loadAnonymousUserData(t,e){try{if("undefined"==typeof window)return;const n=this.managers.abTestManager.assignUserToTests(t,void 0,{}),i=this.managers.storageManager.getAnonymousUserData();let s={userId:t,userData:e||{},watchedPlaylists:{},abTestAssignments:n,timestamp:Date.now()};if(i){const n=i.abTestAssignments||{},r=this.managers.abTestManager.assignUserToTests(t,n);s={userId:t,userData:{...i.userData,...e},watchedPlaylists:i.watchedPlaylists||{},abTestAssignments:r,timestamp:Date.now()}}this.managers.storageManager.setAnonymousUserData(s);bt().setUserData({watchedPlaylists:s.watchedPlaylists||{},language:null==e?void 0:e.language}),this.managers.eventManager.trigger("userDataLoaded",{timestamp:Date.now(),userId:t,userData:{watchedPlaylists:s.watchedPlaylists||{}}});const r=await this.checkAndResumeFromPendingNavigation(),a=s.watchedPlaylists||{};if(!(r||await this.checkAndResumeInProgressPlaylist(a))){const t=await this.shareLinkService.shouldAutoStartSharePlaylist();t&&this.playlistOrchestrator?(t.flowId,await this.playlistOrchestrator.startPlaylist(t.flowId,{once:!1,position:"bottom-right",_startedFromShareLink:!0,_isGlobalShare:t.isGlobal})):this.managers.triggerManager.startMonitoring()}}catch(n){Et.handleNetworkError(n,{component:"PlayerInitializationService",method:"loadAnonymousUserData",userId:t})}}async checkAndResumeInProgressPlaylist(t){var e;if(!t)return!1;const n=bt(),i=null==(e=n.manifest)?void 0:e.id,s=n.currentState;if(i&&"idle"!==s&&"error"!==s)return!1;const r=Object.entries(t).find((([t,e])=>{if("in_progress"!==(null==e?void 0:e.status))return!1;const{isValid:n,ageMs:i}=St(e);return!!n}));if(r){const[t,e]=r;wt(e);try{if(this.playlistOrchestrator)return await this.playlistOrchestrator.startPlaylist(t),!0}catch(a){return!1}}return!1}async checkAndResumeFromPendingNavigation(){const t=this.managers.storageManager.getPendingNavigation();if(!t)return!1;if(Date.now()-t.timestamp>At)return this.managers.storageManager.clearPendingNavigation(),!1;if(!this.isURLPathMatch(t.urlPattern))return t.urlPattern,this.managers.storageManager.clearPendingNavigation(),!1;t.playlistId,t.nextStepId,this.managers.storageManager.clearPendingNavigation();try{if(this.playlistOrchestrator)return await this.playlistOrchestrator.startPlaylist(t.playlistId,{startNodeId:t.nextStepId}),!0}catch(e){return!1}return!1}isURLPathMatch(t){if(!t||"undefined"==typeof window)return!1;const e=window.location.href,n=window.location.pathname,i=t.replace(/[.*+?^${}()|[\]\\]/g,"\\$&").replace(/\\\*/g,".*"),s=new RegExp(i);return s.test(e)||s.test(n)}getOrCreateAnonymousUserId(){if("undefined"==typeof window)return`anonymous_${Date.now()}_${Math.random().toString(36).substring(2,11)}`;const t=this.managers.storageManager.getAnonymousUserData();if(null==t?void 0:t.userId)return t.userId,t.userId;const e=`anonymous_${Date.now()}_${Math.random().toString(36).substring(2,11)}`;return this.managers.storageManager.setAnonymousUserData({userId:e,userData:{},watchedPlaylists:{},timestamp:Date.now()}),e}destroy(){this.lastConfig=null}}function Vt(t){if(!t)return;if("auto"===t){return function(){try{const t=navigator.language||navigator.userLanguage;if(!t)return;return t.split("-")[0].toLowerCase()}catch(t){return}}()}return t.split("-")[0].toLowerCase()}class Ot{constructor(t){e(this,"managers"),e(this,"playerInitializationService"),e(this,"userDataLoadedPromise",null),e(this,"userDataLoadedResolve",null),e(this,"lastUserIdentification",null),this.managers=t}setPlayerInitializationService(t){this.playerInitializationService=t}getLastUserIdentification(){return this.lastUserIdentification}getUserDataLoadedPromise(){return this.userDataLoadedPromise}identifyUser(t,e){let n=e;if(e&&"string"==typeof e.language){const t=Vt(e.language);n={...e,language:t},e.language}this.lastUserIdentification={userId:t,userData:n};const i=bt();i.identifyUser(t,n),this.managers.analyticsManager.setUser({id:t,...n});(i.abTests||[]).length>0&&(this.userDataLoadedPromise=new Promise((t=>{this.userDataLoadedResolve=t}))),this.playerInitializationService&&this.playerInitializationService.fetchUserData(t,n)}async identifyAnonymous(t){if(!this.playerInitializationService)throw new Error("PlayerInitializationService not set");let e=t;if(t&&"string"==typeof t.language){const n=Vt(t.language);e={...t,language:n},t.language}const n=this.playerInitializationService.getOrCreateAnonymousUserId();this.lastUserIdentification={userId:n,userData:e};bt().identifyUser(n,{...e,__isAnonymous:!0}),this.managers.analyticsManager.setUser({id:n,...e}),await this.playerInitializationService.loadAnonymousUserData(n,e)}async recordABTestAttempt(t){var e;try{const n=bt(),i=n.user;if(!i||!(null==(e=n.config)?void 0:e.token))return;const s=(n.abTests||[]).find((e=>e.playlistId===t));if(!s)return;const r=(n.abTestAssignments||{})[s.id];if(!r)return void s.id;s.name,r.assigned;const a=await fetch(`https://player.saltfish.ai/clients/${n.config.token}/users/${i.id}`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({abTestAssignments:{[s.id]:r}})});a.ok?s.name:(a.status,a.statusText)}catch(n){}}resolveUserDataLoaded(){this.userDataLoadedResolve&&(this.userDataLoadedResolve(),this.userDataLoadedResolve=null,this.userDataLoadedPromise=null)}destroy(){this.userDataLoadedPromise=null,this.userDataLoadedResolve=null,this.lastUserIdentification=null}}class Dt{async validatePlaylistStart(t){const{playlistId:e,options:n,eventManager:i}=t;try{const t=bt();if(!t.config)return{isValid:!1,error:"Saltfish Player must be initialized before starting a playlist"};if(!0===t.isAdmin){return{isValid:!0,manifestPath:`https://storage.saltfish.ai/flows2/drafts/${e}.json`,updatedOptions:n}}if(!0===(null==n?void 0:n._startedFromShareLink)&&!0===(null==n?void 0:n._isGlobalShare)){return{isValid:!0,manifestPath:`https://storage.saltfish.ai/flows2/drafts/${e}.json`,updatedOptions:n}}!0===(null==n?void 0:n._startedFromShareLink)&&(null==n||n._isGlobalShare);const s=t.backendPlaylists;if(!s||0===s.length)return Et.handlePlaylistError("No playlist list available from backend validation",{component:"PlaylistValidator",method:"validatePlaylistStart",playlistId:e,errorType:"playlist_backend_unavailable"}),{isValid:!1,error:"No backend playlists available"};const r=s.find((t=>t.id===e));if(!r)return Et.handlePlaylistError(`Playlist ID '${e}' not found in the list provided by backend validation`,{component:"PlaylistValidator",method:"validatePlaylistStart",playlistId:e,errorType:"playlist_not_found",additionalData:{backendPlaylists:s}}),{isValid:!1,error:"Playlist not found in backend list"};if((null==r?void 0:r.hasTriggers)??(null==r?void 0:r.autoStart)??!1){const t=await this.validateTriggerConditions(e,r,i);if(!t.isValid)return t}let a=n;if(null==n?void 0:n.once){const t=await this.validateOnceOptionConditions(e,n,i);if(!t.isValid)return t;a=t.updatedOptions||n}const o=await this.validateDeviceCompatibility(r,e);return o.isValid?{isValid:!0,manifestPath:r.path,updatedOptions:a}:o}catch(s){const t=s instanceof Error?s.message:"Unknown validation error";return Et.handlePlaylistError(`Playlist validation failed: ${t}`,{component:"PlaylistValidator",method:"validatePlaylistStart",playlistId:e,additionalData:{error:s}}),{isValid:!1,error:t}}}async validateTriggerConditions(t,e,n){var i,s;const r=bt();if(!r.user)return Et.handlePlaylistError("User must be identified before starting auto-start playlist",{component:"PlaylistValidator",method:"validateAutoStartConditions",playlistId:t,errorType:"playlist_user_required"}),{isValid:!1,error:"User identification required for triggered playlist"};r.userData||await this.waitForUserData(n);const a=(null==(i=bt().userData)?void 0:i.watchedPlaylists)||{},o=e.hasTriggers??e.autoStart??!1,l=a[t],c=null==(s=e.triggers)?void 0:s.maxVisits,d=(null==l?void 0:l.visitCount)??("completed"===(null==l?void 0:l.status)||"dismissed"===(null==l?void 0:l.status)?1:0);return o&&null!=c&&d>=c?(q(`Playlist ${t} has hasTriggers enabled with maxVisits:${c} and user has ${d} visits. Skipping playlist start.`,{watchedPlaylists:a,triggers:e.triggers}),{isValid:!1,error:`Playlist visit limit reached (${d}/${c})`}):{isValid:!0}}async validateOnceOptionConditions(t,e,n){var i;const s=bt();if(!s.user)return Et.handlePlaylistError("User must be identified before starting playlist with once option",{component:"PlaylistValidator",method:"validateOnceOptionConditions",playlistId:t,errorType:"playlist_auth_required"}),{isValid:!1,error:"User identification required for once option"};s.userData||await this.waitForUserData(n);const r=(null==(i=bt().userData)?void 0:i.watchedPlaylists)||{},a=r[t];if(a&&("completed"===a.status||"dismissed"===a.status))return q(`Playlist ${t} has once option enabled and has already been ${a.status}. Skipping playlist start.`,{watchedPlaylists:r,playlistStatus:a.status}),{isValid:!1,error:`Playlist already ${a.status} with once option`};if(a&&"in_progress"===a.status&&!(null==e?void 0:e.startNodeId)&&a.currentStepId){return{isValid:!0,updatedOptions:{...e,startNodeId:a.currentStepId}}}return{isValid:!0}}async validateDeviceCompatibility(t,e){try{const n=t.deviceType||"both",{isDeviceCompatible:i}=await Promise.resolve().then((()=>Wt));return i(n)?{isValid:!0}:(Et.handlePlaylistError(`Playlist '${e}' is not compatible with this device. Required: ${n}`,{component:"PlaylistValidator",method:"validateDeviceCompatibility",playlistId:e,errorType:"playlist_device_incompatible",additionalData:{requiredDeviceType:n,manifestPath:t.path}}),{isValid:!1,error:`Device incompatible. Required: ${n}`})}catch(n){const i=n instanceof Error?n.message:"Unknown error";return Et.handlePlaylistError(`Device compatibility check failed: ${i}`,{component:"PlaylistValidator",method:"validateDeviceCompatibility",playlistId:e,additionalData:{error:n,manifestPath:t.path}}),{isValid:!1,error:`Device compatibility check failed: ${i}`}}}async waitForUserData(t){return new Promise(((e,n)=>{const i=setTimeout((()=>{t.off("userDataLoaded",s),n(new Error("Timeout waiting for user data"))}),5e3),s=()=>{clearTimeout(i),bt(),e()};t.on("userDataLoaded",s)}))}}class Ft{constructor(t){e(this,"managers"),e(this,"userManagementService"),e(this,"managerOrchestrator"),e(this,"playerInitializationService"),e(this,"stateMachineActionHandler"),this.managers=t}setUserManagementService(t){this.userManagementService=t}setManagerOrchestrator(t){this.managerOrchestrator=t}setPlayerInitializationService(t){this.playerInitializationService=t}setStateMachineActionHandler(t){this.stateMachineActionHandler=t}async startPlaylist(t,e){var n,i,s,r,a;try{const l=this.isInitialized()&&!this.managers.uiManager.getPlayerElement();if(!this.isInitialized()&&this.playerInitializationService){const e=this.playerInitializationService.getLastConfig();if(e)try{await this.playerInitializationService.initialize(e);const t=null==(n=this.userManagementService)?void 0:n.getLastUserIdentification();t&&this.userManagementService&&this.userManagementService.identifyUser(t.userId,t.userData),this.resetManagers(),this.stateMachineActionHandler&&this.stateMachineActionHandler.registerStateMachineActions()}catch(o){throw Et.handleInitializationError(`Failed to reinitialize player: ${o instanceof Error?o.message:"Unknown error"}`,{component:"PlaylistOrchestrator",method:"startPlaylist",playlistId:t,additionalData:{reinitError:o}})}}l&&(this.resetManagers(),this.managers.transitionManager.setTriggerManager(this.managers.triggerManager),this.stateMachineActionHandler&&this.stateMachineActionHandler.registerStateMachineActions());const c=bt();if(!c.config){if(!(null==(i=this.playerInitializationService)?void 0:i.getLastConfig()))throw Et.createError("Saltfish Player must be initialized at least once before starting a playlist",{component:"PlaylistOrchestrator",method:"startPlaylist",playlistId:t});throw Et.createError("Saltfish Player must be initialized before starting a playlist",{component:"PlaylistOrchestrator",method:"startPlaylist",playlistId:t})}c.manifest&&("playing"===c.currentState||"paused"===c.currentState||"loading"===c.currentState||"waitingForInteraction"===c.currentState||"autoplayBlocked"===c.currentState||"minimized"===c.currentState||"idleMode"===c.currentState)&&(this.managerOrchestrator&&this.managerOrchestrator.cleanupCurrentPlaylist(),c.resetForNewPlaylist(),this.stateMachineActionHandler&&this.stateMachineActionHandler.registerStateMachineActions()),"completed"!==c.currentState&&"closing"!==c.currentState||(c.currentState,c.resetForNewPlaylist(),this.stateMachineActionHandler&&this.stateMachineActionHandler.registerStateMachineActions());this.managers.sessionManager.startNewRun();this.managers.triggerManager.markPlaylistAsTriggered(t);const d=null==(s=this.userManagementService)?void 0:s.getUserDataLoadedPromise();if(d&&await d,this.userManagementService&&await this.userManagementService.recordABTestAttempt(t),!this.managers.abTestManager.isPlaylistAvailable(t))return;const h=new Dt,u=await h.validatePlaylistStart({playlistId:t,options:e,eventManager:this.managers.eventManager});if(!u.isValid)return;e=u.updatedOptions||e;const p=u.manifestPath,m=e||{};m?(c.setPlaylistOptions(m),m.position||c.setPlaylistOptions({...m,position:"bottom-right"})):c.setPlaylistOptions({position:"bottom-right"}),this.managers.uiManager.createPlayerUI(this.managers.videoManager,this.managers.cursorManager,this.managers.interactionManager),this.managerOrchestrator&&this.managerOrchestrator.setupUpdaters(),this.managers.uiManager.updatePosition(),c.sendStateMachineEvent({type:"LOAD_MANIFEST"});const g=null==e?void 0:e.persistence;if("undefined"!=typeof window){const e=null==(r=c.user)?void 0:r.id,n=this.managers.storageManager.getProgress(e);if(n&&n[t])c.loadPlaylistProgress(t,n[t]);else if(c.progress[t]){const e={...c.progress};delete e[t],vt.setState((t=>{t.progress=e}))}}this.managers.analyticsManager.trackPlaylistStart(t),this.managers.cursorManager.resetFirstAnimation(),await this.managers.playlistManager.load(p,{...m,persistence:g});const f=bt();if(f.manifest){const t=m.persistence??f.manifest.isPersistent??!0,e=f.playlistOptions||{};f.setPlaylistOptions({...e,...m,persistence:t})}if(m.startNodeId&&f.manifest){f.manifest.steps.find((t=>t.id===m.startNodeId))?f.goToStep(m.startNodeId):console.warn(`[PlaylistOrchestrator] startNodeId '${m.startNodeId}' not found in manifest steps. Starting from default step.`)}if(f.manifest){f.manifest.cursorColor&&this.managers.cursorManager.setColor(f.manifest.cursorColor),f.manifest.cursorLabel&&this.managers.cursorManager.setLabel(f.manifest.cursorLabel);m._triggeredByTriggerManager;const t=f.currentStepId===(null==(a=f.manifest.steps[0])?void 0:a.id);if(f.manifest.idleMode&&t){if(f.manifest.compactFirstStep){const t=this.managers.uiManager.getPlayerElement();null==t||t.classList.add("sf-player--compact"),f.manifest.compactLabel&&this.managers.uiManager.showCompactLabel(f.manifest.compactLabel)}c.setIdleMode()}else c.play()}else c.play();q(`Playlist started: ${t}${f.manifest?` (${f.manifest.name})`:""}`)}catch(l){this.managers.uiManager.hideLoading();bt().sendStateMachineEvent({type:"ERROR",error:l instanceof Error?l:new Error(String(l))}),Et.handlePlaylistError(l,{component:"PlaylistOrchestrator",method:"startPlaylist",playlistId:t,errorType:"playlist_load_failed"})}}resetPlaylist(){const t=bt();t.manifest&&t.goToStep(t.manifest.startStep)}isInitialized(){return!!bt().config}resetManagers(){this.managers.videoManager.reset(),this.managers.cursorManager.reset(),this.managers.interactionManager.reset(),this.managers.transitionManager.reset(),this.managers.uiManager.reset(),this.managers.stepTimeoutManager.reset()}destroy(){}}function Bt(t){const{pattern:e,matchType:n}=t;if(!e)return!0;const i=window.location.href,s=window.location.pathname;if("regex"===n)try{const t=new RegExp(e),n=t.test(i),r=t.test(s),a=n||r;return a}catch(r){return!1}if("contains"===n){return i.includes(e)||s.includes(e)}return i===e||s===e}class Ut{constructor(t){e(this,"managers"),e(this,"destroyCallback",null),e(this,"cursorAnimationListener",null),e(this,"cursorAnimationVideoElement",null),e(this,"cursorAnimationStepId",null),this.managers=t}setDestroyCallback(t){this.destroyCallback=t}registerStateMachineActions(){bt().registerStateMachineActions({startVideoPlayback:t=>{this.handleStartVideoPlayback(t)},pauseVideoPlayback:()=>{this.handlePauseVideoPlayback()},startMutedLoopedVideo:()=>{this.handleStartMutedLoopedVideo()},startIdleModeVideo:t=>{this.handleStartIdleModeVideo(t)},trackPlaylistComplete:()=>{this.handleTrackPlaylistComplete()},handleError:t=>{this.handleError(t)},hideError:()=>{this.handleHideError()},showLoadingState:()=>{this.handleShowLoadingState()},hideLoadingState:()=>{this.handleHideLoadingState()},hideVideoControls:()=>{this.handleHideVideoControls()},showVideoControls:()=>{this.handleShowVideoControls()},showPlayButton:()=>{this.handleShowPlayButton()},hidePlayButton:()=>{this.handleHidePlayButton()},enablePlayButtonProminent:()=>{this.handleEnablePlayButtonProminent()},disablePlayButtonProminent:()=>{this.handleDisablePlayButtonProminent()},enterCompactMode:()=>{this.handleEnterCompactMode()},exitCompactMode:()=>{this.handleExitCompactMode()},triggerPlaylistDismissed:()=>{this.handleTriggerPlaylistDismissed()},scheduleDestroy:()=>{this.handleScheduleDestroy()}})}getVideoUrl(t){var e;const n=null==(e=bt().userData)?void 0:e.language;let i;if(n&&t.translations&&t.translations[n]){i=t.translations[n].videoUrl}else i=t.compressedUrl||t.videoUrl;return i&&""!==i.trim()||!t.audioUrl||""===t.audioUrl.trim()?i:(t.id,t.audioUrl)}isUsingAudioFallback(t){var e;const n=null==(e=bt().userData)?void 0:e.language;let i;return i=n&&t.translations&&t.translations[n]?t.translations[n].videoUrl:t.compressedUrl||t.videoUrl,!(i&&""!==i.trim()||!t.audioUrl||""===t.audioUrl.trim())}findNextVideoUrl(t){const e=bt();if(!e.manifest||!t)return null;if(t.transitions.length>0){const n=t.transitions[0];if("url-path"===n.type||"dom-click"===n.type)return null;const i=n.nextStep,s=e.manifest.steps.find((t=>t.id===i));if(s)return this.getVideoUrl(s)}const n=e.manifest.steps.findIndex((e=>e.id===t.id));return n>=0&&n<e.manifest.steps.length-1?this.getVideoUrl(e.manifest.steps[n+1]):null}destroy(){this.cleanupCursorAnimationListener()}cleanupCursorAnimationListener(t){t&&this.cursorAnimationStepId&&t!==this.cursorAnimationStepId?this.cursorAnimationStepId:this.cursorAnimationListener&&this.cursorAnimationVideoElement&&(this.cursorAnimationVideoElement.removeEventListener("timeupdate",this.cursorAnimationListener),this.cursorAnimationListener=null,this.cursorAnimationVideoElement=null,this.cursorAnimationStepId=null)}scheduleCursorAnimation(t,e){this.cleanupCursorAnimationListener();let n=t.showAtSeconds??0;if("number"==typeof n&&isFinite(n)||(n=0),n<0&&(n=0),n<=0)this.managers.cursorManager.animate(t);else{const i=this.managers.videoManager.getVideoElement();if(!i)return;let s=!1,r=!1;const a=()=>{if(s)return;const e=i.currentTime,a=i.duration;if(a&&!isNaN(a)&&n>a&&!r)return r=!0,s=!0,this.cleanupCursorAnimationListener(),void this.managers.cursorManager.animate(t);e>=n&&(s=!0,this.cleanupCursorAnimationListener(),this.managers.cursorManager.animate(t))},o=()=>{if(!s){const n=bt();if(n.currentStepId!==e)return n.currentStepId,void this.cleanupCursorAnimationListener(e);i.duration,s=!0,this.managers.cursorManager.animate(t),this.cleanupCursorAnimationListener()}};this.cursorAnimationListener=()=>{a()},this.cursorAnimationVideoElement=i,this.cursorAnimationStepId=e,i.addEventListener("timeupdate",this.cursorAnimationListener),i.addEventListener("ended",o,{once:!0})}}async validateStepUrlRequirement(t){if(!t.urlRequirement)return!0;t.id,this.managers.transitionManager.startStateMachineValidation();try{const e=await async function(t,e=20,n=100){if(!t)return!0;for(let i=0;i<e;i++){if(Bt(t))return!0;if(i<e-1&&(await new Promise((t=>setTimeout(t,n))),!window._saltfishPlayer))return!1}return t.pattern,t.matchType,!1}(t.urlRequirement);if(!e){t.id;const e=window._saltfishPlayer;e&&"function"==typeof e.destroy&&e.destroy()}return e}finally{this.managers.transitionManager.endStateMachineValidation()}}async handleStartVideoPlayback(t){if(!t.currentStep)return;const e=t.currentStep;if(e.urlRequirement){e.id;if(!(await this.validateStepUrlRequirement(e)))return}this.managers.uiManager.updatePosition(),this.managers.uiManager.showPlayer();const n=this.getVideoUrl(e),i=this.isUsingAudioFallback(e);if(i){const t=bt().manifest,n=e.gifUrl,i=null==t?void 0:t.avatarThumbnailUrl;this.managers.videoManager.showAudioFallbackOverlay(n,i)}else this.managers.videoManager.hideAudioFallbackOverlay();try{this.managers.interactionManager.clearButtons(),e.buttons&&this.managers.interactionManager.createButtons(e.buttons),e.cursorAnimations&&e.cursorAnimations.length;const t=e.buttons&&e.buttons.length>0||e.transitions.some((t=>"dom-click"===t.type||"url-path"===t.type||"dom-element-visible"===t.type)),s=t?"manual":"auto";t&&this.managers.transitionManager.setupTransitions(e,!1,!0),this.managers.videoManager.setCompletionPolicy(s,(()=>{var n;const i=bt();if(t){const t=e.transitions.find((t=>"timeout"===t.type)),s=null==(n=e.buttons)?void 0:n.some((t=>"goto"===t.action.type||"next"===t.action.type));if(t&&!s){const n=t.timeout||0;t.nextStep,setTimeout((()=>{var n;const i=bt();i.currentStepId!==e.id||"waitingForInteraction"!==i.currentState&&"playing"!==i.currentState?i.currentState:(t.nextStep,null==(n=i.goToStep)||n.call(i,t.nextStep))}),n),i.sendStateMachineEvent({type:"VIDEO_FINISHED_WAIT",step:e})}else i.sendStateMachineEvent({type:"VIDEO_FINISHED_WAIT",step:e})}else{const t=e.transitions.find((t=>"timeout"===t.type));t&&t.timeout&&t.timeout>0?(t.timeout,this.managers.transitionManager.setupTransitions(e,!1)):this.managers.transitionManager.setupTransitions(e,!0);e.transitions.some((t=>i.manifest.steps.some((e=>e.id===t.nextStep))))||i.sendStateMachineEvent({type:"COMPLETE_PLAYLIST"})}}));const r=()=>{var t,n;const i=bt(),s=(null==(t=i.manifest)?void 0:t.captions)??!0,r=null==(n=i.userData)?void 0:n.language;let a=e.transcript;if(r&&e.translations&&e.translations[r]){const t=e.translations[r].transcript;t&&(a=t,e.id)}a?(e.id,this.managers.videoManager.loadTranscript(a,s)):(e.id,this.managers.videoManager.loadTranscript(null,!0))};this.managers.videoManager.loadVideo(n).then((()=>{this.managers.uiManager.hideError(),r(),e.cursorAnimations&&e.cursorAnimations.length>0?(e.id,this.managers.cursorManager.setShouldShowCursor(!0),this.scheduleCursorAnimation(e.cursorAnimations[0],e.id)):(e.id,this.managers.cursorManager.setShouldShowCursor(!1)),i?this.managers.videoManager.startAudioVisualization():this.managers.videoManager.initializeAudioForVideo(),this.managers.videoManager.play();const t=this.findNextVideoUrl(e);t&&this.managers.videoManager.preloadNextVideo(t)})).catch((t=>{var n;this.managers.uiManager.showError(t instanceof Error?t:new Error(`Failed to load video: ${t}`),"video");const i=bt(),s=t instanceof Error?t:new Error(`Failed to load video: ${t}`),r=t;this.managers.eventManager.trigger("error",{timestamp:Date.now(),playlistId:(null==(n=i.manifest)?void 0:n.id)||void 0,stepId:e.id,error:s,errorType:"video",videoUrl:null==r?void 0:r.videoUrl,mediaErrorCode:null==r?void 0:r.mediaErrorCode,mediaErrorMessage:null==r?void 0:r.mediaErrorMessage,failureReason:null==r?void 0:r.failureReason})}))}catch(s){}}handlePauseVideoPlayback(){this.managers.videoManager.pause()}handleStartMutedLoopedVideo(){const t=this.managers.videoManager.getVideoElement();t&&(t.muted=!0,t.loop=!0,t.play().catch((()=>{})))}handleStartIdleModeVideo(t){if(!t.currentStep)return;const e=t.currentStep,n=this.getVideoUrl(e),i=this.isUsingAudioFallback(e);if(this.managers.uiManager.showPlayer(),i){const t=bt().manifest,n=e.gifUrl,i=null==t?void 0:t.avatarThumbnailUrl;this.managers.videoManager.showAudioFallbackOverlay(n,i)}else this.managers.videoManager.hideAudioFallbackOverlay();this.managers.videoManager.loadVideo(n).then((()=>{this.managers.uiManager.hideError(),i&&this.managers.videoManager.startAudioVisualization();const t=this.managers.videoManager.getVideoElement();t&&(t.muted=!0,t.loop=!0,t.play().catch((()=>{})))})).catch((t=>{}))}handleTrackPlaylistComplete(){var t,e;const n=bt();if(n.manifest&&this.managers.eventManager){const i=n.manifest.id;this.managers.eventManager.trigger("playlistEnded",{timestamp:Date.now(),playlist:{id:i,title:n.manifest.name}});if(((null==(t=n.playlistOptions)?void 0:t.persistence)??!0)&&n.progress[i]){const t={...n.progress};delete t[i];const s=null==(e=n.user)?void 0:e.id;this.managers.storageManager.setProgress(t,s)}}}handleError(t){var e,n;if(null==(e=t.error)||e.message,t.error&&this.managers.uiManager.getPlayerElement()){this.managers.uiManager.showError(t.error,"player");const e=bt();this.managers.eventManager.trigger("error",{timestamp:Date.now(),playlistId:(null==(n=e.manifest)?void 0:n.id)||void 0,stepId:e.currentStepId||void 0,error:t.error,errorType:"player"})}}handleHideError(){this.managers.uiManager.hideError()}handleShowLoadingState(){this.managers.uiManager.showLoading("Loading...")}handleHideLoadingState(){this.managers.uiManager.hideLoading()}handleHideVideoControls(){this.managers.videoManager.hideProgressBar(),this.managers.videoManager.hideMuteButton()}handleShowVideoControls(){this.managers.videoManager.showProgressBar(),this.managers.videoManager.showMuteButton()}handleShowPlayButton(){this.managers.uiManager.updatePlayPauseButton("paused")}handleHidePlayButton(){this.managers.uiManager.updatePlayPauseButton("playing")}handleEnablePlayButtonProminent(){this.managers.uiManager.enablePlayButtonProminent()}handleDisablePlayButtonProminent(){this.managers.uiManager.disablePlayButtonProminent()}handleEnterCompactMode(){var t,e,n;const i=bt();if(i.manifest&&i.currentStepId===(null==(t=i.manifest.steps[0])?void 0:t.id)&&(null==(e=i.manifest)?void 0:e.compactFirstStep)){const t=this.managers.uiManager.getPlayerElement();null==t||t.classList.add("sf-player--compact"),(null==(n=i.manifest)?void 0:n.compactLabel)&&this.managers.uiManager.showCompactLabel(i.manifest.compactLabel)}}handleExitCompactMode(){const t=this.managers.uiManager.getPlayerElement();null==t||t.classList.remove("sf-player--compact"),this.managers.uiManager.hideCompactLabel()}handleTriggerPlaylistDismissed(){const t=bt();t.manifest&&this.managers.eventManager&&this.managers.eventManager.trigger("playlistDismissed",{timestamp:Date.now(),playlist:{id:t.manifest.id,title:t.manifest.name}})}handleScheduleDestroy(){setTimeout((()=>{this.destroyCallback&&this.destroyCallback()}),0)}}function Nt(t,e){let n=null;const i=()=>{n=t.querySelector(".sf-player__minimize-button")};i();let s={currentState:"",isMinimized:!1,currentStepId:null};function r(t,n){var i;if(!e)return;const s=null==(i=null==n?void 0:n.steps)?void 0:i.find((e=>e.id===t));s&&s.cursorAnimations&&s.cursorAnimations.length>0&&e.setShouldShowCursor(!0)}return vt.subscribe((a=>{var o,l,c,d;n||i(),a.currentState!==s.currentState&&(o=a.currentState,["sf-player--idle","sf-player--loading","sf-player--playing","sf-player--paused","sf-player--waitingForInteraction","sf-player--autoplayBlocked","sf-player--idleMode","sf-player--error","sf-player--completed","sf-player--completedWaitingForInteraction"].forEach((e=>{t.classList.remove(e)})),t.classList.add(`sf-player--${o}`)),a.isMinimized!==s.isMinimized&&(l=a.isMinimized,c=a.currentStepId,d=a.manifest,l?(t.classList.add("sf-player--minimized"),e&&e.setShouldShowCursor(!1)):(t.classList.remove("sf-player--minimized"),r(c,d)),function(t){if(!n)return;n.innerHTML=t?'\n <svg width="18" height="18" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">\n <path d="M12 5v14M5 12h14" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>\n </svg>\n ':'\n <svg width="20" height="20" viewBox="0 0 256 256" fill="currentColor" xmlns="http://www.w3.org/2000/svg">\n <path d="M205.66,194.34a8,8,0,0,1-11.32,11.32L128,139.31,61.66,205.66a8,8,0,0,1-11.32-11.32L116.69,128,50.34,61.66A8,8,0,0,1,61.66,50.34L128,116.69l66.34-66.35a8,8,0,0,1,11.32,11.32L139.31,128Z"></path>\n </svg>\n '}(a.isMinimized)),a.currentStepId!==s.currentStepId&&(a.isMinimized||r(a.currentStepId,a.manifest)),s={currentState:a.currentState,isMinimized:a.isMinimized,currentStepId:a.currentStepId}}))}function Rt(t){let e=null,n=null,i=null,s=null;const r=vt.subscribe((r=>{var a;if(e===r.currentState&&i===r.isMinimized&&s===r.currentStepId)return;const o=e,l=n,c=i,d=s;n=e,e=r.currentState,i=r.isMinimized,s=r.currentStepId;const h={prevPreviousState:l,previousState:o,currentState:r.currentState,currentStepId:r.currentStepId,isMinimized:r.isMinimized};null==(a=r.manifest)||a.id,function(t,e,n){const{prevPreviousState:i,previousState:s,currentState:r,currentStepId:a}=t,o="playing"===r&&"paused"===s&&"loading"===i,l="playing"===r&&("autoplayBlocked"===s||"idleMode"===s);if((o||l)&&e.manifest&&a){if(a===e.manifest.startStep)return e.manifest.id,void n.trigger("playlistStarted",{timestamp:Date.now(),playlist:{id:e.manifest.id,title:e.manifest.name}})}"paused"===s&&"playing"===r?n.trigger("playerResumed",{timestamp:Date.now(),previousState:s,currentState:r}):"playing"===s&&"paused"===r&&n.trigger("playerPaused",{timestamp:Date.now(),previousState:s,currentState:r})}(h,r,t),function(t,e,n,i){const{previousState:s,currentState:r,isMinimized:a}=t,o=i||!1;!a&&o?n.trigger("playerMaximized",{timestamp:Date.now(),previousState:s,currentState:r}):a&&!o&&n.trigger("playerMinimized",{timestamp:Date.now(),previousState:s,currentState:r})}(h,0,t,c),function(t,e,n,i){var s,r,a;const{prevPreviousState:o,previousState:l,currentStepId:c,currentState:d}=t,h=e.currentStepId?((null==(s=e.manifest)?void 0:s.steps)||[]).find((t=>t.id===e.currentStepId)):null;null==h||h.id,null==(r=e.manifest)||r.id,e.manifest;const u=i&&e.manifest&&(i!==c||"waitingForInteraction"===d||"completed"===d);if(e.manifest,u){const t=((null==(a=e.manifest)?void 0:a.steps)||[]).find((t=>t.id===i));null==t||t.id,t&&(t.id,n.trigger("stepEnded",{timestamp:Date.now(),step:{id:t.id,title:t.title||t.id},playlist:{id:e.manifest.id,title:e.manifest.name}}))}const p=c!==i&&"playing"===d,m=("autoplayBlocked"===l||"idleMode"===l)&&"playing"===d&&i===c,g="loading"===o&&"paused"===l&&"playing"===d&&c,f=h&&e.manifest&&(p||m||g);null==h||h.id,e.manifest,f&&(h.id,n.trigger("stepStarted",{timestamp:Date.now(),step:{id:h.id,title:h.title||h.id},playlist:{id:e.manifest.id,title:e.manifest.name}}))}(h,r,t,d),function(t,e,n){var i;const{currentState:s,previousState:r}=t;"error"===s&&"error"!==r&&e.error&&n.trigger("error",{timestamp:Date.now(),playlistId:null==(i=e.manifest)?void 0:i.id,stepId:e.currentStepId,error:e.error,errorType:"state"})}(h,r,t)}));return r}const Ht=class t{constructor(t){e(this,"managers"),e(this,"uiUpdaterUnsubscribe",null),e(this,"eventUpdaterUnsubscribe",null),e(this,"cursorAnimationListener",null),e(this,"cursorAnimationVideoElement",null),e(this,"cursorAnimationStepId",null),e(this,"isInitialized",!1),this.managers=t}setInitialized(t){this.isInitialized=t}setupUpdaters(){this.uiUpdaterUnsubscribe&&this.uiUpdaterUnsubscribe(),this.eventUpdaterUnsubscribe&&this.eventUpdaterUnsubscribe();const t=this.managers.uiManager.getPlayerElement();t&&(this.uiUpdaterUnsubscribe=Nt(t,this.managers.cursorManager)),this.eventUpdaterUnsubscribe=Rt(this.managers.eventManager);const e=vt.subscribe((t=>{this.managers.stepTimeoutManager.update({currentState:t.currentState,currentStepId:t.currentStepId,isMinimized:t.isMinimized,previousState:void 0})})),n=this.eventUpdaterUnsubscribe;this.eventUpdaterUnsubscribe=()=>{n&&n(),e()}}cleanupCursorAnimationListener(t){t&&this.cursorAnimationStepId&&t!==this.cursorAnimationStepId?this.cursorAnimationStepId:this.cursorAnimationListener&&this.cursorAnimationVideoElement&&(this.cursorAnimationVideoElement.removeEventListener("timeupdate",this.cursorAnimationListener),this.cursorAnimationListener=null,this.cursorAnimationVideoElement=null,this.cursorAnimationStepId=null)}scheduleCursorAnimation(t,e){this.cleanupCursorAnimationListener();let n=t.showAtSeconds??0;if("number"==typeof n&&isFinite(n)||(n=0),n<0&&(n=0),n<=0)this.managers.cursorManager.animate(t);else{const i=this.managers.videoManager.getVideoElement();if(!i)return;let s=!1,r=!1;const a=()=>{if(s)return;const e=i.currentTime,a=i.duration;if(a&&!isNaN(a)&&n>a&&!r)return r=!0,s=!0,this.cleanupCursorAnimationListener(),void this.managers.cursorManager.animate(t);e>=n&&(s=!0,this.cleanupCursorAnimationListener(),this.managers.cursorManager.animate(t))},o=()=>{if(!s){const n=bt();if(n.currentStepId!==e)return n.currentStepId,void this.cleanupCursorAnimationListener(e);i.duration,s=!0,this.managers.cursorManager.animate(t),this.cleanupCursorAnimationListener()}};this.cursorAnimationListener=()=>{a()},this.cursorAnimationVideoElement=i,this.cursorAnimationStepId=e,i.addEventListener("timeupdate",this.cursorAnimationListener),i.addEventListener("ended",o,{once:!0})}}handleStoreChanges(){if(!this.isInitialized)return;const e=bt();if(e.currentState!==t.prevState.currentState||e.currentStepId!==t.prevState.currentStepId||e.isMinimized!==t.prevState.isMinimized){if(t.prevState.currentState,e.currentState,t.prevState.currentStepId,e.currentStepId,t.prevState.isMinimized,e.isMinimized,this.managers.uiManager.getPlayerRoot()&&this.managers.uiManager.getPlayerElement()&&this.managers.uiManager.updatePosition(),this.managers.videoManager.transcriptManager.handleStateChange(e.currentState),"autoplayBlocked"===e.currentState)this.managers.cursorManager.stopAnimation(),this.managers.cursorManager.setShouldShowCursor(!1);else if("playing"===e.currentState&&"autoplayBlocked"===t.prevState.currentState){const t=e.manifest,n=null==t?void 0:t.steps.find((t=>t.id===e.currentStepId));(null==n?void 0:n.cursorAnimations)&&n.cursorAnimations.length>0&&(this.managers.cursorManager.setShouldShowCursor(!0),this.scheduleCursorAnimation(n.cursorAnimations[0],e.currentStepId||"unknown"))}else"completed"!==e.currentState&&"closing"!==e.currentState||this.cleanupPlaylist();e.isMinimized!==t.prevState.isMinimized&&this.managers.uiManager.handleMinimizeStateChange(e.isMinimized),t.prevState={currentState:e.currentState,currentStepId:e.currentStepId,isMinimized:e.isMinimized}}}cleanupCurrentPlaylist(){try{this.cleanupCursorAnimationListener(),this.eventUpdaterUnsubscribe&&(this.eventUpdaterUnsubscribe(),this.eventUpdaterUnsubscribe=null),this.managers.stepTimeoutManager&&this.managers.stepTimeoutManager.reset(),this.managers.videoManager&&(this.managers.videoManager.pause(),this.managers.videoManager.reset()),this.managers.cursorManager&&(this.managers.cursorManager.stopAnimation(),this.managers.cursorManager.setShouldShowCursor(!1)),this.managers.transitionManager&&this.managers.transitionManager.cleanupTransitions(),this.managers.interactionManager&&this.managers.interactionManager.clearButtons(),this.managers.uiManager.reset()}catch(t){Et.handleCleanupError(t,{component:"ManagerOrchestrator",method:"cleanupCurrentPlaylist"})}}cleanupPlaylist(){var t;if(this.isInitialized)try{const e=bt();e.currentState,e.currentStepId,e.isMinimized,null==(t=e.manifest)||t.id,this.uiUpdaterUnsubscribe&&(this.uiUpdaterUnsubscribe(),this.uiUpdaterUnsubscribe=null),this.managers.transitionManager.destroy(),this.managers.videoManager.destroy(),this.managers.cursorManager.destroy(),this.managers.interactionManager.destroy(),this.managers.playlistManager.destroy(),this.managers.stepTimeoutManager.destroy(),this.managers.uiManager.destroy()}catch(e){Et.handleCleanupError(e,{component:"ManagerOrchestrator",method:"cleanupPlaylist"})}else console.warn("Saltfish playlist Player is not initialized")}destroyAll(){var t;if(this.isInitialized)try{const e=bt();e.currentState,e.currentStepId,e.isMinimized,null==(t=e.manifest)||t.id,this.cleanupCursorAnimationListener(),this.uiUpdaterUnsubscribe&&(this.uiUpdaterUnsubscribe(),this.uiUpdaterUnsubscribe=null),this.eventUpdaterUnsubscribe&&(this.eventUpdaterUnsubscribe(),this.eventUpdaterUnsubscribe=null),this.managers.transitionManager.destroy(),this.managers.triggerManager.destroy(),this.managers.videoManager.destroy(),this.managers.cursorManager.destroy(),this.managers.interactionManager.destroy(),this.managers.analyticsManager.destroy(),this.managers.sessionManager.destroy(),this.managers.playlistManager.destroy(),this.managers.stepTimeoutManager.destroy(),this.managers.uiManager.destroy(),this.isInitialized=!1,e.reset()}catch(e){Et.handleCleanupError(e,{component:"ManagerOrchestrator",method:"destroyAll"});try{this.isInitialized=!1;bt().reset()}catch(n){Et.handleCleanupError(n,{component:"ManagerOrchestrator",method:"destroyAll",additionalData:{originalError:e}})}}else console.warn("Saltfish playlist Player is not initialized")}getManagers(){return this.managers}destroy(){this.destroyAll()}};e(Ht,"prevState",{currentState:"idle",currentStepId:null,isMinimized:!1});let $t=Ht;class Yt{constructor(){e(this,"container",null),e(this,"shadowRoot",null),e(this,"styleElement",null)}create(){if(this.container)return;this.container=document.createElement("div"),this.container.id="saltfish-container",this.container.appendChild(document.createTextNode("")),document.body.appendChild(this.container),this.shadowRoot=this.container.attachShadow({mode:"open"});try{const t=new CSSStyleSheet;t.replaceSync(this.getBaseStyles()),this.shadowRoot.adoptedStyleSheets=[t]}catch(e){this.styleElement=document.createElement("style"),this.styleElement.textContent=this.getBaseStyles(),this.shadowRoot.appendChild(this.styleElement)}const t=document.createElement("div");t.id="sf-player-root",this.shadowRoot.appendChild(t)}getShadowRoot(){return this.shadowRoot}getRootElement(){if(!this.shadowRoot)return null;return this.shadowRoot.getElementById("sf-player-root")}addStyles(t){if(this.shadowRoot){if(this.shadowRoot.adoptedStyleSheets&&this.shadowRoot.adoptedStyleSheets.length>0)try{const e=this.shadowRoot.adoptedStyleSheets[0],n=Array.from(e.cssRules).map((t=>t.cssText)).join("\n");return void e.replaceSync(n+"\n"+t)}catch(e){console.warn("ShadowDOMManager: Failed to append to adoptedStyleSheet:",e)}this.styleElement&&(this.styleElement.textContent+=t)}}remove(){this.container&&(document.body.removeChild(this.container),this.container=null,this.shadowRoot=null,this.styleElement=null)}getBaseStyles(){return"\n /* \n * CSS Reset for the Saltfish playlist Player\n * Minimal reset for the Shadow DOM to ensure consistent rendering\n */\n\n:host {\n all: initial;\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;\n box-sizing: border-box;\n}\n\n:host *,\n:host *::before,\n:host *::after {\n box-sizing: inherit;\n margin: 0;\n padding: 0;\n}\n\nbutton {\n background: none;\n border: none;\n cursor: pointer;\n font: inherit;\n outline: none;\n padding: 0;\n}\n\n/* Utility classes for CSP-compliant styling */\n.sf-hidden {\n display: none !important;\n} \n /* \n * Variables for the Saltfish playlist Player\n * Defines all design tokens used throughout the application\n */\n\n:host {\n /* Colors */\n --sf-primary-color: #4a9bff;\n --sf-secondary-color: #6ccfff;\n --sf-background-color: #1e1e1e;\n --sf-text-color: #ffffff;\n --sf-button-bg: rgba(0, 0, 0, 0.5);\n --sf-button-hover-bg: rgba(0, 0, 0, 0.7);\n --sf-overlay-gradient: linear-gradient(180deg, rgba(0, 0, 0, 0.7) 0%, transparent 30%, transparent 70%, rgba(0, 0, 0, 0.7) 100%);\n --sf-progress-gradient: linear-gradient(90deg, var(--sf-primary-color), var(--sf-secondary-color));\n --sf-error-color: #ff4d4d;\n --sf-error-bg: rgba(255, 77, 77, 0.1);\n \n /* Spacing */\n --sf-spacing-xs: 4px;\n --sf-spacing-sm: 8px;\n --sf-spacing-md: 12px;\n --sf-spacing-lg: 16px;\n --sf-spacing-xl: 24px;\n \n /* Sizes */\n --sf-player-width: 240px;\n --sf-player-height: 336px;\n --sf-player-min-width: 80px;\n --sf-player-min-height: 80px;\n --sf-player-compact-width: 120px;\n --sf-player-compact-height: 120px;\n --sf-control-button-size: 24px;\n --sf-play-button-size: 60px;\n --sf-play-button-compact-size: 44px;\n --sf-minimize-button-size: 34px;\n --sf-mute-button-size: 32px;\n --sf-cc-button-size: 32px;\n --sf-cursor-size: 32px;\n \n /* Border radius */\n --sf-border-radius-sm: 4px;\n --sf-border-radius-md: 8px;\n --sf-border-radius-lg: 16px;\n --sf-border-radius-circle: 50%;\n \n /* Transitions */\n --sf-transition-fast: 0.1s ease;\n --sf-transition-normal: 0.2s ease;\n --sf-transition-slow: 0.3s cubic-bezier(0.25, 0.8, 0.25, 1);\n \n /* Shadows */\n --sf-shadow-small: 0 2px 5px rgba(0, 0, 0, 0.2);\n --sf-shadow-medium: 0 4px 8px rgba(0, 0, 0, 0.15);\n --sf-shadow-large: 0 10px 25px rgba(0, 0, 0, 0.2);\n \n /* Z-index layering */\n --sf-z-index-base: 1;\n --sf-z-index-overlay: 2;\n --sf-z-index-controls: 10;\n --sf-z-index-cursor: 9999;\n --sf-z-index-player: 2147483648;\n \n /* Font sizes */\n --sf-font-size-sm: 14px;\n --sf-font-size-md: 16px;\n --sf-font-size-lg: 18px;\n --sf-font-size-xl: 24px;\n} \n\n/* Mobile device responsive adjustments - make player smaller for mobile screens */\n@media (max-width: 768px) {\n :host {\n /* Reduce player size on mobile for better space utilization */\n --sf-player-width: 180px; /* 25% smaller than desktop (240px -> 180px) */\n --sf-player-height: 252px; /* 25% smaller than desktop (336px -> 252px) */\n --sf-player-min-width: 60px; /* Smaller when minimized (80px -> 60px) */\n --sf-player-min-height: 60px; /* Smaller when minimized (80px -> 60px) */\n --sf-player-compact-width: 90px; /* Smaller compact mode for mobile (120px -> 90px) */\n --sf-player-compact-height: 90px; /* Smaller compact mode for mobile (120px -> 90px) */\n\n /* Keep controls touch-friendly despite smaller player size */\n --sf-play-button-size: 44px; /* Smaller but still touch-friendly (60px -> 44px) */\n --sf-play-button-compact-size: 36px; /* Touch-friendly compact play button */\n --sf-control-button-size: 28px; /* Keep larger for touch targets (24px -> 28px) */\n --sf-mute-button-size: 26px; /* Smaller for mobile (32px -> 26px) */\n --sf-cc-button-size: 26px; /* Smaller for mobile (32px -> 26px) */\n --sf-minimize-button-size: 26px; /* Match other mobile button sizes */\n }\n}\n\n/* Touch device specific adjustments (tablets and larger touch devices, excluding mobile) */\n@media (pointer: coarse) and (min-width: 769px) {\n :host {\n /* Ensure touch-friendly sizes even on larger touch devices */\n --sf-control-button-size: 28px;\n --sf-mute-button-size: 38px;\n --sf-cc-button-size: 38px;\n --sf-minimize-button-size: 38px; /* Match other touch device button sizes */\n }\n} \n\n /* \n * Player component styles for the Saltfish playlist Player\n * Following BEM naming convention\n */\n\n/* Main player container */\n.sf-player {\n border-radius: var(--sf-border-radius-md);\n box-shadow: 0 15px 30px rgba(0, 0, 0, 0.15), 0 5px 15px rgba(0, 0, 0, 0.08);\n position: relative;\n backdrop-filter: blur(10px);\n -webkit-backdrop-filter: blur(10px);\n opacity: 0;\n /* Only transition opacity initially - prevents size flicker on load */\n transition: opacity 0.3s ease-in-out;\n}\n\n/* Player visible state - show with fade in and enable size transitions */\n.sf-player--visible {\n opacity: 1;\n /* Enable size transitions only after player is visible to prevent initial flicker */\n transition: opacity 0.3s ease-in-out,\n width 0.3s cubic-bezier(0.25, 0.8, 0.25, 1),\n height 0.3s cubic-bezier(0.25, 0.8, 0.25, 1),\n border-radius 0.3s cubic-bezier(0.25, 0.8, 0.25, 1);\n}\n\n/* Gradient overlay now moved to video container - see _video.css */\n\n/* Full-size player state */\n.sf-player:not(.sf-player--minimized) {\n width: var(--sf-player-width);\n height: var(--sf-player-height);\n}\n\n/* Autoplay fallback state - ensure play button is visible */\n.sf-player--waiting-for-user-interaction .sf-controls-container__play-button {\n display: flex !important;\n opacity: 1 !important;\n visibility: visible !important;\n}\n\n/* Also show the center play button in autoplay fallback state */\n.sf-player--waiting-for-user-interaction .sf-player__center-play-button {\n display: flex !important;\n opacity: 1 !important;\n z-index: calc(var(--sf-z-index-controls) + 20) !important; /* Higher z-index to appear above overlay */\n}\n\n/* Make the autoplay fallback state more prominent to indicate need for interaction */\n.sf-player--waiting-for-user-interaction::after {\n content: '';\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(0, 0, 0, 0.3);\n pointer-events: none;\n z-index: var(--sf-z-index-overlay);\n}\n\n/* Player state: minimized */\n.sf-player--minimized {\n /* Equal width and height are essential for maintaining a perfect circle when using border-radius: 50% */\n width: var(--sf-player-min-width);\n height: var(--sf-player-min-height);\n border-radius: var(--sf-border-radius-circle);\n box-shadow: 0 15px 30px rgba(0, 0, 0, 0.20), 0 5px 15px rgba(0, 0, 0, 0.12);\n cursor: pointer;\n /* Force overriding any inline styles that might be applied */\n max-width: var(--sf-player-min-width) !important;\n max-height: var(--sf-player-min-height) !important;\n min-width: var(--sf-player-min-width) !important;\n min-height: var(--sf-player-min-height) !important;\n}\n\n/* Player state: compact (first step, small rounded) */\n.sf-player--compact {\n width: var(--sf-player-compact-width) !important;\n height: var(--sf-player-compact-height) !important;\n border-radius: var(--sf-border-radius-circle);\n box-shadow: 0 15px 30px rgba(0, 0, 0, 0.20), 0 5px 15px rgba(0, 0, 0, 0.12);\n cursor: pointer; /* Whole bubble is clickable */\n /* Force overriding any inline styles that might be applied */\n max-width: var(--sf-player-compact-width) !important;\n max-height: var(--sf-player-compact-height) !important;\n min-width: var(--sf-player-compact-width) !important;\n min-height: var(--sf-player-compact-height) !important;\n}\n\n/* Hide center play button in compact mode - the whole bubble is clickable */\n.sf-player--compact .sf-player__center-play-button {\n display: none !important;\n}\n\n/* Hide elements in compact mode */\n.sf-player--compact .sf-player__logo,\n.sf-player--compact .sf-player__minimize-button {\n display: none;\n}\n\n/* Hide gradient overlay when in compact mode - see _video.css */\n.sf-player--compact .sf-video-container::after {\n display: none;\n}\n\n/* Hide controls when minimized */\n.sf-player--minimized .sf-controls-container {\n display: none;\n}\n\n/* Hide controls when in compact mode */\n.sf-player--compact .sf-controls-container {\n display: none;\n}\n\n/* Only show the minimize button when hovering on minimized player */\n.sf-player--minimized .sf-player__minimize-button {\n opacity: 0;\n}\n\n.sf-player--minimized:hover .sf-player__minimize-button {\n opacity: 1;\n}\n\n/* Player root element */\n#sf-player-root {\n position: fixed;\n z-index: var(--sf-z-index-player);\n}\n\n/* Fixed positioning classes */\n.sf-player-root--bottom-left {\n bottom: 20px;\n left: 20px;\n}\n\n.sf-player-root--bottom-right {\n bottom: 20px;\n right: 20px;\n}\n\n/* Player error message */\n.sf-player__error {\n padding: var(--sf-spacing-md);\n color: var(--sf-error-color);\n background-color: var(--sf-error-bg);\n border-radius: var(--sf-border-radius-md);\n margin: var(--sf-spacing-sm);\n font-size: var(--sf-font-size-sm);\n border-left: 4px solid var(--sf-error-color);\n}\n\n/* Minimize button */\n.sf-player__minimize-button {\n position: absolute;\n top: 8px;\n right: 4px;\n width: var(--sf-minimize-button-size);\n height: var(--sf-minimize-button-size);\n background: none !important;\n border-radius: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n cursor: pointer;\n z-index: var(--sf-z-index-controls);\n color: white;\n border: none;\n font-size: calc(var(--sf-font-size-sm) + 4px);\n transition: all var(--sf-transition-normal);\n text-shadow: 0 1px 3px rgba(0, 0, 0, 0.3);\n opacity: 0;\n}\n\n/* Minimize button background circle */\n.sf-player__minimize-button::before {\n content: '';\n position: absolute;\n width: 80%;\n height: 80%;\n background-color: rgba(0, 0, 0, 0.1);\n border-radius: 50%;\n z-index: -1;\n transition: all var(--sf-transition-normal);\n}\n\n/* Minimize button hover state */\n.sf-player__minimize-button:hover {\n transform: scale(1.1);\n}\n\n/* Show minimize button on player hover */\n.sf-player:hover .sf-player__minimize-button {\n opacity: 1;\n}\n\n/* Mobile and touch device overrides for minimize button visibility */\n/* Ensure minimize button is always visible on touch devices, even when minimized */\n@media (pointer: coarse) {\n .sf-player__minimize-button {\n opacity: 1 !important;\n z-index: calc(var(--sf-z-index-controls) + 50) !important; /* Much higher z-index for touch devices */\n }\n \n .sf-player--minimized .sf-player__minimize-button {\n opacity: 1 !important;\n z-index: calc(var(--sf-z-index-controls) + 50) !important; /* Much higher z-index for touch devices */\n }\n}\n\n/* Ensure minimize button is always visible on mobile screens under 768px */\n@media (max-width: 768px) {\n .sf-player__minimize-button {\n opacity: 1 !important;\n z-index: calc(var(--sf-z-index-controls) + 50) !important; /* Much higher z-index for mobile */\n /* Position closer to top right corner on mobile */\n top: var(--sf-spacing-xs) !important; /* 4px from top instead of 16px */\n right: var(--sf-spacing-xs) !important; /* 4px from right instead of 12px */\n }\n \n .sf-player--minimized .sf-player__minimize-button {\n opacity: 1 !important;\n z-index: calc(var(--sf-z-index-controls) + 50) !important; /* Much higher z-index for mobile */\n /* Position closer to top right corner on mobile */\n top: var(--sf-spacing-xs) !important; /* 4px from top instead of 16px */\n right: var(--sf-spacing-xs) !important; /* 4px from right instead of 12px */\n }\n}\n\n/* Player title */\n.sf-player__title {\n position: absolute;\n top: var(--sf-spacing-md);\n left: var(--sf-spacing-md);\n color: var(--sf-text-color);\n font-size: var(--sf-font-size-md);\n font-weight: 600;\n z-index: var(--sf-z-index-controls);\n text-shadow: 0 1px 2px rgba(0, 0, 0, 0.5);\n max-width: 70%;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n/* Centered play/pause button overlay */\n.sf-player__center-play-button {\n position: absolute;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n width: var(--sf-play-button-size);\n height: var(--sf-play-button-size);\n background-color: rgba(0, 0, 0, 0.5);\n border-radius: var(--sf-border-radius-circle);\n display: none; /* Hidden by default */\n justify-content: center;\n align-items: center;\n z-index: calc(var(--sf-z-index-controls) + 10); /* Ensure higher z-index than other elements */\n color: white;\n border: none;\n font-size: var(--sf-control-button-size);\n cursor: pointer;\n transition: transform var(--sf-transition-normal), background-color var(--sf-transition-normal), opacity var(--sf-transition-normal);\n backdrop-filter: blur(1px);\n -webkit-backdrop-filter: blur(1px);\n pointer-events: auto; /* Enable pointer events to capture clicks */\n}\n\n/* Icon visibility control - use opacity for smooth transitions */\n.sf-player__center-play-button__pause-icon,\n.sf-player__center-play-button__play-icon {\n position: absolute;\n transition: opacity var(--sf-transition-normal);\n}\n\n.sf-player__center-play-button__pause-icon {\n opacity: 0;\n}\n\n.sf-player__center-play-button__play-icon {\n opacity: 1;\n}\n\n/* When playing, make button hoverable but invisible (desktop only) */\n@media (hover: hover) and (pointer: fine) {\n .sf-player--playing .sf-player__center-play-button {\n display: flex;\n opacity: 0;\n pointer-events: auto;\n }\n\n /* Show pause icon on hover when playing */\n .sf-player--playing .sf-player__center-play-button:hover {\n opacity: 1;\n }\n\n .sf-player--playing .sf-player__center-play-button:hover .sf-player__center-play-button__play-icon {\n opacity: 0;\n transition: none; /* Instant switch when hovering during playback */\n }\n\n .sf-player--playing .sf-player__center-play-button:hover .sf-player__center-play-button__pause-icon {\n opacity: 1;\n transition: none; /* Instant switch when hovering during playback */\n }\n\n /* Delay icon switch when not hovering during playback so pause icon stays visible during fade-out */\n .sf-player--playing .sf-player__center-play-button .sf-player__center-play-button__play-icon,\n .sf-player--playing .sf-player__center-play-button .sf-player__center-play-button__pause-icon {\n transition: opacity 0s 0.2s; /* Instant transition but delayed by button fade duration */\n }\n}\n\n/* Replay icon hidden by default */\n.sf-player__center-play-button__replay-icon {\n opacity: 0;\n position: absolute;\n transition: opacity var(--sf-transition-normal);\n}\n\n/* Show replay icon when video completed or waiting for interaction */\n.sf-player--completedWaitingForInteraction .sf-player__center-play-button__replay-icon,\n.sf-player--waitingForInteraction .sf-player__center-play-button__replay-icon {\n opacity: 1;\n transition: none;\n}\n\n/* Hide play/pause icons when showing replay */\n.sf-player--completedWaitingForInteraction .sf-player__center-play-button__play-icon,\n.sf-player--completedWaitingForInteraction .sf-player__center-play-button__pause-icon,\n.sf-player--waitingForInteraction .sf-player__center-play-button__play-icon,\n.sf-player--waitingForInteraction .sf-player__center-play-button__pause-icon {\n opacity: 0;\n transition: none;\n}\n\n/* Center play button visible state */\n.sf-player__center-play-button--visible {\n display: flex !important;\n}\n\n/* Center play button prominent state (for autoplay blocked, idle mode) */\n.sf-player__center-play-button--prominent {\n opacity: 1 !important;\n pointer-events: auto !important;\n}\n\n/* Center play button hover state */\n.sf-player__center-play-button:hover {\n transform: translate(-50%, -50%) scale(1.1);\n}\n\n/* Hide center play button in minimized state */\n.sf-player--minimized .sf-player__center-play-button {\n display: none !important;\n}\n\n/* Center play button with dynamic positioning when buttons are present */\n/* Positions button centered between top of player and top of first button */\n.sf-player__center-play-button--with-buttons {\n /* Available space above buttons = playerHeight - bottomSpacing - buttonContainerHeight */\n /* Center point = availableSpace / 2 */\n top: calc((var(--sf-player-height) - var(--sf-spacing-xl) - var(--sf-button-container-height, 0px)) / 2) !important;\n transform: translate(-50%, -50%) !important;\n}\n\n/* Maintain scale on hover for buttons with dynamic positioning */\n.sf-player__center-play-button--with-buttons:hover {\n transform: translate(-50%, -50%) scale(1.1) !important;\n}\n\n/* Exit button for minimized mode */\n.sf-player__exit-button {\n position: absolute;\n top: -22px; /* Position it above the player */\n right: 0;\n width: 22px;\n height: 22px;\n background-color: rgba(0, 0, 0, 0.5);\n border-radius: var(--sf-border-radius-circle);\n display: flex;\n align-items: center;\n justify-content: center;\n cursor: pointer;\n z-index: var(--sf-z-index-controls);\n color: white;\n border: none;\n font-size: var(--sf-font-size-md);\n transition: all var(--sf-transition-normal);\n text-shadow: 0 1px 3px rgba(0, 0, 0, 0.3);\n}\n\n.sf-player__exit-button svg {\n width: 18px;\n height: 18px;\n}\n\n/* Exit button hover state */\n.sf-player__exit-button:hover {\n transform: scale(1.1);\n background-color: rgba(0, 0, 0, 0.7);\n}\n\n/* Show exit button on minimized player hover */\n.sf-player--minimized:hover .sf-player__exit-button {\n opacity: 1;\n}\n\n/* Saltfish logo */\n.sf-player__logo {\n position: absolute;\n bottom: var(--sf-spacing-xs);\n left: 0;\n right: 0;\n height: 18px;\n z-index: var(--sf-z-index-controls);\n opacity: 0.7;\n transition: opacity var(--sf-transition-normal);\n cursor: pointer;\n display: flex;\n justify-content: center;\n align-items: center;\n}\n\n.sf-player__logo svg {\n width: 55px;\n height: 20px;\n}\n\n/* Logo hover state */\n.sf-player:hover .sf-player__logo {\n opacity: 0.9;\n}\n\n/* Hide logo when minimized */\n.sf-player--minimized .sf-player__logo {\n display: none;\n} \n /* \n * Video component styles for the Saltfish playlist Player\n * Following BEM naming convention\n */\n\n/* Video container */\n.sf-video-container {\n position: relative;\n width: 100%;\n height: 100%;\n border-radius: var(--sf-border-radius-md);\n overflow: hidden;\n pointer-events: auto; /* Ensure clicks on video container are captured */\n background-color: #000; /* Fallback background for audio-only mode */\n /* Force clean border-radius clipping */\n isolation: isolate;\n transform: translateZ(0);\n -webkit-mask-image: -webkit-radial-gradient(white, black);\n /* Ensure video container and its children (including captions) sit above the gradient overlay */\n z-index: 3;\n /* Smooth transition for border-radius changes */\n transition: border-radius var(--sf-transition-slow);\n}\n\n/* Dark gradient overlay at bottom of video - ensures captions are visible above it */\n.sf-video-container::after {\n content: '';\n position: absolute;\n bottom: 0;\n left: 0;\n right: 0;\n height: 33.33%; /* One third of container height */\n background: linear-gradient(to top, rgba(0, 0, 0, 0.8) 0%, rgba(0, 0, 0, 0) 100%);\n pointer-events: none;\n z-index: var(--sf-z-index-overlay);\n border-radius: 0 0 var(--sf-border-radius-md) var(--sf-border-radius-md);\n}\n\n/* Dark gradient overlay at bottom of video - ensures captions are visible above it */\n.sf-video-container::after {\n content: '';\n position: absolute;\n bottom: 0;\n left: 0;\n right: 0;\n height: 33.33%; /* One third of container height */\n background: linear-gradient(to top, rgba(0, 0, 0, 0.6) 0%, rgba(0, 0, 0, 0) 100%);\n pointer-events: none;\n z-index: var(--sf-z-index-overlay);\n border-radius: 0 0 var(--sf-border-radius-md) var(--sf-border-radius-md);\n}\n\n/* Dark gradient overlay at bottom of video - ensures captions are visible above it */\n.sf-video-container::after {\n content: '';\n position: absolute;\n bottom: 0;\n left: 0;\n right: 0;\n height: 33.33%; /* One third of container height */\n background: linear-gradient(to top, rgba(0, 0, 0, 0.6) 0%, rgba(0, 0, 0, 0) 100%);\n pointer-events: none;\n z-index: var(--sf-z-index-overlay);\n border-radius: 0 0 var(--sf-border-radius-lg) var(--sf-border-radius-lg);\n}\n\n/* Dark gradient overlay at bottom of video - ensures captions are visible above it */\n.sf-video-container::after {\n content: '';\n position: absolute;\n bottom: 0;\n left: 0;\n right: 0;\n height: 33.33%; /* One third of container height */\n background: linear-gradient(to top, rgba(0, 0, 0, 0.6) 0%, rgba(0, 0, 0, 0) 100%);\n pointer-events: none;\n z-index: var(--sf-z-index-overlay);\n border-radius: 0 0 var(--sf-border-radius-lg) var(--sf-border-radius-lg);\n}\n\n/* Dark gradient overlay at bottom of video - ensures captions are visible above it */\n.sf-video-container::after {\n content: '';\n position: absolute;\n bottom: 0;\n left: 0;\n right: 0;\n height: 33.33%; /* One third of container height */\n background: linear-gradient(to top, rgba(0, 0, 0, 0.6) 0%, rgba(0, 0, 0, 0) 100%);\n pointer-events: none;\n z-index: var(--sf-z-index-overlay);\n border-radius: 0 0 var(--sf-border-radius-md) var(--sf-border-radius-md);\n}\n\n/* Dark gradient overlay at bottom of video - ensures captions are visible above it */\n.sf-video-container::after {\n content: '';\n position: absolute;\n bottom: 0;\n left: 0;\n right: 0;\n height: 33.33%; /* One third of container height */\n background: linear-gradient(to top, rgba(0, 0, 0, 0.6) 0%, rgba(0, 0, 0, 0) 100%);\n pointer-events: none;\n z-index: var(--sf-z-index-overlay);\n border-radius: 0 0 var(--sf-border-radius-md) var(--sf-border-radius-md);\n}\n\n/* Dark gradient overlay at bottom of video - ensures captions are visible above it */\n.sf-video-container::after {\n content: '';\n position: absolute;\n bottom: 0;\n left: 0;\n right: 0;\n height: 33.33%; /* One third of container height */\n background: linear-gradient(to top, rgba(0, 0, 0, 0.6) 0%, rgba(0, 0, 0, 0) 100%);\n pointer-events: none;\n z-index: var(--sf-z-index-overlay);\n border-radius: 0 0 var(--sf-border-radius-md) var(--sf-border-radius-md);\n}\n\n/* Dark gradient overlay at bottom of video - ensures captions are visible above it */\n.sf-video-container::after {\n content: '';\n position: absolute;\n bottom: 0;\n left: 0;\n right: 0;\n height: 33.33%; /* One third of container height */\n background: linear-gradient(to top, rgba(0, 0, 0, 0.6) 0%, rgba(0, 0, 0, 0) 100%);\n pointer-events: none;\n z-index: var(--sf-z-index-overlay);\n border-radius: 0 0 var(--sf-border-radius-md) var(--sf-border-radius-md);\n}\n\n/* Dark gradient overlay at bottom of video - ensures captions are visible above it */\n.sf-video-container::after {\n content: '';\n position: absolute;\n bottom: 0;\n left: 0;\n right: 0;\n height: 33.33%; /* One third of container height */\n background: linear-gradient(to top, rgba(0, 0, 0, 0.6) 0%, rgba(0, 0, 0, 0) 100%);\n pointer-events: none;\n z-index: var(--sf-z-index-overlay);\n border-radius: 0 0 var(--sf-border-radius-md) var(--sf-border-radius-md);\n}\n\n/* Dark gradient overlay at bottom of video - ensures captions are visible above it */\n.sf-video-container::after {\n content: '';\n position: absolute;\n bottom: 0;\n left: 0;\n right: 0;\n height: 33.33%; /* One third of container height */\n background: linear-gradient(to top, rgba(0, 0, 0, 0.6) 0%, rgba(0, 0, 0, 0) 100%);\n pointer-events: none;\n z-index: var(--sf-z-index-overlay);\n border-radius: 0 0 var(--sf-border-radius-md) var(--sf-border-radius-md);\n}\n\n/* Audio fallback poster image */\n.sf-video-container--audio-fallback {\n background-size: cover;\n background-position: center;\n background-repeat: no-repeat;\n background-image: var(--sf-audio-poster-url, none);\n}\n\n/* Audio fallback overlay */\n.sf-audio-fallback-overlay {\n position: absolute;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n background: rgba(0, 0, 0, 0.6);\n z-index: 2;\n pointer-events: none;\n}\n\n/* Avatar mode overlay - no background, just container */\n.sf-audio-fallback-overlay--avatar {\n background: none;\n}\n\n.sf-audio-fallback-overlay__icon {\n width: 60px;\n height: 60px;\n margin-bottom: 16px;\n color: white;\n opacity: 0.9;\n}\n\n.sf-audio-fallback-overlay__text {\n color: white;\n font-size: 14px;\n text-align: center;\n padding: 0 20px;\n text-shadow: 0 2px 4px rgba(0, 0, 0, 0.5);\n opacity: 0.9;\n}\n\n.sf-audio-fallback-overlay__avatar {\n position: absolute;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n object-fit: cover;\n z-index: 1;\n}\n\n/* Semi-transparent overlay on top of avatar */\n.sf-audio-fallback-overlay__dim {\n position: absolute;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n background: rgba(0, 0, 0, 0.3);\n z-index: 2;\n}\n\n/* Soundbar-only mode overlay - dark background for soundbar visibility */\n.sf-audio-fallback-overlay--soundbar-only {\n background: rgba(0, 0, 0, 0.85);\n}\n\n/* Audio visualization soundbar container */\n.sf-audio-soundbar {\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 8px;\n height: 120px;\n width: auto;\n max-width: 300px;\n z-index: 3;\n position: relative;\n padding: 0 20px;\n}\n\n/* Individual soundbar frequency bar */\n.sf-audio-soundbar__bar {\n flex: 1;\n min-width: 8px;\n max-width: 20px;\n height: 10%; /* Default minimum height */\n background-color: hsla(180, 70%, 60%, 0.3);\n border-radius: 4px;\n transition: height 0.05s ease-out, background-color 0.1s ease-out;\n transform-origin: center;\n will-change: height, background-color;\n}\n\n/* Video element */\n.sf-video-container__video {\n width: 100%;\n height: 100%;\n object-fit: cover;\n /* Ensure video is visible on mobile */\n display: block;\n /* Add explicit positioning to ensure video is visible */\n position: relative;\n z-index: 1;\n /* Remove any border-radius - let container's overflow: hidden do the clipping */\n border-radius: 0;\n /* Force GPU acceleration for cleaner clipping with scale effect */\n transform: scale(1.04) translateZ(0);\n backface-visibility: hidden;\n transition: transform 0.3s cubic-bezier(0.25, 0.8, 0.25, 1);\n}\n\n/* Video blur effect (for end-of-video transitions) */\n.sf-video-container__video--blurred {\n filter: blur(3px);\n transform: scale(1.04) translateZ(0);\n transition: filter 0.3s ease-out, transform 0.3s ease-out;\n}\n\n\n\n/* Mobile-specific video styles */\n@media (max-width: 768px) {\n\n .sf-video-container__video {\n /* Force video dimensions on mobile */\n width: 100% !important;\n height: 100% !important;\n object-fit: cover !important;\n /* Prevent video from being hidden */\n opacity: 1 !important;\n visibility: visible !important;\n position: relative !important;\n }\n \n /* Make controls more touch-friendly on mobile */\n .sf-video-container__controls {\n height: 5px; /* Thicker on mobile for easier touch */\n }\n \n /* Adjust pseudo-element for mobile touch target */\n .sf-video-container__controls::before {\n height: 14px; /* Larger touch target on mobile */\n }\n \n .sf-video-container__mute-button {\n /* Use CSS variable for consistent sizing */\n min-width: var(--sf-mute-button-size) !important;\n min-height: var(--sf-mute-button-size) !important;\n opacity: 1; /* Always visible on mobile (no hover) */\n }\n \n .sf-video-container__cc-button {\n /* Use CSS variable for consistent sizing */\n min-width: var(--sf-cc-button-size) !important;\n min-height: var(--sf-cc-button-size) !important;\n opacity: 1; /* Always visible on mobile (no hover) */\n }\n}\n\n/* Touch device specific styles */\n@media (pointer: coarse) {\n .sf-video-container__controls:hover {\n height: 5px; /* Keep consistent height on touch devices */\n }\n \n /* Maintain consistent clickable area on touch devices */\n .sf-video-container__controls::before,\n .sf-video-container__controls:hover::before {\n height: 14px; /* Consistent touch target */\n }\n \n .sf-video-container__mute-button {\n opacity: 1; /* Always show on touch devices */\n }\n \n .sf-video-container__cc-button {\n opacity: 1; /* Always show on touch devices */\n }\n \n .sf-video-container:hover .sf-video-container__mute-button {\n opacity: 1;\n }\n}\n\n/* Video in minimized state */\n.sf-player--minimized .sf-video-container {\n border-radius: var(--sf-border-radius-circle);\n cursor: pointer;\n z-index: var(--sf-z-index-base);\n width: 100%;\n height: 100%;\n /* Ensure clean clipping in circular state */\n isolation: isolate;\n transform: translateZ(0);\n}\n\n/* Hide gradient overlay when minimized */\n.sf-player--minimized .sf-video-container::after {\n display: none;\n}\n\n.sf-player--minimized .sf-video-container__video {\n border-radius: 0; /* Let container handle clipping */\n object-fit: cover;\n width: 100%;\n height: 100%;\n transform: scale(1.2) translateZ(0);\n}\n\n/* Hide progress bar in minimized state */\n.sf-player--minimized .sf-video-container__controls {\n display: none !important;\n}\n\n/* Also hide mute button in minimized state */\n.sf-player--minimized .sf-video-container__mute-button {\n display: none !important;\n}\n\n/* Also hide CC button in minimized state */\n.sf-player--minimized .sf-video-container__cc-button {\n display: none !important;\n}\n\n/* Progress bar container */\n.sf-video-container__controls {\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n width: 100%;\n height: 4px;\n background-color: rgba(255, 255, 255, 0.3);\n z-index: var(--sf-z-index-controls);\n /* Match the container's top border-radius for seamless integration */\n border-radius: var(--sf-border-radius-md) var(--sf-border-radius-md) 0 0;\n cursor: pointer;\n /* Ensure pixel-perfect alignment and edge-to-edge coverage */\n transform: translateZ(0);\n backface-visibility: hidden;\n /* Smooth transition for height change on hover */\n transition: height 0.15s ease-in-out, background-color 0.15s ease-in-out;\n /* Ensure it covers the full width */\n margin: 0;\n box-sizing: border-box;\n}\n\n/* Invisible pseudo-element to extend clickable area downward */\n.sf-video-container__controls::before {\n content: '';\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n height: 10px; /* Visual height (4px) + extended clickable area (6px) */\n cursor: pointer;\n}\n\n/* Show slightly thicker progress bar on hover for better UX */\n.sf-video-container__controls:hover {\n height: 6px;\n background-color: rgba(255, 255, 255, 0.35);\n}\n\n/* Extend pseudo-element when progress bar grows on hover */\n.sf-video-container__controls:hover::before {\n height: 12px; /* Visual height (6px) + extended clickable area (6px) */\n}\n\n/* Progress indicator */\n.sf-video-container__progress {\n height: 100%;\n background: linear-gradient(90deg, rgba(255, 255, 255, 0.9) 0%, rgba(255, 255, 255, 0.85) 100%);\n width: 0%;\n transition: width 0.1s linear;\n /* Only apply top-left border-radius to maintain seamless look */\n border-radius: var(--sf-border-radius-md) 0 0 0;\n cursor: pointer;\n transform-origin: left;\n /* Ensure smooth rendering */\n will-change: width;\n}\n\n/* Mute button */\n.sf-video-container__mute-button {\n position: absolute;\n top: calc(8px + var(--sf-minimize-button-size) + 6px);\n right: 4px;\n width: var(--sf-mute-button-size);\n height: var(--sf-mute-button-size);\n background: none !important;\n border-radius: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n cursor: pointer;\n z-index: var(--sf-z-index-controls);\n color: white;\n border: none;\n font-size: calc(var(--sf-font-size-md) + 2px);\n transition: all var(--sf-transition-normal);\n text-shadow: 0 1px 3px rgba(0, 0, 0, 0.3);\n opacity: 0;\n}\n\n/* Mute button background circle */\n.sf-video-container__mute-button::before {\n content: '';\n position: absolute;\n width: 80%;\n height: 80%;\n background-color: rgba(0, 0, 0, 0.1);\n border-radius: 50%;\n z-index: -1;\n transition: all var(--sf-transition-normal);\n}\n\n/* Mute button hover state */\n.sf-video-container__mute-button:hover {\n transform: scale(1.1);\n}\n\n/* Show mute button on container hover */\n.sf-video-container:hover .sf-video-container__mute-button {\n opacity: 1;\n}\n\n/* CC button */\n.sf-video-container__cc-button {\n position: absolute;\n top: calc(8px + var(--sf-minimize-button-size) + 6px + var(--sf-mute-button-size) + 6px);\n right: 4px;\n width: var(--sf-cc-button-size);\n height: var(--sf-cc-button-size);\n background: none !important;\n border-radius: 0;\n padding: 0; /* Remove default button padding */\n display: flex;\n align-items: center;\n justify-content: center;\n cursor: pointer;\n z-index: var(--sf-z-index-controls);\n color: white;\n border: none;\n font-size: calc(var(--sf-font-size-md) + 2px);\n transition: all var(--sf-transition-normal);\n text-shadow: 0 1px 3px rgba(0, 0, 0, 0.3);\n opacity: 0;\n}\n\n/* CC button background circle */\n.sf-video-container__cc-button::before {\n content: '';\n position: absolute;\n width: 80%;\n height: 80%;\n background-color: rgba(0, 0, 0, 0.1);\n border-radius: 50%;\n z-index: -1;\n transition: all var(--sf-transition-normal);\n}\n\n.sf-video-container__cc-button svg {\n display: block;\n margin: auto;\n width: 60%;\n height: 60%;\n}\n\n/* CC button hover state */\n.sf-video-container__cc-button:hover {\n transform: scale(1.1);\n}\n\n/* Compact mode styling - circular border-radius for video container */\n.sf-player--compact .sf-video-container {\n border-radius: var(--sf-border-radius-circle);\n}\n\n/* Hide gradient overlay in compact mode (already handled in _player.css but kept for clarity) */\n.sf-player--compact .sf-video-container::after {\n display: none;\n}\n\n/* Hide mute and cc buttons in autoplayBlocked and idleMode states */\n.sf-player--autoplayBlocked .sf-video-container__mute-button,\n.sf-player--autoplayBlocked .sf-video-container__cc-button,\n.sf-player--idleMode .sf-video-container__mute-button,\n.sf-player--idleMode .sf-video-container__cc-button {\n display: none !important;\n}\n\n/* Show mute and cc buttons on hover in playing/paused states */\n.sf-player--playing .sf-video-container:hover .sf-video-container__mute-button,\n.sf-player--playing .sf-video-container:hover .sf-video-container__cc-button,\n.sf-player--paused .sf-video-container:hover .sf-video-container__mute-button,\n.sf-player--paused .sf-video-container:hover .sf-video-container__cc-button {\n opacity: 1;\n} \n /* \n * Controls component styles for the Saltfish playlist Player\n * Following BEM naming convention\n */\n\n/* Main controls container */\n.sf-controls-container {\n position: absolute;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n display: flex;\n justify-content: center;\n align-items: center;\n background-color: transparent;\n z-index: var(--sf-z-index-controls);\n pointer-events: auto;\n}\n\n/* Play button */\n.sf-controls-container__play-button {\n background-color: rgba(0, 0, 0, 0.6);\n border: none;\n color: var(--sf-text-color);\n font-size: var(--sf-control-button-size);\n cursor: pointer;\n width: var(--sf-play-button-size);\n height: var(--sf-play-button-size);\n border-radius: var(--sf-border-radius-circle);\n display: flex;\n justify-content: center;\n align-items: center;\n transition: transform var(--sf-transition-normal), background-color var(--sf-transition-normal);\n padding-left: 4px; /* Optical centering for play icon */\n}\n\n/* Button hover state */\n.sf-controls-container__play-button:hover {\n background-color: rgba(0, 0, 0, 0.4);\n transform: scale(1.1);\n}\n\n/* Button container for interactive buttons */\n.sf-controls-container__buttons {\n display: flex;\n justify-content: center;\n align-items: center;\n gap: var(--sf-spacing-md);\n}\n\n/* Interactive button */\n.sf-controls-container__interactive-button {\n background-color: rgba(255, 255, 255, 0.2);\n backdrop-filter: blur(8px);\n -webkit-backdrop-filter: blur(8px);\n color: white;\n border: none;\n border-radius: var(--sf-border-radius-md);\n padding: var(--sf-spacing-xs) var(--sf-spacing-md);\n font-size: var(--sf-font-size-sm);\n cursor: pointer;\n transition: background-color var(--sf-transition-normal), transform var(--sf-transition-fast);\n box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);\n}\n\n.sf-controls-container__interactive-button:hover {\n background-color: rgba(255, 255, 255, 0.3);\n transform: translateY(-2px);\n}\n\n/* \n * Choice buttons container and buttons - positioned inside player\n */\n\n/* Choice buttons container - positioned inside the player at the bottom */\n.sf-choice-buttons-container {\n position: absolute;\n bottom: var(--sf-spacing-xl);\n left: 50%;\n transform: translateX(-50%);\n width: calc(100% - var(--sf-spacing-lg));\n max-width: calc(100% - var(--sf-spacing-lg));\n z-index: calc(var(--sf-z-index-controls) + 1);\n gap: var(--sf-spacing-sm);\n pointer-events: auto;\n align-items: center;\n display: flex;\n flex-direction: column;\n /* Ensure container is fully transparent */\n background: transparent;\n border: none;\n outline: none;\n}\n\n/* Choice buttons container with scrolling for 5+ buttons */\n.sf-choice-buttons-container--scrollable {\n max-height: 176px; /* Show ~4 buttons with gaps (4 * 36px button + 4 * 8px gap) */\n overflow-y: auto;\n overflow-x: hidden;\n scrollbar-width: thin; /* Show thin scrollbar in Firefox */\n scrollbar-color: rgba(255, 255, 255, 0.2) transparent; /* More transparent Firefox scrollbar */\n scroll-behavior: smooth;\n /* Important: Use block display for scrollable container */\n display: block !important;\n}\n\n/* Style webkit scrollbar to be visible but subtle */\n.sf-choice-buttons-container--scrollable::-webkit-scrollbar {\n width: 4px;\n}\n\n.sf-choice-buttons-container--scrollable::-webkit-scrollbar-track {\n background: transparent;\n}\n\n.sf-choice-buttons-container--scrollable::-webkit-scrollbar-thumb {\n background: rgba(255, 255, 255, 0.2); /* More transparent */\n border-radius: 2px;\n}\n\n.sf-choice-buttons-container--scrollable::-webkit-scrollbar-thumb:hover {\n background: rgba(255, 255, 255, 0.4); /* Still subtle on hover */\n}\n\n/* Removed fade gradient to keep container fully transparent */\n\n/* Choice button styles - solid rounded buttons matching the image */\n.sf-choice-button {\n width: 100%;\n max-width: none;\n background: rgba(0, 0, 0, 4);\n backdrop-filter: blur(8px);\n -webkit-backdrop-filter: blur(8px);\n color: white;\n border: none;\n border-radius: 24px; /* More rounded for pill shape */\n padding: var(--sf-spacing-md) var(--sf-spacing-md);\n font-size: 12px;\n cursor: pointer;\n transition: all 0.2s ease;\n text-align: center;\n outline: none;\n font-family: inherit;\n margin-bottom: 0;\n position: relative;\n overflow: hidden;\n opacity: 0; /* Start hidden for animation */\n pointer-events: none;\n /* Animation will be triggered by JavaScript when video reaches 90% */\n}\n\n/* Add margin between buttons in scrollable container */\n.sf-choice-buttons-container--scrollable .sf-choice-button {\n margin-bottom: var(--sf-spacing-sm);\n}\n\n/* Remove margin from last button */\n.sf-choice-buttons-container--scrollable .sf-choice-button:last-child {\n margin-bottom: 0;\n}\n\n/* Hover state for buttons */\n.sf-choice-button:hover {\n background: rgba(0, 0, 0, 0.9);\n transform: translateY(-2px);\n box-shadow: 0 6px 16px rgba(0, 0, 0, 0.8);\n}\n\n/* Active state for all buttons */\n.sf-choice-button:active {\n transform: translateY(0) scale(0.98);\n transition: all 0.1s ease;\n}\n\n/* Remove specific action type styling - use consistent dark buttons */\n.sf-choice-button--goto,\n.sf-choice-button--url,\n.sf-choice-button--next,\n.sf-choice-button--dom,\n.sf-choice-button--function {\n background: rgba(0, 0, 0, 0.4);\n border: none;\n}\n\n.sf-choice-button--goto:hover,\n.sf-choice-button--url:hover,\n.sf-choice-button--next:hover,\n.sf-choice-button--dom:hover,\n.sf-choice-button--function:hover {\n background: rgba(0, 0, 0, 0.9);\n transform: translateY(-2px);\n box-shadow: 0 6px 16px rgba(0, 0, 0, 0.4);\n}\n\n/* Hide choice buttons in minimized state */\n.sf-player--minimized .sf-choice-buttons-container {\n display: none !important;\n}\n\n/* Hide choice buttons in autoplayBlocked and idleMode states */\n.sf-player--autoplayBlocked .sf-choice-buttons-container,\n.sf-player--idleMode .sf-choice-buttons-container {\n display: none !important;\n}\n\n/* Smaller mobile screens - maintain same layout but with tighter spacing */\n@media (max-width: 480px) {\n .sf-choice-buttons-container {\n bottom: var(--sf-spacing-sm);\n width: calc(100% - var(--sf-spacing-md));\n max-width: calc(100% - var(--sf-spacing-md));\n gap: calc(var(--sf-spacing-xs) + 2px);\n }\n \n .sf-choice-button {\n padding: var(--sf-spacing-sm) var(--sf-spacing-sm);\n font-size: 11px;\n border-radius: 20px;\n }\n}\n\n/* Touch device specific adjustments */\n@media (pointer: coarse) {\n .sf-choice-buttons-container {\n gap: var(--sf-spacing-sm);\n }\n \n .sf-choice-button {\n min-height: 44px; /* Apple's recommended minimum touch target size */\n padding: var(--sf-spacing-md) var(--sf-spacing-md);\n }\n}\n\n/* Button fade-in animation */\n@keyframes buttonFadeIn {\n from {\n opacity: 0;\n transform: translateY(10px);\n }\n to {\n opacity: 1;\n transform: translateY(0);\n }\n}\n\n/* Animation class that will be added by JavaScript at 90% video progress */\n.sf-choice-button.sf-show-button {\n animation: buttonFadeIn 0.3s ease-out forwards;\n pointer-events: auto;\n}\n\n/* Staggered animation delays for multiple buttons when shown */\n.sf-choice-button.sf-show-button:nth-child(1) {\n animation-delay: 0s;\n}\n\n.sf-choice-button.sf-show-button:nth-child(2) {\n animation-delay: 0.15s;\n}\n\n.sf-choice-button.sf-show-button:nth-child(3) {\n animation-delay: 0.3s;\n}\n\n.sf-choice-button.sf-show-button:nth-child(4) {\n animation-delay: 0.45s;\n}\n\n.sf-choice-button.sf-show-button:nth-child(5) {\n animation-delay: 0.6s;\n}\n\n.sf-choice-button.sf-show-button:nth-child(6) {\n animation-delay: 0.75s;\n}\n\n.sf-choice-button.sf-show-button:nth-child(7) {\n animation-delay: 0.9s;\n}\n\n.sf-choice-button.sf-show-button:nth-child(8) {\n animation-delay: 1.05s;\n}\n\n/* Scroll indicator arrow */\n.sf-scroll-indicator {\n position: absolute;\n bottom: calc(var(--sf-spacing-xl) - 25px);\n left: 50%;\n transform: translateX(-50%);\n color: rgba(255, 255, 255, 0.6);\n font-size: 20px;\n pointer-events: none;\n z-index: calc(var(--sf-z-index-controls) + 2);\n transition: opacity 0.3s ease;\n display: flex;\n align-items: center;\n justify-content: center;\n width: 24px;\n height: 24px;\n opacity: 0; /* Start hidden */\n}\n\n/* Show scroll indicator with animation - appears after buttons */\n.sf-scroll-indicator.sf-show-scroll-indicator {\n animation: scrollIndicatorFadeIn 0.4s ease-out 1.2s forwards, bounceArrow 1.5s ease-in-out 1.6s infinite;\n}\n\n/* Hide arrow when scrolled to bottom */\n.sf-scroll-indicator--hidden {\n opacity: 0;\n}\n\n/* Fade in animation for scroll indicator */\n@keyframes scrollIndicatorFadeIn {\n from {\n opacity: 0;\n transform: translateX(-50%) translateY(-10px);\n }\n to {\n opacity: 1;\n transform: translateX(-50%) translateY(0);\n }\n}\n\n/* Bounce animation for the arrow */\n@keyframes bounceArrow {\n 0%, 100% {\n transform: translateX(-50%) translateY(0);\n }\n 50% {\n transform: translateX(-50%) translateY(5px);\n }\n}\n\n/* Hide scroll indicator in minimized state */\n.sf-player--minimized .sf-scroll-indicator {\n display: none !important;\n}\n\n/* Hide scroll indicator in autoplayBlocked and idleMode states */\n.sf-player--autoplayBlocked .sf-scroll-indicator,\n.sf-player--idleMode .sf-scroll-indicator {\n display: none !important;\n} \n /* \n * Transcript component styles for the Saltfish Playlist Player\n * Following BEM naming convention\n */\n\n/* Transcript container */\n.sf-transcript {\n position: absolute;\n bottom: 40px; /* Above the progress bar */\n left: 0;\n right: 0;\n max-height: 200px;\n background: transparent;\n margin: 0 var(--sf-spacing-md);\n overflow: hidden;\n z-index: var(--sf-z-index-controls);\n opacity: 0;\n transform: translateY(20px);\n transition: all 0.3s ease-out;\n pointer-events: none;\n}\n\n/* Visible state */\n.sf-transcript--visible {\n opacity: 1;\n transform: translateY(0);\n pointer-events: auto;\n}\n\n/* Transcript content */\n.sf-transcript__content {\n max-height: 180px;\n overflow: visible;\n padding: 0;\n display: flex;\n justify-content: center;\n align-items: center;\n width: 100%;\n text-align: center;\n}\n\n/* Webkit scrollbar styling */\n.sf-transcript__content::-webkit-scrollbar {\n width: 4px;\n}\n\n.sf-transcript__content::-webkit-scrollbar-track {\n background: transparent;\n}\n\n.sf-transcript__content::-webkit-scrollbar-thumb {\n background: rgba(255, 255, 255, 0.3);\n border-radius: 2px;\n}\n\n.sf-transcript__content::-webkit-scrollbar-thumb:hover {\n background: rgba(255, 255, 255, 0.5);\n}\n\n/* Word-by-word display container - progressive reveal style */\n.sf-transcript__word-container {\n display: flex;\n justify-content: center;\n align-items: center;\n gap: 0.04em; /* Much tighter gap to compensate for inverse scaling effect */\n min-height: 60px;\n padding: 0 var(--sf-spacing-md);\n flex-wrap: nowrap;\n overflow: hidden;\n width: 100%;\n max-width: 100%;\n box-sizing: border-box;\n text-align: center;\n transition: opacity 0.15s ease-in-out; /* Smooth fade during window transitions */\n}\n\n/* Individual word styling - base state (hidden by default) */\n.sf-transcript__word {\n color: rgba(255, 255, 255, 0.65);\n font-size: 20px; /* Increased from 18px to compensate for 0.893 scale (20 * 0.893 ≈ 18px) */\n font-weight: 500; /* Set to 500 from start to prevent pixel shift on activation */\n line-height: 1.3;\n white-space: nowrap;\n text-align: center;\n opacity: 0;\n transform: scale(0.893) translateY(0); /* Scaled down - active word will be normal size (1/1.12 ≈ 0.893) */\n transition: opacity 0.2s ease, color 0.2s ease, text-shadow 0.2s ease, transform 0.2s ease;\n padding-left: 0.12em; /* Consistent padding */\n padding-right: 0.12em;\n}\n\n/* Visible state - word has appeared */\n.sf-transcript__word--visible {\n opacity: 0.8;\n transform: scale(0.893) translateY(0); /* Keep scaled down */\n}\n\n/* Active word (currently speaking) - highlighted at normal size (inverse scale approach) */\n.sf-transcript__word--active {\n color: rgba(255, 255, 255, 1) !important;\n opacity: 1 !important;\n transform: scale(1) translateY(0); /* Normal size - appears 12% larger relative to scaled-down neighbors */\n text-shadow: 0 0 20px rgba(255, 255, 255, 0.3);\n /* font-weight removed - already 500 from base to prevent pixel shift */\n}\n\n/* Legacy segment styling (kept for compatibility) */\n.sf-transcript__segment {\n color: rgba(255, 255, 255);\n font-size: var(--sf-font-size-sm);\n line-height: 1.4;\n padding: var(--sf-spacing-xs) 0;\n cursor: pointer;\n transition: all 0.2s ease;\n padding-left: var(--sf-spacing-xs);\n padding-right: var(--sf-spacing-xs);\n}\n\n/* CC button styling removed - now handled via icon toggling */\n\n/* Mobile responsive styles */\n@media (max-width: 768px) {\n .sf-transcript {\n bottom: 35px; /* Positioned lower on mobile for better visibility */\n margin: 0 var(--sf-spacing-sm);\n max-height: 150px; /* Smaller on mobile */\n }\n\n .sf-transcript__content {\n max-height: 130px;\n padding: var(--sf-spacing-sm);\n }\n\n .sf-transcript__word-container {\n min-height: 50px;\n padding: 0 var(--sf-spacing-sm);\n gap: 0.2em; /* Tighter gap for mobile */\n }\n \n .sf-transcript__word {\n font-size: var(--sf-font-size-md);\n /* font-weight already 500 from base styles */\n }\n \n .sf-transcript__segment {\n font-size: var(--sf-font-size-xs);\n padding: var(--sf-spacing-xs) var(--sf-spacing-sm);\n }\n}\n\n/* Touch device optimizations */\n@media (pointer: coarse) {\n .sf-transcript__segment {\n padding: var(--sf-spacing-sm) var(--sf-spacing-xs);\n min-height: 44px; /* Larger touch target */\n display: flex;\n align-items: center;\n }\n}\n\n/* Hide transcript in minimized state */\n.sf-player--minimized .sf-transcript {\n display: none !important;\n}\n\n/* Hide transcript in autoplayBlocked and idleMode states */\n.sf-player--autoplayBlocked .sf-transcript,\n.sf-player--idleMode .sf-transcript {\n display: none !important;\n}\n\n/* Animation for transcript appearance */\n@keyframes transcriptFadeIn {\n from {\n opacity: 0;\n transform: translateY(20px);\n }\n to {\n opacity: 1;\n transform: translateY(0);\n }\n}\n\n@keyframes transcriptFadeOut {\n from {\n opacity: 1;\n transform: translateY(0);\n }\n to {\n opacity: 0;\n transform: translateY(20px);\n }\n}\n /* \n * Error Display component styles for the Saltfish playlist Player\n * Clean and subtle full-widget error overlay\n */\n\n/* Error display overlay - covers full widget */\n.sf-error-display {\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background-color: rgba(0, 0, 0, 0.75);\n backdrop-filter: blur(6px);\n -webkit-backdrop-filter: blur(6px);\n display: flex;\n align-items: center;\n justify-content: center;\n z-index: calc(var(--sf-z-index-controls) + 30);\n border-radius: var(--sf-border-radius-lg);\n opacity: 0;\n transition: opacity var(--sf-transition-slow);\n pointer-events: auto;\n}\n\n/* Error display visible state */\n.sf-error-display--visible {\n opacity: 1;\n}\n\n/* Error content container */\n.sf-error-display__content {\n background-color: rgba(20, 20, 20, 0.9);\n border-radius: var(--sf-border-radius-md);\n padding: var(--sf-spacing-lg) var(--sf-spacing-xl);\n backdrop-filter: blur(10px);\n -webkit-backdrop-filter: blur(10px);\n border: 1px solid rgba(255, 255, 255, 0.08);\n transform: translateY(8px);\n transition: transform var(--sf-transition-slow);\n max-width: 85%;\n text-align: center;\n}\n\n/* Error content visible animation */\n.sf-error-display--visible .sf-error-display__content {\n transform: translateY(0);\n}\n\n/* Error message */\n.sf-error-display__message {\n color: rgba(255, 255, 255, 0.95);\n font-size: var(--sf-font-size-md);\n line-height: 1.5;\n margin: 0;\n text-align: center;\n font-weight: 500;\n}\n\n/* Mobile responsive adjustments */\n@media (max-width: 768px) {\n .sf-error-display__content {\n padding: var(--sf-spacing-md) var(--sf-spacing-lg);\n max-width: 90%;\n }\n\n .sf-error-display__message {\n font-size: var(--sf-font-size-sm);\n }\n}\n\n/* Minimized player state adjustments */\n.sf-player--minimized .sf-error-display__content {\n padding: var(--sf-spacing-sm) var(--sf-spacing-md);\n max-width: 80%;\n}\n\n.sf-player--minimized .sf-error-display__message {\n font-size: var(--sf-font-size-sm);\n font-weight: 400;\n}\n\n/* High contrast mode support */\n@media (prefers-contrast: high) {\n .sf-error-display__content {\n background-color: rgba(0, 0, 0, 0.95);\n border: 2px solid rgba(255, 255, 255, 0.3);\n }\n\n .sf-error-display__message {\n color: rgba(255, 255, 255, 0.95);\n }\n}\n\n/* Reduced motion support */\n@media (prefers-reduced-motion: reduce) {\n .sf-error-display,\n .sf-error-display__content {\n transition: none;\n }\n}\n /**\n * Loading spinner styles\n */\n\n.sf-loading-spinner {\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n background-color: rgba(255, 255, 255, 0.95);\n backdrop-filter: blur(2px);\n z-index: 100;\n border-radius: 12px;\n opacity: 1 !important; /* Always visible when shown, overrides parent opacity */\n}\n\n.sf-loading-spinner__content {\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 12px;\n padding: 24px;\n}\n\n.sf-loading-spinner__icon {\n display: flex;\n align-items: center;\n justify-content: center;\n color: #000000;\n opacity: 0.9;\n}\n\n.sf-loading-spinner__icon svg {\n width: 60px;\n height: 60px;\n /* Remove the rotation animation since we now have internal SVG animation */\n}\n\n.sf-loading-spinner__text {\n color: #333333;\n font-size: 14px;\n font-weight: 500;\n text-align: center;\n opacity: 0.8;\n letter-spacing: 0.5px;\n}\n\n/* CSS keyframe animation removed - using SVG animateTransform instead */\n\n/* Responsive adjustments */\n@media (max-width: 480px) {\n .sf-loading-spinner__content {\n padding: 20px;\n gap: 10px;\n }\n \n .sf-loading-spinner__icon svg {\n width: 50px;\n height: 50px;\n }\n \n .sf-loading-spinner__text {\n font-size: 13px;\n }\n}\n /*\n * Cursor animation component styles for the Saltfish playlist Player\n * CSP-compliant: All styles use CSS classes and CSS custom properties instead of inline styles\n */\n\n/* Base cursor element */\n.sf-cursor {\n position: fixed;\n top: 0;\n left: 0;\n width: 36px;\n height: 36px;\n z-index: 9999999;\n pointer-events: none;\n display: none;\n will-change: transform;\n transform: var(--sf-cursor-transform, translate(0, 0));\n opacity: var(--sf-cursor-opacity, 1);\n}\n\n.sf-cursor--visible {\n display: block;\n}\n\n/* Selection element */\n.sf-selection {\n position: fixed;\n pointer-events: none;\n display: none;\n z-index: 9999998;\n border: 2px solid var(--sf-selection-color, #ff7614);\n background: var(--sf-selection-bg-color, rgba(255, 118, 20, 0.1));\n border-radius: 4px;\n left: var(--sf-selection-left, 0);\n top: var(--sf-selection-top, 0);\n width: var(--sf-selection-width, 0);\n height: var(--sf-selection-height, 0);\n}\n\n.sf-selection--visible {\n display: block;\n}\n\n/* Flashlight overlay */\n.sf-flashlight-overlay {\n position: fixed;\n top: 0;\n left: 0;\n width: 100vw;\n height: 100vh;\n pointer-events: none;\n z-index: 999997;\n display: none;\n background: var(--sf-flashlight-bg, radial-gradient(circle 150px at 50% 50%, transparent 0%, rgba(0, 0, 0, 0.4) 100%));\n clip-path: var(--sf-flashlight-clip, none);\n}\n\n.sf-flashlight-overlay--visible {\n display: block;\n}\n\n /**\n * Compact Label Styles\n * Label that appears next to the player when in compact first step mode\n * Position adapts based on player placement (left/right)\n */\n\n.sf-compact-label {\n position: absolute;\n top: 50%;\n transform: translateY(-50%);\n\n /* Typography */\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;\n font-size: 14px;\n font-weight: 500;\n line-height: 1.4;\n color: #ffffff;\n\n /* Visual styling */\n background: rgba(0, 0, 0, 0.85);\n backdrop-filter: blur(10px);\n padding: 10px 16px;\n border-radius: 8px;\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3),\n 0 0 0 1px rgba(255, 255, 255, 0.1);\n\n /* Ensure it doesn't wrap */\n white-space: nowrap;\n\n /* Layering */\n z-index: 10;\n\n /* Pointer events - will be enabled via JS when clickable */\n pointer-events: none;\n user-select: none;\n\n /* Smooth transitions for hover effects */\n transition: transform 0.2s cubic-bezier(0.25, 0.8, 0.25, 1),\n box-shadow 0.2s cubic-bezier(0.25, 0.8, 0.25, 1),\n background 0.2s cubic-bezier(0.25, 0.8, 0.25, 1);\n}\n\n/* Position to the LEFT of player (when player is on the right side) */\n.sf-compact-label--left {\n right: calc(100% + 16px); /* 16px spacing from player edge */\n animation: sf-compact-label-enter-from-left 0.4s cubic-bezier(0.25, 0.8, 0.25, 1) forwards;\n}\n\n/* Position to the RIGHT of player (when player is on the left side) */\n.sf-compact-label--right {\n left: calc(100% + 16px); /* 16px spacing from player edge */\n animation: sf-compact-label-enter-from-right 0.4s cubic-bezier(0.25, 0.8, 0.25, 1) forwards;\n}\n\n/* Entrance animation from LEFT - slide in from left with fade */\n@keyframes sf-compact-label-enter-from-left {\n 0% {\n opacity: 0;\n transform: translateY(-50%) translateX(-20px);\n }\n 100% {\n opacity: 1;\n transform: translateY(-50%) translateX(0);\n }\n}\n\n/* Entrance animation from RIGHT - slide in from right with fade */\n@keyframes sf-compact-label-enter-from-right {\n 0% {\n opacity: 0;\n transform: translateY(-50%) translateX(20px);\n }\n 100% {\n opacity: 1;\n transform: translateY(-50%) translateX(0);\n }\n}\n\n/* Hover effect - only applies when label is clickable (pointer-events: auto) */\n.sf-compact-label--left:hover,\n.sf-compact-label--right:hover {\n background: rgba(0, 0, 0, 0.95);\n box-shadow: 0 6px 20px rgba(0, 0, 0, 0.4),\n 0 0 0 1px rgba(255, 255, 255, 0.2),\n 0 0 25px rgba(255, 255, 255, 0.08);\n}\n\n.sf-compact-label--left:hover {\n transform: translateY(-50%) translateX(-2px);\n}\n\n.sf-compact-label--right:hover {\n transform: translateY(-50%) translateX(2px);\n}\n\n/* Active/click state */\n.sf-compact-label--left:active,\n.sf-compact-label--right:active {\n transform: translateY(-50%) scale(0.98);\n}\n\n/* Mobile adjustments */\n@media (max-width: 768px) {\n .sf-compact-label {\n font-size: 12px;\n padding: 8px 12px;\n }\n\n .sf-compact-label--left {\n right: calc(100% + 12px); /* Slightly less spacing on mobile */\n }\n\n .sf-compact-label--right {\n left: calc(100% + 12px); /* Slightly less spacing on mobile */\n }\n}\n\n/* Very small screens - keep to side with tighter spacing */\n@media (max-width: 480px) {\n .sf-compact-label {\n /* Use most of the available screen width - on 390px wide screen this gives ~270px */\n max-width: calc(100vw - 90px - 20px - 8px - 10px); /* viewport - player - margin - spacing - small buffer */\n /* Keep nowrap - we have plenty of space on mobile screens */\n }\n\n .sf-compact-label--left {\n right: calc(100% + 8px); /* Reduce spacing slightly for mobile */\n }\n\n .sf-compact-label--right {\n left: calc(100% + 8px); /* Reduce spacing slightly for mobile */\n }\n}\n\n\n /* \n * Transitions and animations for Saltfish playlist Player\n */\n\n/* Fade in animation */\n@keyframes sf-fade-in {\n from { opacity: 0; }\n to { opacity: 1; }\n}\n\n.sf-fade-in {\n animation: sf-fade-in 0.3s ease-in-out forwards;\n}\n\n/* Slide in from bottom animation */\n@keyframes sf-slide-in-bottom {\n from { transform: translateY(100%); opacity: 0; }\n to { transform: translateY(0); opacity: 1; }\n}\n\n.sf-slide-in-bottom {\n animation: sf-slide-in-bottom 0.3s cubic-bezier(0.25, 0.8, 0.25, 1) forwards;\n}\n\n/* Slide in from right animation */\n@keyframes sf-slide-in-right {\n from { transform: translateX(100%); opacity: 0; }\n to { transform: translateX(0); opacity: 1; }\n}\n\n.sf-slide-in-right {\n animation: sf-slide-in-right 0.3s cubic-bezier(0.25, 0.8, 0.25, 1) forwards;\n}\n\n/* Scale in animation */\n@keyframes sf-scale-in {\n from { transform: scale(0.8); opacity: 0; }\n to { transform: scale(1); opacity: 1; }\n}\n\n.sf-scale-in {\n animation: sf-scale-in 0.3s cubic-bezier(0.25, 0.8, 0.25, 1) forwards;\n}\n\n/* Scale out animation */\n@keyframes sf-scale-out {\n from { transform: scale(1); opacity: 1; }\n to { transform: scale(0.8); opacity: 0; }\n}\n\n.sf-scale-out {\n animation: sf-scale-out 0.3s cubic-bezier(0.25, 0.8, 0.25, 1) forwards;\n} \n"}}class Xt{static isMobile(){return this.getDeviceInfo().isMobile}static isTablet(){return this.getDeviceInfo().isTablet}static isDesktop(){return this.getDeviceInfo().isDesktop}static isTouchDevice(){return this.getDeviceInfo().isTouchDevice}static getOrientation(){return this.getDeviceInfo().orientation}static getDeviceInfo(){if(this.cachedDeviceInfo)return this.cachedDeviceInfo.orientation=this.detectOrientation(),this.cachedDeviceInfo;const t="undefined"!=typeof navigator?navigator.userAgent:"",e=this.detectTouchSupport(),{width:n,height:i}=this.getScreenDimensions(),s=/iPad|Android(?!.*Mobile)|Tablet|tablet/i,r=/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini|Mobile|mobile|CriOS/i.test(t)&&!s.test(t),a=s.test(t),o=this.getScreenSize(n,i),l="small"===o&&Math.min(n,i)<768,c=r||l&&e,d=a||"medium"===o&&!l&&e&&!c,h={isMobile:c,isTablet:d,isDesktop:!c&&!d,isTouchDevice:e,screenSize:o,orientation:this.detectOrientation(),userAgent:t};return this.cachedDeviceInfo=h,h}static detectTouchSupport(){return"undefined"!=typeof window&&("ontouchstart"in window||navigator.maxTouchPoints>0||navigator.msMaxTouchPoints>0)}static getScreenDimensions(){return"undefined"==typeof window?{width:1920,height:1080}:{width:window.innerWidth||document.documentElement.clientWidth||1920,height:window.innerHeight||document.documentElement.clientHeight||1080}}static getScreenSize(t,e){const n=Math.min(t,e);return n<768?"small":n<1024?"medium":"large"}static detectOrientation(){if("undefined"==typeof window)return"landscape";const{width:t,height:e}=this.getScreenDimensions();return e>t?"portrait":"landscape"}static clearCache(){this.cachedDeviceInfo=null}static onDeviceChange(t){if("undefined"==typeof window)return()=>{};const e=()=>{try{this.clearCache(),t(this.getDeviceInfo())}catch(e){console.warn("DeviceDetector: Error in device change handler:",e)}};return window.addEventListener("orientationchange",e),window.addEventListener("resize",e),()=>{window.removeEventListener("orientationchange",e),window.removeEventListener("resize",e)}}}e(Xt,"cachedDeviceInfo",null);const Wt=Object.freeze(Object.defineProperty({__proto__:null,DeviceDetector:Xt,isDeviceCompatible:t=>{if(!t||"both"===t)return!0;const e=Xt.getDeviceInfo();return"mobile"===t?e.isMobile||e.isTablet:"desktop"===t&&e.isDesktop}},Symbol.toStringTag,{value:"Module"})),jt=class t{constructor(){e(this,"transcriptContainer",null),e(this,"transcriptContent",null),e(this,"ccButton",null),e(this,"isVisible",!0),e(this,"currentTranscript",null),e(this,"chunks",[]),e(this,"videoElement",null),e(this,"timeUpdateListener",null),e(this,"videoManager",null),e(this,"firstWordForceDisplayUntil",0),e(this,"isNewVideo",!1),e(this,"lastDisplayedChunkIndex",-1),e(this,"animationFrameId",null),e(this,"isAnimationLoopActive",!1),e(this,"currentWindowStartIndex",-1),e(this,"currentWindowEndIndex",-1)}setup(t,e,n){this.videoElement=t,this.ccButton=e,this.videoManager=n,this.ccButton.addEventListener("click",this.handleCCButtonClick.bind(this)),this.timeUpdateListener=this.handleTimeUpdate.bind(this),this.videoElement.addEventListener("timeupdate",this.timeUpdateListener)}updateVideoElement(t){this.videoElement&&this.timeUpdateListener&&this.videoElement.removeEventListener("timeupdate",this.timeUpdateListener),this.videoElement=t,this.videoElement&&this.timeUpdateListener&&this.videoElement.addEventListener("timeupdate",this.timeUpdateListener)}loadTranscript(e,n=!0){this.transcriptContent&&(this.transcriptContent.innerHTML=""),this.lastDisplayedChunkIndex=-1,this.currentWindowStartIndex=-1,this.currentWindowEndIndex=-1,this.currentTranscript=e,e?(this.createTranscriptUI(),this.chunks=e.chunks||[],this.isNewVideo=!0,this.firstWordForceDisplayUntil=Date.now()+500,this.setupWordDisplay(),null!==t.userCaptionPreference?(this.isVisible=t.userCaptionPreference,this.isVisible):(this.isVisible=n,this.isVisible),this.updateCCButtonState(!0),this.isVisible?this.showTranscript():this.hideTranscript(),this.chunks.length,this.isVisible):(this.updateCCButtonState(!1),this.hideTranscript())}toggleVisibility(){this.currentTranscript&&(this.isVisible=!this.isVisible,t.userCaptionPreference=this.isVisible,this.isVisible,this.isVisible?(this.showTranscript(),this.startAnimationLoop()):(this.hideTranscript(),this.stopAnimationLoop()),this.updateCCButtonState(!!this.currentTranscript),this.isVisible)}handleCCButtonClick(t){t.preventDefault(),t.stopPropagation(),this.toggleVisibility()}handleTimeUpdate(t){!this.isAnimationLoopActive&&this.isVisible&&this.chunks.length>0&&this.startAnimationLoop()}startAnimationLoop(){if(this.isAnimationLoopActive)return;this.isAnimationLoopActive=!0;const t=()=>{if(!this.currentTranscript||!this.isVisible||!this.videoElement||0===this.chunks.length)return void this.stopAnimationLoop();const e=this.videoElement.currentTime;let n=this.findActiveChunkIndex(e);const i=Date.now();this.isNewVideo&&i<this.firstWordForceDisplayUntil&&this.chunks.length>0?n=0:this.isNewVideo&&i>=this.firstWordForceDisplayUntil&&(this.isNewVideo=!1),this.updateIntelligentWordDisplay(n),this.animationFrameId=requestAnimationFrame(t)};this.animationFrameId=requestAnimationFrame(t)}stopAnimationLoop(){null!==this.animationFrameId&&(cancelAnimationFrame(this.animationFrameId),this.animationFrameId=null),this.isAnimationLoopActive=!1}findActiveChunkIndex(t){if(0===this.chunks.length)return-1;for(let e=0;e<this.chunks.length;e++){const n=this.chunks[e];if(t>=n.start&&t<=n.end)return e}if(t<this.chunks[0].start)return 0;if(t>this.chunks[this.chunks.length-1].end)return this.chunks.length-1;for(let e=0;e<this.chunks.length-1;e++)if(t>this.chunks[e].end&&t<this.chunks[e+1].start){if(this.chunks[e+1].start-t<.1)return e+1;return t-this.chunks[e].end<.1?e:e+1}return-1}handleStateChange(t){if(this.currentTranscript,this.chunks.length,this.currentTranscript&&0!==this.chunks.length)return"waitingForInteraction"===t||"completedWaitingForInteraction"===t?(this.transcriptContent&&(this.transcriptContent.innerHTML=""),void this.stopAnimationLoop()):void(this.isVisible?(this.isVisible,this.showTranscript(),this.startAnimationLoop()):(this.isVisible,this.hideTranscript(),this.stopAnimationLoop()));this.stopAnimationLoop()}updateIntelligentWordDisplay(t){if(!this.transcriptContent)return;if(t===this.lastDisplayedChunkIndex)return;if(!(t>=0&&t<this.chunks.length?this.chunks[t]:null))return this.lastDisplayedChunkIndex=-1,void(this.transcriptContent.innerHTML="");t>=this.currentWindowStartIndex&&t<=this.currentWindowEndIndex&&-1!==this.currentWindowStartIndex?this.updateHighlightInWindow(t):this.createNewWindow(t),this.lastDisplayedChunkIndex=t}updateHighlightInWindow(t){if(!this.transcriptContent)return;const e=this.transcriptContent.querySelectorAll(".sf-transcript__word"),n=t-this.currentWindowStartIndex;e.forEach(((t,e)=>{t.classList.remove("sf-transcript__word--active"),e<=n?t.classList.add("sf-transcript__word--visible"):t.classList.remove("sf-transcript__word--visible")})),e[n]&&e[n].classList.add("sf-transcript__word--active")}createNewWindow(t){if(!this.transcriptContent)return;const e=this.calculateWordWindow(t);this.currentWindowStartIndex=e.startIndex,this.currentWindowEndIndex=e.endIndex;const n=this.transcriptContent.querySelector(".sf-transcript__word-container"),i=()=>{const n=document.createElement("div");n.className="sf-transcript__word-container";const i=t-e.startIndex;for(let s=e.startIndex;s<=e.endIndex;s++){const r=this.chunks[s],a=document.createElement("span");let o="sf-transcript__word";s-e.startIndex<=i&&(o+=" sf-transcript__word--visible"),s===t&&(o+=" sf-transcript__word--active"),a.className=o,a.textContent=r.text,n.appendChild(a)}return n};if(n)n.style.opacity="0",setTimeout((()=>{if(!this.transcriptContent)return;this.transcriptContent.innerHTML="";const t=i();t.style.opacity="0",this.transcriptContent.appendChild(t),requestAnimationFrame((()=>{t.style.opacity="1"}))}),150);else{const t=i();this.transcriptContent.appendChild(t)}}calculateWordWindow(t){if(t<0||t>=this.chunks.length)return{startIndex:-1,endIndex:-1};let e=t,n=t,i=this.chunks[t].text.length;const s=this.chunks[t].text.trim();if(s.endsWith(".")||s.endsWith("!")||s.endsWith("?"))return{startIndex:e,endIndex:n};for(;n-e+1<4&&n+1<this.chunks.length;){const t=this.chunks[n+1].text,e=Math.ceil(1.12*t.length);if(i+e>18)break;n++,i+=e;const s=t.trim();if(s.endsWith(".")||s.endsWith("!")||s.endsWith("?"))break}return{startIndex:e,endIndex:n}}createTranscriptUI(){var t;this.transcriptContainer&&this.transcriptContainer.parentNode&&(this.transcriptContainer.parentNode.removeChild(this.transcriptContainer),this.transcriptContainer=null,this.transcriptContent=null);const e=null==(t=this.videoElement)?void 0:t.closest(".sf-video-container");e&&(this.transcriptContainer=document.createElement("div"),this.transcriptContainer.className="sf-transcript",this.transcriptContainer.classList.add("sf-hidden"),this.transcriptContent=document.createElement("div"),this.transcriptContent.className="sf-transcript__content",this.transcriptContainer&&this.transcriptContent&&(this.transcriptContainer.appendChild(this.transcriptContent),e.appendChild(this.transcriptContainer)))}setupWordDisplay(){this.transcriptContent&&(this.transcriptContent.innerHTML="")}showTranscript(){this.transcriptContainer,this.transcriptContainer&&(this.transcriptContainer.classList.remove("sf-hidden"),this.transcriptContainer.classList.add("sf-transcript--visible"))}hideTranscript(){this.transcriptContainer,this.transcriptContainer&&(this.transcriptContainer.classList.add("sf-hidden"),this.transcriptContainer.classList.remove("sf-transcript--visible"))}updateCCButtonState(t){var e;this.ccButton&&(t?(this.ccButton.classList.remove("sf-hidden"),null==(e=this.videoManager)||e.updateCCButtonIcon(this.isVisible)):this.ccButton.classList.add("sf-hidden"))}reset(){this.stopAnimationLoop(),this.transcriptContent&&(this.transcriptContent.innerHTML=""),this.currentTranscript=null,this.chunks=[],this.isNewVideo=!1,this.firstWordForceDisplayUntil=0,this.lastDisplayedChunkIndex=-1,this.currentWindowStartIndex=-1,this.currentWindowEndIndex=-1,this.isVisible&&this.hideTranscript(),this.updateCCButtonState(!1),this.transcriptContainer=null,this.transcriptContent=null}static resetUserPreference(){t.userCaptionPreference=null}async destroy(){this.stopAnimationLoop(),this.timeUpdateListener&&this.videoElement&&this.videoElement.removeEventListener("timeupdate",this.timeUpdateListener),this.transcriptContainer&&this.transcriptContainer.parentNode&&this.transcriptContainer.parentNode.removeChild(this.transcriptContainer),this.transcriptContainer=null,this.transcriptContent=null,this.ccButton=null,this.videoElement=null,this.timeUpdateListener=null,this.currentTranscript=null,this.isVisible=!1}};e(jt,"userCaptionPreference",null);let qt=jt;class Zt{constructor(t){e(this,"deviceInfo"),this.deviceInfo=t}updateDeviceInfo(t){this.deviceInfo=t}}class Gt extends Zt{getVideoElementConfig(){return{playsInline:!0,muted:!0,controls:!1,preload:"metadata",additionalAttributes:{"webkit-playsinline":"true",playsinline:"true","x-webkit-airplay":"allow"},styles:{width:"100%",height:"100%",objectFit:"cover",backgroundColor:"white"}}}getControlsConfig(){return{buttonMinSize:{width:"44px",height:"44px"},useTouch:!0,progressUpdateInterval:500}}getAutoplayConfig(t){return{shouldStartMuted:!t,enableFallbackLoop:!0,fallbackTimeout:3e3,requiresUserInteraction:!0}}configureVideoElement(t){const e=this.getVideoElementConfig();t.playsInline=e.playsInline,t.muted=e.muted,t.controls=e.controls,t.preload=e.preload,Object.entries(e.additionalAttributes).forEach((([e,n])=>{try{t.setAttribute(e,n)}catch(i){console.warn(`MobilePlaybackHandler: Failed to set attribute ${e}:`,i)}})),Object.entries(e.styles).forEach((([e,n])=>{try{t.style.setProperty(e,n)}catch(i){console.warn(`MobilePlaybackHandler: Failed to set style ${e}:`,i)}}))}configureControlElement(t){const e=this.getControlsConfig();t.style.setProperty("min-width",e.buttonMinSize.width),t.style.setProperty("min-height",e.buttonMinSize.height)}async handlePlayAttempt(t,e){const n=bt().isMuted;t.muted=n,t.loop=!1;try{return await t.play(),!0}catch(i){return t.muted,await this.handleAutoplayFallback(t),!1}}async handleAutoplayFallback(t){t.muted=!0,t.loop=!0,t.playsInline=!0,t.setAttribute("playsinline","true"),t.setAttribute("webkit-playsinline","true");try{await t.play()}catch(e){console.error("MobilePlaybackHandler: All autoplay attempts failed")}}destroy(){}getProgressUpdateFrequency(t){return t?500:16}}class Kt extends Zt{getVideoElementConfig(){return{playsInline:!0,muted:!1,controls:!1,preload:"metadata",additionalAttributes:{},styles:{backgroundColor:"white"}}}getControlsConfig(){return{buttonMinSize:{width:"auto",height:"auto"},useTouch:!1,progressUpdateInterval:16}}getAutoplayConfig(t){return{shouldStartMuted:!1,enableFallbackLoop:!1,fallbackTimeout:5e3,requiresUserInteraction:!1}}configureVideoElement(t){const e=this.getVideoElementConfig();t.playsInline=e.playsInline,t.muted=e.muted,t.controls=e.controls,t.preload=e.preload,Object.entries(e.styles).forEach((([e,n])=>{t.style.setProperty(e,n)}))}configureControlElement(t){}async handlePlayAttempt(t,e){const n=bt().isMuted;t.muted=n,t.loop=!1;try{return await t.play(),!0}catch(i){return t.muted,await this.handleAutoplayFallback(t),!1}}async handleAutoplayFallback(t){t.muted=!0,t.loop=!0;try{await t.play()}catch(e){throw console.error("DesktopPlaybackHandler: All autoplay attempts failed"),new Error("Desktop autoplay completely blocked")}}getProgressUpdateFrequency(t){return 16}destroy(){}}class Jt{constructor(t,n,i){e(this,"container"),e(this,"controlsElement",null),e(this,"progressBar",null),e(this,"muteButton",null),e(this,"ccButton",null),e(this,"deviceHandler"),e(this,"callbacks"),e(this,"updateInterval",null),e(this,"animationFrameId",null),e(this,"lastTimeupdateEvent",0),e(this,"videoElement",null),e(this,"buttonsShownAt90Percent",!1),e(this,"handleDetailedTimeUpdate",(()=>{var t;if(this.lastTimeupdateEvent=Date.now(),this.progressBar&&!1===(null==(t=this.videoElement)?void 0:t.paused)&&this.progressBar.style.setProperty("transition","width 0.1s linear"),this.videoElement&&!this.buttonsShownAt90Percent&&this.videoElement.duration>0){this.videoElement.currentTime/this.videoElement.duration>=.9&&(this.callbacks.on90PercentReached(),this.buttonsShownAt90Percent=!0)}})),e(this,"handleSeeking",(()=>{this.progressBar&&(this.progressBar.style.setProperty("transition","none"),this.updateProgress())})),e(this,"handleSeeked",(()=>{this.progressBar&&this.videoElement&&(this.videoElement.paused||(this.updateProgress(),this.progressBar.offsetWidth,this.progressBar.style.setProperty("transition","width 0.1s linear")))})),e(this,"handleProgressBarClick",(t=>{const e=t.currentTarget;if(!this.videoElement||this.videoElement.duration<=0)return;const n=e.getBoundingClientRect(),i=(t.clientX-n.left)/n.width,s=this.videoElement.duration*i;this.progressBar&&(this.progressBar.style.setProperty("transition","none"),this.progressBar.style.setProperty("width",100*i+"%")),this.callbacks.onSeek(s),t.preventDefault(),t.stopPropagation()})),this.container=t,this.deviceHandler=n,this.callbacks=i}create(t){this.videoElement=t,this.controlsElement=document.createElement("div"),this.controlsElement.className="sf-video-container__controls",this.container.appendChild(this.controlsElement),this.progressBar=document.createElement("div"),this.progressBar.className="sf-video-container__progress",this.controlsElement.appendChild(this.progressBar);const e=this.deviceHandler.getControlsConfig();e.useTouch&&this.controlsElement.addEventListener("touchend",this.handleProgressBarClick),this.controlsElement.addEventListener("click",this.handleProgressBarClick),this.muteButton=document.createElement("button"),this.muteButton.className="sf-video-container__mute-button",this.deviceHandler.configureControlElement(this.muteButton),this.muteButton.innerHTML='\n <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">\n <polygon points="11 5 6 9 2 9 2 15 6 15 11 19 11 5" fill="none"></polygon>\n <path d="M15 9c0.8 0.8 1.5 1.9 1.5 3s-0.7 2.2-1.5 3" stroke="currentColor"></path>\n <path d="M19 7c1.6 1.6 2.5 3.8 2.5 6s-0.9 4.4-2.5 6" stroke="currentColor"></path>\n </svg>\n ',e.useTouch&&this.muteButton.addEventListener("touchend",(t=>{t.preventDefault(),this.toggleMute()})),this.muteButton.addEventListener("click",(t=>{t.preventDefault(),t.stopPropagation(),this.toggleMute()})),this.container.appendChild(this.muteButton),this.updateMuteButtonIcon(),this.ccButton=document.createElement("button"),this.ccButton.className="sf-video-container__cc-button",this.deviceHandler.configureControlElement(this.ccButton),this.updateCCButtonIcon(!1),e.useTouch&&this.ccButton.addEventListener("touchend",(t=>{t.preventDefault()})),this.ccButton.addEventListener("click",(t=>{t.preventDefault()})),this.container.appendChild(this.ccButton),t&&(t.addEventListener("seeking",this.handleSeeking),t.addEventListener("seeked",this.handleSeeked),t.addEventListener("timeupdate",this.handleDetailedTimeUpdate))}updateVideoElement(t){this.videoElement&&(this.videoElement.removeEventListener("seeking",this.handleSeeking),this.videoElement.removeEventListener("seeked",this.handleSeeked),this.videoElement.removeEventListener("timeupdate",this.handleDetailedTimeUpdate)),this.videoElement=t,t&&(t.addEventListener("seeking",this.handleSeeking),t.addEventListener("seeked",this.handleSeeked),t.addEventListener("timeupdate",this.handleDetailedTimeUpdate))}reset(){this.stopProgressTracking(),this.buttonsShownAt90Percent=!1,this.lastTimeupdateEvent=0,this.progressBar&&(this.progressBar.style.setProperty("transition","none"),this.progressBar.style.setProperty("width","0%"))}reset90PercentTrigger(){this.buttonsShownAt90Percent=!1}destroy(){if(this.stopProgressTracking(),this.videoElement&&(this.videoElement.removeEventListener("seeking",this.handleSeeking),this.videoElement.removeEventListener("seeked",this.handleSeeked),this.videoElement.removeEventListener("timeupdate",this.handleDetailedTimeUpdate)),this.controlsElement){this.deviceHandler.getControlsConfig().useTouch&&this.controlsElement.removeEventListener("touchend",this.handleProgressBarClick),this.controlsElement.removeEventListener("click",this.handleProgressBarClick)}this.controlsElement=null,this.progressBar=null,this.muteButton=null,this.ccButton=null,this.videoElement=null}startProgressTracking(){if(this.stopProgressTracking(),!this.videoElement)return;const t=this.videoElement.loop&&this.videoElement.muted,e=this.deviceHandler.getProgressUpdateFrequency(t);if(e>=16){const t=()=>{!this.videoElement||this.videoElement.paused||this.videoElement.ended||this.updateProgress(),this.animationFrameId=requestAnimationFrame(t)};this.animationFrameId=requestAnimationFrame(t)}else{const t=()=>{null===this.updateInterval||!this.videoElement||this.videoElement.paused||this.videoElement.ended||(this.updateProgress(),this.updateInterval=window.setTimeout(t,e))};this.updateInterval=window.setTimeout(t,e)}}stopProgressTracking(){null!==this.updateInterval&&(window.clearInterval(this.updateInterval),this.updateInterval=null),null!==this.animationFrameId&&(cancelAnimationFrame(this.animationFrameId),this.animationFrameId=null)}updateProgressImmediate(t,e){if(!this.progressBar||e<=0)return;const n=t/e*100;this.progressBar.style.setProperty("transition","none"),this.progressBar.style.setProperty("width",`${n}%`)}updateProgress(){if(!this.progressBar||!this.videoElement)return;const t=this.videoElement.currentTime||0,e=this.videoElement.duration||0;if(e>0){const n=t/e*100,i="none"!==this.progressBar.style.getPropertyValue("transition"),s=Date.now()-this.lastTimeupdateEvent;this.progressBar.style.setProperty("transition","none"),this.progressBar.style.setProperty("width",`${n}%`),this.progressBar.offsetWidth,this.videoElement.ended?this.progressBar.style.setProperty("transition","width 0.2s ease-out"):!this.videoElement.paused&&!this.videoElement.seeking&&i&&s<500&&this.progressBar.style.setProperty("transition","width 0.1s linear")}}setMuted(t){bt().setMuted(t),this.updateMuteButtonIcon()}toggleMute(){const t=!bt().isMuted;this.setMuted(t),this.callbacks.onMuteToggle()}getMuted(){return bt().isMuted}updateMuteButtonIcon(){if(!this.muteButton)return;const t=bt().isMuted;this.muteButton.innerHTML=t?'\n <svg width="18" height="18" viewBox="0 0 256 256" fill="currentColor" xmlns="http://www.w3.org/2000/svg">\n <path d="M155.51,24.81a8,8,0,0,0-8.42.88L77.25,80H32A16,16,0,0,0,16,96v64a16,16,0,0,0,16,16H77.25l69.84,54.31A8,8,0,0,0,160,224V32A8,8,0,0,0,155.51,24.81ZM32,96H72v64H32ZM144,207.64,88,164.09V91.91l56-43.55Zm101.66-61.3a8,8,0,0,1-11.32,11.32L216,139.31l-18.34,18.35a8,8,0,0,1-11.32-11.32L204.69,128l-18.35-18.34a8,8,0,0,1,11.32-11.32L216,116.69l18.34-18.35a8,8,0,0,1,11.32,11.32L227.31,128Z"></path>\n </svg>\n ':'\n <svg width="18" height="18" viewBox="0 0 256 256" fill="currentColor" xmlns="http://www.w3.org/2000/svg">\n <path d="M155.51,24.81a8,8,0,0,0-8.42.88L77.25,80H32A16,16,0,0,0,16,96v64a16,16,0,0,0,16,16H77.25l69.84,54.31A8,8,0,0,0,160,224V32A8,8,0,0,0,155.51,24.81ZM32,96H72v64H32ZM144,207.64,88,164.09V91.91l56-43.55Zm54-106.08a40,40,0,0,1,0,52.88,8,8,0,0,1-12-10.58,24,24,0,0,0,0-31.72,8,8,0,0,1,12-10.58ZM248,128a79.9,79.9,0,0,1-20.37,53.34,8,8,0,0,1-11.92-10.67,64,64,0,0,0,0-85.33,8,8,0,1,1,11.92-10.67A79.83,79.83,0,0,1,248,128Z"></path>\n </svg>\n '}updateCCButtonIcon(t){this.ccButton&&(this.ccButton.innerHTML=t?'\n <svg width="18" height="18" viewBox="0 0 256 256" fill="currentColor" xmlns="http://www.w3.org/2000/svg">\n <path d="M224,48H32A16,16,0,0,0,16,64V192a16,16,0,0,0,16,16H224a16,16,0,0,0,16-16V64A16,16,0,0,0,224,48Zm0,144H32V64H224V192ZM118.92,151.71A8,8,0,0,1,116,162.64a40,40,0,1,1,0-69.28,8,8,0,1,1-8,13.85,24,24,0,1,0,0,41.58A8,8,0,0,1,118.92,151.71Zm80,0A8,8,0,0,1,196,162.64a40,40,0,1,1,0-69.28,8,8,0,1,1-8,13.85,24,24,0,1,0,0,41.58A8,8,0,0,1,198.92,151.71Z"></path>\n </svg>\n ':'\n <svg width="18" height="18" viewBox="0 0 256 256" fill="currentColor" xmlns="http://www.w3.org/2000/svg">\n <path d="M224,48H32A16,16,0,0,0,16,64V192a16,16,0,0,0,16,16H224a16,16,0,0,0,16-16V64A16,16,0,0,0,224,48Zm0,144H32V64H224V192ZM118.92,151.71A8,8,0,0,1,116,162.64a40,40,0,1,1,0-69.28,8,8,0,1,1-8,13.85,24,24,0,1,0,0,41.58A8,8,0,0,1,118.92,151.71Zm80,0A8,8,0,0,1,196,162.64a40,40,0,1,1,0-69.28,8,8,0,1,1-8,13.85,24,24,0,1,0,0,41.58A8,8,0,0,1,198.92,151.71Z"></path>\n <line x1="48" y1="48" x2="208" y2="208" stroke="currentColor" stroke-width="16" stroke-linecap="round"/>\n </svg>\n ')}showProgressBar(){if(this.controlsElement){const t=this.controlsElement.closest(".sf-player");null==t||t.classList.contains("sf-player--minimized");this.controlsElement.classList.remove("sf-hidden")}this.progressBar&&(this.progressBar.style.setProperty("transition","none"),this.progressBar.style.setProperty("width","0%"),this.progressBar.offsetWidth,this.progressBar.style.setProperty("transition","width 0.1s linear"))}hideProgressBar(){this.controlsElement&&this.controlsElement.classList.add("sf-hidden")}showMuteButton(){this.muteButton&&this.muteButton.classList.remove("sf-hidden")}hideMuteButton(){this.muteButton&&this.muteButton.classList.add("sf-hidden")}getCCButton(){return this.ccButton}}class Qt{constructor(){e(this,"audioContext",null),e(this,"analyser",null),e(this,"sourceVideo1",null),e(this,"sourceVideo2",null),e(this,"activeSource",null),e(this,"videoElement1",null),e(this,"videoElement2",null),e(this,"dataArray",null),e(this,"animationId",null),e(this,"isInitialized",!1),e(this,"useFallbackMode",!1),e(this,"isPaused",!1),e(this,"fftSize",2048),e(this,"barCount",12),e(this,"smoothingTimeConstant",.75),e(this,"fallbackTime",0),e(this,"zeroDataFrameCount",0),e(this,"maxZeroFramesBeforeFallback",60)}initialize(t){try{if(!this.isInitialized){const t=window.AudioContext||window.webkitAudioContext;this.audioContext=new t,this.analyser=this.audioContext.createAnalyser(),this.analyser.fftSize=this.fftSize,this.analyser.smoothingTimeConstant=this.smoothingTimeConstant;const e=this.analyser.frequencyBinCount;this.dataArray=new Uint8Array(e),this.analyser.connect(this.audioContext.destination),this.isInitialized=!0,this.useFallbackMode=!1,this.zeroDataFrameCount=0}if(this.videoElement1===t)return this.resumeAudioContext(),void this.switchToSource(this.sourceVideo1);if(this.videoElement2===t)return this.resumeAudioContext(),void this.switchToSource(this.sourceVideo2);this.resumeAudioContext();const e=this.audioContext.createMediaElementSource(t);this.videoElement1?this.videoElement2?console.warn("AudioVisualizationManager: More than 2 video elements detected - this should not happen with dual video system"):(this.videoElement2=t,this.sourceVideo2=e,this.switchToSource(e)):(this.videoElement1=t,this.sourceVideo1=e,this.switchToSource(e)),this.zeroDataFrameCount=0}catch(e){console.warn("AudioVisualizationManager: Web Audio API failed, using fallback animation",e),this.isInitialized=!0,this.useFallbackMode=!0}}switchToSource(t){this.activeSource&&this.activeSource!==t&&this.activeSource.disconnect(),t.connect(this.analyser),this.activeSource=t}getBarHeights(){if(this.isPaused)return this.getFlatBarHeights();if(this.useFallbackMode||!this.analyser||!this.dataArray)return this.getFallbackBarHeights();this.analyser.getByteFrequencyData(this.dataArray);const t=this.dataArray.some((t=>t>0));if(!t)return this.zeroDataFrameCount++,this.zeroDataFrameCount>=this.maxZeroFramesBeforeFallback&&(this.useFallbackMode||(console.warn("AudioVisualizationManager: Detected CORS blocking audio analysis after",this.zeroDataFrameCount,"frames, switching to fallback animation"),this.useFallbackMode=!0)),this.getFallbackBarHeights();this.zeroDataFrameCount=0,this.useFallbackMode&&t&&(this.useFallbackMode=!1);const e=Math.floor(this.barCount/2),n=[],i=this.dataArray.length,s=Math.floor(i/this.barCount);for(let a=0;a<e;a++){let t=0;const e=a*s,r=e+s;for(let n=e;n<r&&n<i;n++)t+=this.dataArray[n];const o=t/s/255;n.push(o)}const r=[...n].reverse();r.pop();return r.concat(n)}getFallbackBarHeights(){const t=Math.floor(this.barCount/2),e=[];for(let i=0;i<t;i++)e.push(0);const n=[...e].reverse();n.pop();return n.concat(e)}getFlatBarHeights(){const t=Math.floor(this.barCount/2),e=[];for(let i=0;i<t;i++)e.push(.1);const n=[...e].reverse();n.pop();return n.concat(e)}getAverageAmplitude(){if(this.useFallbackMode||!this.analyser||!this.dataArray)return 0;this.analyser.getByteFrequencyData(this.dataArray);let t=0;for(let n=0;n<this.dataArray.length;n++)t+=this.dataArray[n];const e=t/this.dataArray.length/255;return 0===e?0:e}startVisualization(t){if(!this.isInitialized)return void console.warn("AudioVisualizationManager: Cannot start visualization - not initialized");null!==this.animationId&&this.stopVisualization(),this.audioContext&&"suspended"===this.audioContext.state&&this.audioContext.resume(),this.fallbackTime=0,this.zeroDataFrameCount=0;const e=()=>{this.fallbackTime+=16;const n=this.getBarHeights(),i=this.getAverageAmplitude();t(n,i),this.animationId=requestAnimationFrame(e)};e()}stopVisualization(){null!==this.animationId&&(cancelAnimationFrame(this.animationId),this.animationId=null)}pause(){this.isPaused=!0}resume(){this.isPaused=!1}resumeAudioContext(){this.audioContext&&"suspended"===this.audioContext.state&&this.audioContext.resume().catch((t=>{console.warn("AudioVisualizationManager: Failed to resume AudioContext",t)}))}resetFallbackMode(){this.useFallbackMode&&(this.useFallbackMode=!1,this.zeroDataFrameCount=0)}getIsInitialized(){return this.isInitialized}reset(){if(this.stopVisualization(),this.sourceVideo1)try{this.sourceVideo1.disconnect()}catch(t){}if(this.sourceVideo2)try{this.sourceVideo2.disconnect()}catch(t){}this.videoElement1=null,this.videoElement2=null,this.sourceVideo1=null,this.sourceVideo2=null,this.activeSource=null,this.useFallbackMode=!1,this.isPaused=!1,this.fallbackTime=0,this.zeroDataFrameCount=0}cleanup(){this.stopVisualization(),this.sourceVideo1&&this.sourceVideo1.disconnect(),this.sourceVideo2&&this.sourceVideo2.disconnect(),this.analyser&&this.analyser.disconnect(),this.audioContext&&"closed"!==this.audioContext.state&&this.audioContext.close(),this.audioContext=null,this.analyser=null,this.sourceVideo1=null,this.sourceVideo2=null,this.activeSource=null,this.videoElement1=null,this.videoElement2=null,this.dataArray=null,this.isInitialized=!1,this.useFallbackMode=!1,this.isPaused=!1,this.fallbackTime=0,this.zeroDataFrameCount=0}destroy(){this.cleanup()}}class te{constructor(){e(this,"currentVideo",null),e(this,"nextVideo",null),e(this,"activeVideoIndex",0),e(this,"container",null),e(this,"controls",null),e(this,"transcriptManager"),e(this,"preloadedVideos",new Map),e(this,"audioFallbackOverlay",null),e(this,"audioVisualizationManager"),e(this,"soundbarElement",null),e(this,"currentVideoUrl",""),e(this,"nextVideoUrl",""),e(this,"playbackPositions",new Map),e(this,"completionPolicy","auto"),e(this,"videoEndedCallback",null),e(this,"deviceHandler"),e(this,"deviceChangeCleanup",null),e(this,"hasUserInteracted",!1),e(this,"autoplayFallbackTimeout",null),e(this,"handleVideoEnded",(t=>{const e=t.target,n=this.getActiveVideo();if(e!==n)return;const i=bt();"autoplayBlocked"!==i.currentState&&"idleMode"!==i.currentState?(this.controls&&n&&this.controls.updateProgressImmediate(n.duration,n.duration),n&&n.classList.add("sf-video-container__video--blurred"),"auto"===this.completionPolicy?this.handleAutoVideoEnded():this.handleManualVideoEnded()):i.currentState})),e(this,"handleTimeUpdate",(t=>{const e=t.target;e===this.getActiveVideo()&&Math.floor(e.currentTime)})),e(this,"handleVideoError",(t=>{const e=t.target;e===this.getActiveVideo()&&console.error("VideoManager: Video error",e.error)})),e(this,"handleAutoVideoEnded",(()=>{this.videoEndedCallback&&this.videoEndedCallback()})),e(this,"handleManualVideoEnded",(()=>{this.videoEndedCallback&&this.videoEndedCallback()}));const t=Xt.getDeviceInfo();this.deviceHandler=function(t){return t.isMobile?new Gt(t):new Kt(t)}(t),this.transcriptManager=new qt,this.audioVisualizationManager=new Qt,this.deviceChangeCleanup=Xt.onDeviceChange((t=>{this.deviceHandler.updateDeviceInfo(t)}))}getDeviceInfo(){return Xt.getDeviceInfo()}isMobileDevice(){return this.getDeviceInfo().isMobile}create(t){this.container=document.createElement("div"),this.container.className="sf-video-container",t.appendChild(this.container),this.currentVideo=document.createElement("video"),this.currentVideo.className="sf-video-container__video sf-video-container__video--current",this.currentVideo.crossOrigin="anonymous",this.deviceHandler.configureVideoElement(this.currentVideo),this.container.appendChild(this.currentVideo),this.nextVideo=document.createElement("video"),this.nextVideo.className="sf-video-container__video sf-video-container__video--next sf-hidden",this.nextVideo.crossOrigin="anonymous",this.deviceHandler.configureVideoElement(this.nextVideo),this.container.appendChild(this.nextVideo);bt().isMuted&&(this.currentVideo.muted=!0,this.nextVideo.muted=!0);const e={onSeek:t=>this.seek(t),onMuteToggle:()=>{var t;const e=(null==(t=this.controls)?void 0:t.getMuted())??!1;this.currentVideo&&(this.currentVideo.muted=e),this.nextVideo&&(this.nextVideo.muted=e),!e&&this.audioVisualizationManager.getIsInitialized()&&this.audioVisualizationManager.resetFallbackMode()},on90PercentReached:()=>{if(this.container){const t=new CustomEvent("video90PercentReached",{bubbles:!0,detail:{timestamp:Date.now()}});this.container.dispatchEvent(t)}}};if(this.controls=new Jt(this.container,this.deviceHandler,e),this.controls.create(this.currentVideo),this.addEventListeners(),this.currentVideo&&this.controls){const t=this.controls.getCCButton();t&&this.transcriptManager.setup(this.currentVideo,t,this)}}getActiveVideo(){return 0===this.activeVideoIndex?this.currentVideo:this.nextVideo}getInactiveVideo(){return 0===this.activeVideoIndex?this.nextVideo:this.currentVideo}swapVideos(){const t=this.getActiveVideo(),e=this.getInactiveVideo();if(!t||!e)return;t.pause();const n=bt();e.muted=n.isMuted,t.classList.add("sf-hidden"),e.classList.remove("sf-hidden"),this.activeVideoIndex=0===this.activeVideoIndex?1:0,this.currentVideoUrl=this.nextVideoUrl,this.nextVideoUrl=""}async loadVideo(t){var e;const n=this.getActiveVideo();if(!n)return;if(!t||""===t.trim())throw new Error("Cannot load video: No video URL provided for this step");this.controls&&this.controls.reset90PercentTrigger();const i=bt();n.muted=i.isMuted;try{this.controls&&this.controls.reset();const i=(null==(e=bt().playlistOptions)?void 0:e.persistence)??!0;if(this.currentVideoUrl===t&&n.src&&(n.src===t||n.src.endsWith(t))){if(i){const e=this.playbackPositions.get(t);void 0!==e&&e>0&&Math.abs(n.currentTime-e)>.5&&(n.currentTime=e)}return}i&&this.currentVideoUrl&&n.currentTime>0&&this.playbackPositions.set(this.currentVideoUrl,n.currentTime);if(this.getInactiveVideo()&&this.nextVideoUrl===t){this.swapVideos();const t=this.getActiveVideo();return t&&(this.transcriptManager.updateVideoElement(t),this.controls&&this.controls.updateVideoElement(t)),void(await new Promise((t=>{const e=this.getActiveVideo();if(!e)return t();if(e.readyState>=3)t();else{const n=()=>{e.removeEventListener("canplay",n),t()};e.addEventListener("canplay",n)}})))}this.currentVideoUrl=t;const s=this.preloadedVideos.get(t);if(s){const e=URL.createObjectURL(s);n.src=e,this.preloadedVideos.delete(t)}else n.src=t;n.load(),await new Promise(((e,s)=>{if(!n)return e(void 0);let r;const a=()=>{if(n){if(clearTimeout(r),i){const e=this.playbackPositions.get(t);if(void 0!==e&&e>0){const t=Math.min(e,n.duration-.5);n.currentTime=t}}else n.currentTime=0;this.transcriptManager.updateVideoElement(n),this.controls&&this.controls.updateVideoElement(n),n.removeEventListener("loadeddata",a),n.removeEventListener("error",o),e(void 0)}},o=e=>{clearTimeout(r);const i=e.target,l=null==i?void 0:i.error;console.error("VideoManager: Video load error:",l),n.removeEventListener("loadeddata",a),n.removeEventListener("error",o);const c=new Error(`Video load failed: ${(null==l?void 0:l.message)||"Unknown error"}`);c.videoUrl=t,c.mediaErrorCode=(null==l?void 0:l.code)||null,c.mediaErrorMessage=(null==l?void 0:l.message)||null,c.failureReason="media_error",s(c)};r=window.setTimeout((()=>{console.error("VideoManager: Video load timeout after 10 seconds"),n.removeEventListener("loadeddata",a),n.removeEventListener("error",o);const e=new Error("Video load timeout");e.videoUrl=t,e.mediaErrorCode=null,e.mediaErrorMessage=null,e.failureReason="timeout",s(e)}),1e4),n.addEventListener("loadeddata",a),n.addEventListener("error",o)}))}catch(s){if(console.error("VideoManager: Failed to load video:",s),s&&"object"==typeof s&&"videoUrl"in s)throw s;const e=new Error("Failed to load video");throw e.videoUrl=t,e.mediaErrorCode=null,e.mediaErrorMessage=null,e.failureReason="load_error",e}}preloadNextVideo(t){if(!t||this.preloadedVideos.has(t))return;if(this.currentVideoUrl===t)return;if(this.nextVideoUrl===t)return;const e=this.getInactiveVideo();if(e){this.nextVideoUrl=t,e.src=t,e.load(),e.preload="auto";const n=bt();e.muted=n.isMuted}else fetch(t).then((t=>{if(!t.ok)throw new Error(`Failed to fetch video: ${t.statusText}`);return t.blob()})).then((e=>{this.preloadedVideos.set(t,e)})).catch((e=>{console.error(`VideoManager: Error preloading video ${t}:`,e)}))}play(){var t;const e=this.getActiveVideo();if(!e)return void console.error("VideoManager: No active video element found");e.classList.remove("sf-video-container__video--blurred"),e.ended&&(e.currentTime=0);const n=bt();if(((null==(t=n.playlistOptions)?void 0:t.persistence)??!0)&&this.currentVideoUrl){const t=this.playbackPositions.get(this.currentVideoUrl);t&&Math.abs(e.currentTime-t)>.5&&(e.currentTime=t)}if(e.loop=!1,this.audioVisualizationManager.getIsInitialized()&&this.audioVisualizationManager.resumeAudioContext(),!e.paused)return this.controls&&this.controls.startProgressTracking(),void(this.audioVisualizationManager.getIsInitialized()&&this.audioVisualizationManager.resume());this.deviceHandler.handlePlayAttempt(e,this.hasUserInteracted).then((t=>{e&&(t?(this.controls&&this.controls.startProgressTracking(),this.audioVisualizationManager.getIsInitialized()&&this.audioVisualizationManager.resume()):(n.setAutoplayFallback(),this.isMobileDevice()&&(e.playsInline=!0,e.setAttribute("playsinline","true"),e.setAttribute("webkit-playsinline","true"),setTimeout((()=>{e.paused&&e.play().catch((()=>{}))}),200))))})).catch((()=>{console.warn("VideoManager: Autoplay handler threw error - browser has strict autoplay policy");bt().setAutoplayFallback()}))}pause(){const t=this.getActiveVideo();t&&(t.paused||(t.muted=!0,this.controls&&this.controls.updateProgressImmediate(t.currentTime,t.duration),t.pause(),this.audioVisualizationManager.getIsInitialized()&&this.audioVisualizationManager.pause(),this.controls&&this.controls.stopProgressTracking()))}seek(t){const e=this.getActiveVideo();e&&(this.controls&&e.duration>0&&this.controls.updateProgressImmediate(t,e.duration),e.currentTime=t)}getCurrentTime(){const t=this.getActiveVideo();return t?t.currentTime:0}getDuration(){const t=this.getActiveVideo();return t?t.duration:0}getVideoElement(){return this.getActiveVideo()}reset(){this.controls&&this.controls.reset(),this.preloadedVideos.clear(),this.playbackPositions.clear(),this.currentVideoUrl="",this.nextVideoUrl="",this.activeVideoIndex=0,this.hasUserInteracted=!1,null!==this.autoplayFallbackTimeout&&(window.clearTimeout(this.autoplayFallbackTimeout),this.autoplayFallbackTimeout=null),this.completionPolicy="auto",this.videoEndedCallback=null,this.transcriptManager.reset(),this.hideAudioFallbackOverlay();const t=this.audioVisualizationManager.getIsInitialized();t&&this.audioVisualizationManager.reset(),this.currentVideo&&(t||(this.currentVideo.src=""),this.currentVideo.currentTime=0,this.currentVideo.pause()),this.nextVideo&&(t||(this.nextVideo.src=""),this.nextVideo.currentTime=0,this.nextVideo.pause())}async destroy(){this.removeEventListeners(),this.controls&&(this.controls.destroy(),this.controls=null),this.transcriptManager.destroy(),this.hideAudioFallbackOverlay(),null!==this.autoplayFallbackTimeout&&(window.clearTimeout(this.autoplayFallbackTimeout),this.autoplayFallbackTimeout=null),this.deviceChangeCleanup&&(this.deviceChangeCleanup(),this.deviceChangeCleanup=null),this.container&&this.container.parentNode&&this.container.parentNode.removeChild(this.container),this.currentVideo=null,this.nextVideo=null,this.container=null,this.currentVideoUrl="",this.nextVideoUrl="",this.videoEndedCallback=null}addEventListeners(){const t=this.currentVideo,e=this.nextVideo;t&&(t.addEventListener("ended",this.handleVideoEnded),t.addEventListener("error",this.handleVideoError)),e&&(e.addEventListener("ended",this.handleVideoEnded),e.addEventListener("error",this.handleVideoError))}removeEventListeners(){const t=this.currentVideo,e=this.nextVideo;t&&(t.removeEventListener("ended",this.handleVideoEnded),t.removeEventListener("error",this.handleVideoError)),e&&(e.removeEventListener("ended",this.handleVideoEnded),e.removeEventListener("error",this.handleVideoError))}setMuted(t){this.currentVideo&&(this.currentVideo.muted=t),this.nextVideo&&(this.nextVideo.muted=t),this.controls&&this.controls.setMuted(t),!t&&this.audioVisualizationManager.getIsInitialized()&&this.audioVisualizationManager.resetFallbackMode()}updateCCButtonIcon(t){this.controls&&this.controls.updateCCButtonIcon(t)}isMuted(){var t;return(null==(t=this.controls)?void 0:t.getMuted())??!0}showProgressBar(){this.controls&&this.controls.showProgressBar()}hideProgressBar(){this.controls&&this.controls.hideProgressBar()}showMuteButton(){this.controls&&this.controls.showMuteButton()}hideMuteButton(){this.controls&&this.controls.hideMuteButton()}setCompletionPolicy(t,e){this.completionPolicy=t,this.videoEndedCallback=e||null,this.updateVideoEndedHandler()}updateVideoEndedHandler(){}markUserInteraction(){this.hasUserInteracted||(this.hasUserInteracted=!0,null!==this.autoplayFallbackTimeout&&(window.clearTimeout(this.autoplayFallbackTimeout),this.autoplayFallbackTimeout=null))}hasUserInteractedWith(){return this.hasUserInteracted}resetUserInteraction(){this.hasUserInteracted=!1,null!==this.autoplayFallbackTimeout&&(window.clearTimeout(this.autoplayFallbackTimeout),this.autoplayFallbackTimeout=null)}handleAutoplayFallbackClick(t){this.markUserInteraction(),t.muted=!1,t.loop=!1,t.currentTime=0}loadTranscript(t,e=!0){this.transcriptManager.loadTranscript(t,e)}createSoundbar(){const t=document.createElement("div");t.className="sf-audio-soundbar";for(let e=0;e<11;e++){const n=document.createElement("div");n.className="sf-audio-soundbar__bar",n.dataset.barIndex=e.toString(),t.appendChild(n)}return t}showAudioFallbackOverlay(t,e){if(this.container){if(t&&(this.container.style.setProperty("--sf-audio-poster-url",`url('${t}')`),this.container.classList.add("sf-video-container--audio-fallback")),!this.audioFallbackOverlay){if(this.audioFallbackOverlay=document.createElement("div"),e){this.audioFallbackOverlay.className="sf-audio-fallback-overlay sf-audio-fallback-overlay--avatar";const t=document.createElement("img");t.className="sf-audio-fallback-overlay__avatar",t.src=e,t.alt="Speaker avatar";const n=document.createElement("div");n.className="sf-audio-fallback-overlay__dim",this.audioFallbackOverlay.appendChild(t),this.audioFallbackOverlay.appendChild(n)}else this.audioFallbackOverlay.className="sf-audio-fallback-overlay sf-audio-fallback-overlay--soundbar-only";this.soundbarElement=this.createSoundbar(),this.audioFallbackOverlay.appendChild(this.soundbarElement),this.container.appendChild(this.audioFallbackOverlay)}}else console.warn("VideoManager: Cannot show audio fallback overlay - container not available")}startAudioVisualization(){if(!this.soundbarElement)return;const t=this.getActiveVideo();if(t)try{this.audioVisualizationManager.initialize(t),this.audioVisualizationManager.startVisualization(((t,e)=>{if(!this.soundbarElement)return;this.soundbarElement.querySelectorAll(".sf-audio-soundbar__bar").forEach(((e,n)=>{const i=t[n]||0,s=e,r=Math.max(10,100*i);s.style.height=`${r}%`;const a=180+Math.abs(n-5)/5*120;s.style.backgroundColor=`hsla(${a}, 70%, 60%, 1)`}))}))}catch(e){console.error("VideoManager: Failed to initialize audio visualization",e)}}initializeAudioForVideo(){const t=this.getActiveVideo();if(t)try{this.audioVisualizationManager.initialize(t)}catch(e){console.error("VideoManager: Failed to initialize audio for video",e)}}hideAudioFallbackOverlay(){this.container&&(this.audioVisualizationManager.stopVisualization(),this.container.style.removeProperty("--sf-audio-poster-url"),this.container.classList.remove("sf-video-container--audio-fallback"),this.audioFallbackOverlay&&this.audioFallbackOverlay.parentNode&&(this.audioFallbackOverlay.parentNode.removeChild(this.audioFallbackOverlay),this.audioFallbackOverlay=null),this.soundbarElement=null)}}const ee={tolerance:.3,minSize:1};function ne(t){return t.trim().replace(/\s+/g," ")}function ie(t,e){if(t.tagName.toUpperCase()!==e.tagName.toUpperCase())return!1;return ne(t.textContent||"")===ne(e.textContent)}function se(t,e){const n=t.getBoundingClientRect();return 0===n.width||0===n.height?"zero size":n.width<e.minSize||n.height<e.minSize?`too small (${n.width.toFixed(0)}x${n.height.toFixed(0)})`:null}function re(t,e){const n=t.getBoundingClientRect();return(Math.min(n.width,e.width)/Math.max(n.width,e.width)+Math.min(n.height,e.height)/Math.max(n.height,e.height))/2*100}function ae(t,e,n,i=ee){const s=document.querySelectorAll(t);if(0===s.length)return null;if(e){const t=function(t,e,n){const i=[];for(const s of t)se(s,n)||ie(s,e)&&i.push(s);return 0===i.length?(e.tagName,e.textContent.substring(0,50),e.textContent.length,null):(i.length,i[0])}(s,e,i);if(t)return t;if(!n)return null}if(n)return function(t,e,n,i){const s=100*(1-i.tolerance),r=[];for(const o of e){const t=se(o,i);if(t){r.push({element:o,score:-1,rejection:t});continue}const e=re(o,n);if(e<s){const t=o.getBoundingClientRect();r.push({element:o,score:e,rejection:`size mismatch: expected ~${n.width.toFixed(0)}x${n.height.toFixed(0)}, got ${t.width.toFixed(0)}x${t.height.toFixed(0)}`})}else r.push({element:o,score:e})}r.length,n.width.toFixed(0),n.height.toFixed(0);for(let o=0;o<r.length;o++){const t=r[o],e=t.element.getBoundingClientRect();t.rejection?t.rejection:t.score.toFixed(0);e.width.toFixed(0),e.height.toFixed(0)}const a=r.filter((t=>!t.rejection));if(0===a.length)return null;return a.sort(((t,e)=>e.score-t.score)),a[0].score.toFixed(0),a[0].element}(0,s,n,i);for(const r of s){if(!se(r,i))return r}return s[0]}function oe(t,e,n,i=ee){const s=document.querySelectorAll(t);if(0===s.length)return[];if(e){const t=function(t,e,n){const i=[];for(const s of t)se(s,n)||ie(s,e)&&i.push(s);return i.length>0?i.length:e.tagName,i}(s,e,i);if(t.length>0)return t;if(!n)return[]}if(n){const t=100*(1-i.tolerance),e=[];for(const r of s){if(se(r,i))continue;re(r,n)>=t&&e.push(r)}return e.length>0&&e.length,e}const r=[];for(const a of s){se(a,i)||r.push(a)}return r.length>0?r:Array.from(s)}function le(t,e,n,i=ee){if(se(t,i))return!1;if(e&&ie(t,e))return!0;if(n){const e=100*(1-i.tolerance);return re(t,n)>=e}return!0}function ce(t,e,n,i,s){const r=function(t,e,n){const i=document.querySelectorAll(t);if(0===i.length)return"no_elements";if(e)return Array.from(i).some((t=>t.tagName.toUpperCase()===e.tagName.toUpperCase()))?"text_mismatch":"tag_mismatch";return n?"size_mismatch":"no_elements"}(n,i,s),a={playlistId:t,stepId:e,failureReason:r,selector:n};fetch("https://player.saltfish.ai/element-errors",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(a)}).catch((t=>{console.warn("Failed to report element error:",t)}))}class de{constructor(){e(this,"cursor",null),e(this,"animationFrameId",null),e(this,"animationStartTime",null),e(this,"currentAnimation",null),e(this,"flashlightOverlay",null),e(this,"startX",null),e(this,"startY",null),e(this,"targetX",null),e(this,"targetY",null),e(this,"shouldShowCursor",!1),e(this,"lastCursorX",50),e(this,"lastCursorY",50),e(this,"isFirstAnimation",!0),e(this,"currentTargetElement",null),e(this,"boundScrollHandler",null),e(this,"scrollRafId",null),e(this,"scrollUpdatePending",!1),e(this,"scrollableParents",[]),e(this,"parentScrollHandlers",new Map),e(this,"selectionElement",null),e(this,"isSelectionMode",!1),e(this,"selectionPadding",4),e(this,"labelElement",null),e(this,"labelText",null),e(this,"dragStartX",null),e(this,"dragStartY",null),e(this,"dragEndX",null),e(this,"dragEndY",null),e(this,"dragPhase","move-to-start"),e(this,"dragAnimationStartTime",null),e(this,"TARGET_SPEED",350),e(this,"MIN_ANIMATION_DURATION",600),e(this,"MAX_ANIMATION_DURATION",2e3),e(this,"animationDuration",800),e(this,"totalDistance",0),e(this,"controlPointX",null),e(this,"controlPointY",null),e(this,"targetMutationObserver",null),e(this,"POINTER_HORIZONTAL_OFFSET",16),e(this,"POINTER_VERTICAL_OFFSET",16),e(this,"SELECTION_HORIZONTAL_OFFSET",8),e(this,"SELECTION_VERTICAL_OFFSET",8),e(this,"animationUtils",{validateAnimationState:()=>!this.isAutoplayBlocked()||(this.stopAnimation(),!1),calculateEasedProgress:(t,e)=>{const n=e>0?t/e:1,i=Math.min(n,1);return.5-.5*Math.cos(i*Math.PI)},calculateBezierPoint:(t,e,n,i)=>{const s=1-t;return{x:Math.pow(s,2)*e.x+2*s*t*n.x+Math.pow(t,2)*i.x,y:Math.pow(s,2)*e.y+2*s*t*n.y+Math.pow(t,2)*i.y}},hasSignificantPositionChange:(t,e,n=10)=>{const i=Math.abs(e.x-t.x),s=Math.abs(e.y-t.y);return i>n||s>n}})}getPaddingFromStyles(t){return"number"==typeof(null==t?void 0:t.padding)?t.padding:(null==t?void 0:t.padding)?parseInt(t.padding,10):this.selectionPadding}calculateDistance(t,e,n,i){return Math.sqrt(Math.pow(n-t,2)+Math.pow(i-e,2))}calculateAnimationDuration(t){const e=t/(this.TARGET_SPEED/1e3);return Math.min(Math.max(e,this.MIN_ANIMATION_DURATION),this.MAX_ANIMATION_DURATION)}getCurrentCursorPosition(){return{x:this.lastCursorX,y:this.lastCursorY}}canShowCursor(){return this.shouldShowCursor&&!this.isAutoplayBlocked()}waitForScrollComplete(t,e,n=1e3){let i=null;const s=()=>{null!==i&&clearTimeout(i),i=window.setTimeout((()=>{t.removeEventListener("scroll",s),e()}),100)};t.addEventListener("scroll",s),setTimeout((()=>{t.removeEventListener("scroll",s),null!==i&&clearTimeout(i),e()}),n)}waitForElement(t,e,n,i){this.targetMutationObserver&&(this.targetMutationObserver.disconnect(),this.targetMutationObserver=null);let s=0,r=null,a=!1;const o=()=>{var e;if(a)return;a=!0;const s=yt.getState(),r=null==(e=s.manifest)?void 0:e.id,o=s.currentStepId;r&&o&&ce(r,o,t,n,i)},l=()=>{this.targetMutationObserver&&(this.targetMutationObserver.disconnect(),this.targetMutationObserver=null),null!==r&&(clearInterval(r),r=null)},c=async()=>(s++,s>10?(console.warn(`CursorManager: Stopped waiting for element '${t}' after 10 attempts`),o(),l(),null):this.findElementAndScrollIntoView(t,n,i));this.targetMutationObserver=new MutationObserver((async()=>{if(this.isAutoplayBlocked())return void l();const t=await c();t&&(l(),e(t))})),this.targetMutationObserver.observe(document.body,{childList:!0,subtree:!0}),r=setInterval((()=>{if(!this.targetMutationObserver||this.isAutoplayBlocked())return void l();if(s++,s>10)return console.warn(`CursorManager: Stopped waiting for element '${t}' after 10 attempts`),o(),void l();const r=this.findElement(t,n,i);r&&(l(),e(r))}),1e3)}findScrollableParents(t){const e=[];let n=t.parentElement;for(;n&&n!==document.body;){const t=window.getComputedStyle(n),i=t.overflow,s=t.overflowX,r=t.overflowY;"scroll"!==i&&"auto"!==i&&"scroll"!==s&&"auto"!==s&&"scroll"!==r&&"auto"!==r||(n.scrollHeight>n.clientHeight||n.scrollWidth>n.clientWidth)&&e.push(n),n=n.parentElement}return e}addScrollListenersToParents(t){this.removeScrollListenersFromParents(),this.scrollableParents=this.findScrollableParents(t),this.scrollableParents.forEach((t=>{const e=this.handleScroll.bind(this);this.parentScrollHandlers.set(t,e),t.addEventListener("scroll",e,{passive:!0})}))}removeScrollListenersFromParents(){this.parentScrollHandlers.forEach(((t,e)=>{e.removeEventListener("scroll",t)})),this.parentScrollHandlers.clear(),this.scrollableParents=[]}findElement(t,e,n){if(e||n){const i=ae(t,e,n);return i||null}const i=document.querySelectorAll(t);if(0===i.length)return null;if(1===i.length)return i[0];for(const l of i)if(this.isElementInViewport(l))return l.getBoundingClientRect(),l;const s=window.innerWidth/2,r=window.innerHeight/2;let a=i[0],o=1/0;for(const l of i){const t=l.getBoundingClientRect(),e=t.left+t.width/2,n=t.top+t.height/2,i=Math.sqrt(Math.pow(e-s,2)+Math.pow(n-r,2));i<o&&(o=i,a=l)}return a.getBoundingClientRect(),a}isElementInViewport(t){const e=t.getBoundingClientRect(),n=window.innerHeight||document.documentElement.clientHeight,i=window.innerWidth||document.documentElement.clientWidth;if(!(e.top>=0&&e.bottom<=n&&e.left>=0&&e.right<=i))return!1;const s=this.findScrollableParents(t);for(const r of s){const t=r.getBoundingClientRect();if(!(e.top>=t.top&&e.bottom<=t.bottom&&e.left>=t.left&&e.right<=t.right))return!1}return!0}async scrollElementIntoView(t){return new Promise((e=>{const n=this.findScrollableParents(t),i=t.getBoundingClientRect(),s=window.innerHeight||document.documentElement.clientHeight,r=i.height>s?"start":"center";0===n.length?(t.scrollIntoView({behavior:"smooth",block:r,inline:"center"}),this.waitForScrollComplete(window,e)):this.scrollParentContainersToShowElement(t,n).then((()=>{this.isElementInViewport(t)||t.scrollIntoView({behavior:"smooth",block:r,inline:"center"}),setTimeout((()=>{e()}),200)}))}))}async scrollParentContainersToShowElement(t,e){return new Promise((n=>{let i=0;const s=e.length;if(0===s)return void n();const r=()=>{i++,i>=s&&n()};e.forEach((e=>{const n=t.getBoundingClientRect(),i=e.getBoundingClientRect(),s=e.scrollTop,a=e.scrollLeft;let o;o=n.height>i.height?s+(n.top-i.top):s+(n.top-i.top)-i.height/2+n.height/2;const l=a+(n.left-i.left)-i.width/2+n.width/2;e.scrollTo({top:Math.max(0,o),left:Math.max(0,l),behavior:"smooth"}),this.waitForScrollComplete(e,r,800)}))}))}async findElementAndScrollIntoView(t,e,n){const i=this.findElement(t,e,n);return i?(this.isElementInViewport(i)||await this.scrollElementIntoView(i),i):null}cleanupExistingElements(){document.querySelectorAll(".sf-cursor").forEach((t=>t.remove()));document.querySelectorAll(".sf-cursor-label").forEach((t=>t.remove()));document.querySelectorAll(".sf-selection").forEach((t=>t.remove()));document.querySelectorAll(".sf-flashlight-overlay").forEach((t=>t.remove())),this.cursor=null,this.labelElement=null,this.selectionElement=null,this.flashlightOverlay=null}create(){this.cleanupExistingElements(),this.injectCursorStyles(),this.cursor=document.createElement("div"),this.cursor.className="sf-cursor",this.cursor.innerHTML='\n <svg xmlns="http://www.w3.org/2000/svg" width="40" height="40" viewBox="0 0 24 24" fill="none">\n <defs>\n <filter id="cursor-shadow" x="-50%" y="-50%" width="200%" height="200%">\n <feDropShadow dx="0" dy="1" stdDeviation="1.2" flood-color="rgba(0, 0, 0, 0.22)"/>\n </filter>\n </defs>\n <path d="M3.5 3.5L10.5 20.5L13.3 13.3L20.5 10.5L3.5 3.5Z" fill="#ff7614" stroke="white" stroke-width="0.7" stroke-linejoin="round" stroke-linecap="round" filter="url(#cursor-shadow)" />\n </svg>\n ',this.labelElement=document.createElement("div"),this.labelElement.className="sf-cursor-label",this.selectionElement=document.createElement("div"),this.selectionElement.className="sf-selection",document.body.appendChild(this.cursor),document.body.appendChild(this.labelElement),document.body.appendChild(this.selectionElement),this.flashlightOverlay=document.createElement("div"),this.flashlightOverlay.className="sf-flashlight-overlay",document.body.appendChild(this.flashlightOverlay),this.boundScrollHandler=this.handleScroll.bind(this),window.addEventListener("scroll",this.boundScrollHandler,{passive:!0}),this.lastCursorX=window.innerWidth-50,this.lastCursorY=window.innerHeight-50}injectCursorStyles(){const t="\n .sf-cursor {\n position: fixed;\n top: 0;\n left: 0;\n width: 40px;\n height: 40px;\n z-index: 9999999;\n pointer-events: none;\n display: none;\n will-change: transform;\n transform: var(--sf-cursor-transform, translate(0, 0));\n opacity: var(--sf-cursor-opacity, 1);\n /* Defensive styles to prevent host page CSS interference */\n margin: 0;\n padding: 0;\n border: 0;\n box-sizing: content-box;\n line-height: 0;\n font-size: 0;\n vertical-align: baseline;\n overflow: visible;\n }\n\n .sf-cursor--visible {\n display: block;\n }\n\n .sf-cursor svg {\n display: block;\n width: 100%;\n height: 100%;\n margin: 0;\n padding: 0;\n border: 0;\n }\n\n .sf-selection {\n position: fixed;\n pointer-events: none;\n display: none;\n z-index: 9999998;\n top: 0;\n left: 0;\n border: 2px solid var(--sf-selection-color, #ff7614);\n background: var(--sf-selection-bg-color, rgba(255, 118, 20, 0));\n border-radius: 4px;\n width: var(--sf-selection-width, 0);\n height: var(--sf-selection-height, 0);\n transform: var(--sf-selection-transform, translate(0, 0));\n will-change: transform;\n box-sizing: border-box;\n }\n\n .sf-selection--visible {\n display: block;\n }\n\n .sf-flashlight-overlay {\n position: fixed;\n top: 0;\n left: 0;\n width: 100vw;\n height: 100vh;\n pointer-events: none;\n z-index: 9999997;\n display: none;\n background: var(--sf-flashlight-bg, radial-gradient(circle 150px at 50% 50%, transparent 0%, rgba(0, 0, 0, 0.4) 100%));\n clip-path: var(--sf-flashlight-clip, none);\n }\n\n .sf-flashlight-overlay--visible {\n display: block;\n }\n\n .sf-cursor-label {\n position: fixed;\n top: 0;\n left: 0;\n z-index: 9999999;\n pointer-events: none;\n display: none;\n will-change: transform;\n transform: var(--sf-cursor-label-transform, translate(0, 0));\n opacity: var(--sf-cursor-opacity, 1);\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif;\n font-size: 13px;\n font-weight: 500;\n color: var(--sf-cursor-label-text, #fff);\n background: var(--sf-cursor-label-bg, #ff7614);\n padding: 4px 10px;\n border-radius: 12px;\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);\n white-space: nowrap;\n margin: 0;\n border: 0;\n box-sizing: border-box;\n line-height: 1.4;\n }\n\n .sf-cursor-label--visible {\n display: block;\n }\n ";try{const e=new CSSStyleSheet;e.replaceSync(t),document.adoptedStyleSheets=[...document.adoptedStyleSheets,e]}catch(e){const n=document.createElement("style");n.textContent=t,document.head.appendChild(n)}}handleScroll(){!this.isAutoplayBlocked()&&this.shouldShowCursor&&this.currentTargetElement&&(null!==this.animationFrameId||this.scrollUpdatePending||(this.scrollUpdatePending=!0,this.scrollRafId=requestAnimationFrame((()=>{this.updateCursorPositionOnScroll(),this.scrollUpdatePending=!1,this.scrollRafId=null}))))}updateCursorPositionOnScroll(){var t,e;if(!this.currentTargetElement)return;const n=this.currentTargetElement.getBoundingClientRect();let i,s;if(this.isSelectionMode){const e=this.getPaddingFromStyles(null==(t=this.currentAnimation)?void 0:t.selectionStyles);i=n.right+e+this.SELECTION_HORIZONTAL_OFFSET,s=n.bottom+e+this.SELECTION_VERTICAL_OFFSET}else i=n.left+n.width/2+this.POINTER_HORIZONTAL_OFFSET,s=n.top+n.height/2+this.POINTER_VERTICAL_OFFSET;if(this.show(i,s),this.lastCursorX=i,this.lastCursorY=s,this.selectionElement&&this.isSelectionMode){const t=this.getPaddingFromStyles(null==(e=this.currentAnimation)?void 0:e.selectionStyles),i=Math.floor(n.left-t),s=Math.floor(n.top-t),r=Math.ceil(n.width+2*t),a=Math.ceil(n.height+2*t);this.selectionElement.style.setProperty("--sf-selection-transform",`translate(${i}px, ${s}px)`),this.selectionElement.style.setProperty("--sf-selection-width",`${r}px`),this.selectionElement.style.setProperty("--sf-selection-height",`${a}px`),this.dragStartX=i,this.dragStartY=s,this.dragEndX=i+r,this.dragEndY=s+a,this.updateFlashlightWithCutout(i,s,r,a)}}isAutoplayBlocked(){return"autoplayBlocked"===yt.getState().currentState}setShouldShowCursor(t){if(this.isAutoplayBlocked())return this.shouldShowCursor=!1,void this.hideCursorElements();this.shouldShowCursor=t,t?this.isFirstAnimation||this.show(this.lastCursorX,this.lastCursorY):this.hideCursorElements()}show(t,e){this.canShowCursor()&&(this.lastCursorX=t,this.lastCursorY=e,this.cursor&&(this.cursor.classList.add("sf-cursor--visible"),this.cursor.style.setProperty("--sf-cursor-transform",`translate(${t}px, ${e}px) translate(-50%, -50%)`)),this.labelElement&&this.labelText&&(this.labelElement.classList.add("sf-cursor-label--visible"),this.labelElement.style.setProperty("--sf-cursor-label-transform",`translate(${t+24}px, ${e+8}px)`)),this.flashlightOverlay&&(this.flashlightOverlay.classList.add("sf-flashlight-overlay--visible"),this.flashlightOverlay.style.setProperty("--sf-flashlight-bg",`radial-gradient(circle 150px at ${t}px ${e}px, transparent 0%, rgba(0, 0, 0, 0.4) 100%)`)))}hideCursorElements(){this.cursor&&this.cursor.classList.remove("sf-cursor--visible"),this.labelElement&&this.labelElement.classList.remove("sf-cursor-label--visible"),this.selectionElement&&this.selectionElement.classList.remove("sf-selection--visible"),this.flashlightOverlay&&(this.flashlightOverlay.classList.remove("sf-flashlight-overlay--visible"),this.resetFlashlightOverlay())}resetFlashlightOverlay(){if(!this.flashlightOverlay)return;this.flashlightOverlay.style.setProperty("--sf-flashlight-clip","none");const t=this.lastCursorX,e=this.lastCursorY;this.flashlightOverlay.style.setProperty("--sf-flashlight-bg",`radial-gradient(circle 150px at ${t}px ${e}px, transparent 0%, rgba(0, 0, 0, 0.4) 100%)`)}async animate(t){if(this.isAutoplayBlocked())return;if(this.stopAnimation(),this.removeScrollListenersFromParents(),this.currentTargetElement=null,this.isSelectionMode=!1,this.resetFlashlightOverlay(),this.selectionElement&&this.selectionElement.classList.remove("sf-selection--visible"),!(null==t?void 0:t.targetSelector))return void console.warn("CursorManager: No targetSelector provided in animation");if(await new Promise((t=>setTimeout(t,_t))),this.isAutoplayBlocked())return;const e=await this.findElementAndScrollIntoView(t.targetSelector,t.expectedElement,t.expectedSize);if(!e)return console.warn("CursorManager: Target element not found in animate:",t.targetSelector),this.setShouldShowCursor(!1),this.hideCursorElements(),void this.waitForElement(t.targetSelector,(()=>this.animate(t)),t.expectedElement,t.expectedSize);this.setShouldShowCursor(!0),this.currentTargetElement=e,this.addScrollListenersToParents(e);const n=e.getBoundingClientRect();this.isFirstAnimation?(this.startX=window.innerWidth-50,this.startY=window.innerHeight-50,this.isFirstAnimation=!1):(this.startX=this.lastCursorX,this.startY=this.lastCursorY);const i={...t,mode:t.mode||"selection"};if(this.isSelectionMode="selection"===i.mode,this.isSelectionMode)return void this.handleSelectionMode(i,n);this.targetX=n.left+n.width/2+this.POINTER_HORIZONTAL_OFFSET,this.targetY=n.top+n.height/2+this.POINTER_VERTICAL_OFFSET,this.selectionElement&&this.selectionElement.classList.remove("sf-selection--visible"),null!==this.targetX&&null!==this.targetY&&null!==this.startX&&null!==this.startY?(this.totalDistance=this.calculateDistance(this.startX,this.startY,this.targetX,this.targetY),this.animationDuration=this.calculateAnimationDuration(this.totalDistance)):(this.totalDistance=100,this.animationDuration=this.MIN_ANIMATION_DURATION),this.calculateControlPoint(),this.currentAnimation={...i};const s=null!==this.startX?this.startX:0,r=null!==this.startY?this.startY:0;this.show(s,r),this.animationStartTime=performance.now(),this.animationFrameId=requestAnimationFrame(this.unifiedAnimationFrame.bind(this))}handleSelectionMode(t,e){const n=this.getPaddingFromStyles(t.selectionStyles);this.dragStartX=Math.floor(e.left-n),this.dragStartY=Math.floor(e.top-n),this.dragEndX=Math.ceil(e.right+n),this.dragEndY=Math.ceil(e.bottom+n),this.dragPhase="move-to-start",this.targetX=this.dragStartX+this.SELECTION_HORIZONTAL_OFFSET,this.targetY=this.dragStartY+this.SELECTION_VERTICAL_OFFSET,null!==this.targetX&&null!==this.targetY&&null!==this.startX&&null!==this.startY?(this.totalDistance=this.calculateDistance(this.startX,this.startY,this.targetX,this.targetY),this.animationDuration=this.calculateAnimationDuration(this.totalDistance)):(this.totalDistance=100,this.animationDuration=this.MIN_ANIMATION_DURATION),this.selectionElement&&(t.selectionStyles&&(t.selectionStyles.borderColor&&this.selectionElement.style.setProperty("--sf-selection-border-color",t.selectionStyles.borderColor),t.selectionStyles.borderWidth&&this.selectionElement.style.setProperty("--sf-selection-border-width",t.selectionStyles.borderWidth),t.selectionStyles.borderRadius&&this.selectionElement.style.setProperty("--sf-selection-border-radius",t.selectionStyles.borderRadius)),this.selectionElement.classList.remove("sf-selection--visible")),this.calculateControlPoint(),this.currentAnimation={...t};const i=null!==this.startX?this.startX:0,s=null!==this.startY?this.startY:0;this.show(i,s),this.animationStartTime=performance.now(),this.animationFrameId=requestAnimationFrame(this.unifiedAnimationFrame.bind(this))}updateDragCoordinatesFromElement(){var t;if(!this.currentTargetElement)return;const e=this.currentTargetElement.getBoundingClientRect(),n=this.getPaddingFromStyles(null==(t=this.currentAnimation)?void 0:t.selectionStyles);this.dragStartX=Math.floor(e.left-n),this.dragStartY=Math.floor(e.top-n),this.dragEndX=Math.ceil(e.right+n),this.dragEndY=Math.ceil(e.bottom+n)}updateSelectionRectangle(t,e){if(!this.selectionElement)return;const n=Math.ceil(Math.abs(t-this.SELECTION_HORIZONTAL_OFFSET-this.dragStartX)),i=Math.ceil(Math.abs(e-this.SELECTION_VERTICAL_OFFSET-this.dragStartY)),s=Math.floor(Math.min(this.dragStartX,t-this.SELECTION_HORIZONTAL_OFFSET)),r=Math.floor(Math.min(this.dragStartY,e-this.SELECTION_VERTICAL_OFFSET));this.selectionElement.style.setProperty("--sf-selection-transform",`translate(${s}px, ${r}px)`),this.selectionElement.style.setProperty("--sf-selection-width",`${n}px`),this.selectionElement.style.setProperty("--sf-selection-height",`${i}px`),this.selectionElement.classList.add("sf-selection--visible"),this.updateFlashlightWithCutout(s,r,n,i)}validatePointerState(){return null!==this.animationStartTime&&null!==this.currentAnimation&&null!==this.startX&&null!==this.startY&&null!==this.targetX&&null!==this.targetY&&null!==this.controlPointX&&null!==this.controlPointY}validateSelectionState(){return!(!this.animationStartTime||!this.currentAnimation)&&("move-to-start"===this.dragPhase?null!==this.startX&&null!==this.startY&&null!==this.targetX&&null!==this.targetY&&null!==this.controlPointX&&null!==this.controlPointY:"dragging"!==this.dragPhase||null!==this.dragAnimationStartTime&&null!==this.dragStartX&&null!==this.dragStartY&&null!==this.dragEndX&&null!==this.dragEndY)}completePointerAnimation(){this.show(this.targetX,this.targetY),this.lastCursorX=this.targetX,this.lastCursorY=this.targetY,this.click(),setTimeout((()=>{this.stopAnimation()}),400)}completeMoveToStartPhase(){this.show(this.targetX,this.targetY),this.lastCursorX=this.targetX,this.lastCursorY=this.targetY,this.dragPhase="dragging",this.dragAnimationStartTime=performance.now();const t=this.calculateDistance(this.dragStartX+this.SELECTION_HORIZONTAL_OFFSET,this.dragStartY+this.SELECTION_VERTICAL_OFFSET,this.dragEndX+this.SELECTION_HORIZONTAL_OFFSET,this.dragEndY+this.SELECTION_VERTICAL_OFFSET);if(this.animationDuration=this.calculateAnimationDuration(t),this.cursor){const t=this.lastCursorX,e=this.lastCursorY;this.cursor.style.setProperty("--sf-cursor-transform",`translate(${t}px, ${e}px) translate(-50%, -50%) scale(0.9)`),this.cursor.style.setProperty("--sf-cursor-opacity","0.9")}this.selectionElement&&(this.selectionElement.style.setProperty("--sf-selection-transform",`translate(${this.dragStartX}px, ${this.dragStartY}px)`),this.selectionElement.style.setProperty("--sf-selection-width","0px"),this.selectionElement.style.setProperty("--sf-selection-height","0px"),this.selectionElement.classList.add("sf-selection--visible"))}completeDraggingPhase(){if(this.dragPhase="release",this.cursor){const t=this.lastCursorX,e=this.lastCursorY;this.cursor.style.setProperty("--sf-cursor-transform",`translate(${t}px, ${e}px) translate(-50%, -50%)`),this.cursor.style.setProperty("--sf-cursor-opacity","1")}null!==this.animationFrameId&&(cancelAnimationFrame(this.animationFrameId),this.animationFrameId=null),this.animationStartTime=null,this.dragAnimationStartTime=null}handleMoveToStartPhase(t){if(this.currentTargetElement){this.updateDragCoordinatesFromElement();const e={x:this.targetX,y:this.targetY};this.targetX=this.dragStartX+this.SELECTION_HORIZONTAL_OFFSET,this.targetY=this.dragStartY+this.SELECTION_VERTICAL_OFFSET;if(this.animationUtils.hasSignificantPositionChange(e,{x:this.targetX,y:this.targetY})){const e=this.getCurrentCursorPosition();this.startX=e.x,this.startY=e.y,this.calculateControlPoint(),this.totalDistance=this.calculateDistance(this.startX,this.startY,this.targetX,this.targetY),this.animationDuration=this.calculateAnimationDuration(this.totalDistance),this.animationStartTime=t}}const e=t-this.animationStartTime;if(e>=this.animationDuration)return void this.completeMoveToStartPhase();const n=this.animationUtils.calculateEasedProgress(e,this.animationDuration),i=this.animationUtils.calculateBezierPoint(n,{x:this.startX,y:this.startY},{x:this.controlPointX,y:this.controlPointY},{x:this.targetX,y:this.targetY});this.show(i.x,i.y)}handleDraggingPhase(t){this.currentTargetElement&&this.updateDragCoordinatesFromElement();const e=t-this.dragAnimationStartTime,n=Math.min(e/this.animationDuration,1),i=.5-.5*Math.cos(n*Math.PI),s=this.dragStartX+(this.dragEndX-this.dragStartX)*i+this.SELECTION_HORIZONTAL_OFFSET,r=this.dragStartY+(this.dragEndY-this.dragStartY)*i+this.SELECTION_VERTICAL_OFFSET;this.show(s,r),this.updateSelectionRectangle(s,r),n>=1&&this.completeDraggingPhase()}handlePointerAnimation(t){if(!this.validatePointerState())return console.warn("CursorManager: Animation frame missing essential data"),void this.stopAnimation();const e=t-this.animationStartTime;if(this.currentTargetElement){const e=this.currentTargetElement.getBoundingClientRect(),n={x:this.targetX,y:this.targetY};if(this.targetX=e.left+e.width/2+this.POINTER_HORIZONTAL_OFFSET,this.targetY=e.top+e.height/2+this.POINTER_VERTICAL_OFFSET,this.animationUtils.hasSignificantPositionChange(n,{x:this.targetX,y:this.targetY})){const e=this.getCurrentCursorPosition();this.startX=e.x,this.startY=e.y,this.calculateControlPoint(),this.totalDistance=this.calculateDistance(this.startX,this.startY,this.targetX,this.targetY),this.animationDuration=this.calculateAnimationDuration(this.totalDistance),this.animationStartTime=t}}if(e>=this.animationDuration)return void this.completePointerAnimation();const n=this.animationUtils.calculateEasedProgress(e,this.animationDuration),i=this.animationUtils.calculateBezierPoint(n,{x:this.startX,y:this.startY},{x:this.controlPointX,y:this.controlPointY},{x:this.targetX,y:this.targetY});this.show(i.x,i.y),this.animationFrameId=requestAnimationFrame(this.unifiedAnimationFrame.bind(this))}handleSelectionAnimation(t){if(this.validateSelectionState()){switch(this.dragPhase){case"move-to-start":this.handleMoveToStartPhase(t);break;case"dragging":this.handleDraggingPhase(t)}"release"!==this.dragPhase&&(this.animationFrameId=requestAnimationFrame(this.unifiedAnimationFrame.bind(this)))}else this.stopAnimation()}unifiedAnimationFrame(t){this.animationUtils.validateAnimationState()&&(this.isSelectionMode?this.handleSelectionAnimation(t):this.handlePointerAnimation(t))}updateFlashlightWithCutout(t,e,n,i){if(!this.flashlightOverlay)return;const s=window.innerWidth,r=window.innerHeight,a=`path(evenodd, "M 0 0 L ${s} 0 L ${s} ${r} L 0 ${r} Z M ${t+4} ${e} L ${t+n-4} ${e} A 4 4 0 0 1 ${t+n} ${e+4} L ${t+n} ${e+i-4} A 4 4 0 0 1 ${t+n-4} ${e+i} L ${t+4} ${e+i} A 4 4 0 0 1 ${t} ${e+i-4} L ${t} ${e+4} A 4 4 0 0 1 ${t+4} ${e} Z")`;this.flashlightOverlay.style.setProperty("--sf-flashlight-clip",a);const o=this.lastCursorX,l=this.lastCursorY;this.flashlightOverlay.style.setProperty("--sf-flashlight-bg",`radial-gradient(circle 150px at ${o}px ${l}px, transparent 0%, rgba(0, 0, 0, 0.4) 100%)`)}calculateControlPoint(){if(!(this.startX&&this.startY&&this.targetX&&this.targetY))return void console.warn("CursorManager: Missing start or target position for control point calculation",{startX:this.startX,startY:this.startY,targetX:this.targetX,targetY:this.targetY});const t=(this.startX+this.targetX)/2,e=(this.startY+this.targetY)/2,n=Math.sqrt(Math.pow(this.targetX-this.startX,2)+Math.pow(this.targetY-this.startY,2));this.totalDistance=n;const i=.2*n,s=(Math.random()-.5)*i*2,r=this.targetX-this.startX,a=-(this.targetY-this.startY),o=r,l=Math.sqrt(a*a+o*o);if(0===l)this.controlPointX=t+5,this.controlPointY=e+5;else{const n=a/l,i=o/l;this.controlPointX=t+n*s,this.controlPointY=e+i*s}}async moveToElement(t,e,n){if(!this.canShowCursor())return;if(this.stopAnimation(),this.removeScrollListenersFromParents(),this.currentTargetElement=null,this.isSelectionMode=!1,this.resetFlashlightOverlay(),this.isAutoplayBlocked())return;const i=await this.findElementAndScrollIntoView(t);if(!i)return console.warn("CursorManager: Target element not found:",t),this.setShouldShowCursor(!1),this.hideCursorElements(),void this.waitForElement(t,(()=>this.moveToElement(t,e,n)));this.currentTargetElement=i,this.addScrollListenersToParents(i);const s={targetSelector:t,mode:e||"selection",selectionStyles:n};this.animate(s)}click(){if(this.canShowCursor()&&this.cursor){const t=this.lastCursorX,e=this.lastCursorY;this.cursor.style.setProperty("--sf-cursor-transform",`translate(${t}px, ${e}px) translate(-50%, -50%) scale(0.8)`),this.cursor.style.setProperty("--sf-cursor-opacity","0.8"),setTimeout((()=>{if(this.cursor){if(!this.canShowCursor())return void this.hideCursorElements();this.cursor.style.setProperty("--sf-cursor-transform",`translate(${t}px, ${e}px) translate(-50%, -50%)`),this.cursor.style.setProperty("--sf-cursor-opacity","1")}}),300)}}stopAnimation(){if(null!==this.animationFrameId&&(cancelAnimationFrame(this.animationFrameId),this.animationFrameId=null),this.animationStartTime=null,this.currentAnimation=null,this.controlPointX=null,this.controlPointY=null,this.dragPhase="move-to-start",this.dragAnimationStartTime=null,this.cursor){const t=this.lastCursorX,e=this.lastCursorY;this.cursor.style.setProperty("--sf-cursor-transform",`translate(${t}px, ${e}px) translate(-50%, -50%)`),this.cursor.style.setProperty("--sf-cursor-opacity","1")}this.resetFlashlightOverlay(),this.selectionElement&&this.selectionElement.classList.remove("sf-selection--visible")}resetFirstAnimation(){this.isFirstAnimation=!0}reset(){this.stopAnimation(),this.currentAnimation=null,this.animationStartTime=null,this.startX=null,this.startY=null,this.targetX=null,this.targetY=null,this.currentTargetElement=null,this.isFirstAnimation=!0,this.shouldShowCursor=!1,this.cursor&&this.cursor.classList.remove("sf-cursor--visible"),this.isSelectionMode=!1,this.selectionElement&&this.selectionElement.classList.remove("sf-selection--visible"),this.dragStartX=null,this.dragStartY=null,this.dragEndX=null,this.dragEndY=null,this.dragPhase="move-to-start",this.dragAnimationStartTime=null,null!==this.scrollRafId&&(cancelAnimationFrame(this.scrollRafId),this.scrollRafId=null),this.scrollUpdatePending=!1,this.removeScrollListenersFromParents(),this.scrollableParents=[]}async destroy(){this.stopAnimation(),this.boundScrollHandler&&(window.removeEventListener("scroll",this.boundScrollHandler),this.boundScrollHandler=null),this.removeScrollListenersFromParents(),null!==this.scrollRafId&&(cancelAnimationFrame(this.scrollRafId),this.scrollRafId=null),this.scrollUpdatePending=!1,this.cursor&&this.cursor.parentNode&&(this.cursor.remove(),this.cursor=null),this.labelElement&&this.labelElement.parentNode&&(this.labelElement.remove(),this.labelElement=null),this.labelText=null,this.selectionElement&&this.selectionElement.parentNode&&(this.selectionElement.remove(),this.selectionElement=null),this.flashlightOverlay&&this.flashlightOverlay.parentNode&&(this.flashlightOverlay.remove(),this.flashlightOverlay=null),this.isFirstAnimation=!0,this.shouldShowCursor=!1,this.currentTargetElement=null,this.isSelectionMode=!1,this.targetMutationObserver&&(this.targetMutationObserver.disconnect(),this.targetMutationObserver=null),document.documentElement.style.removeProperty("--sf-cursor-x"),document.documentElement.style.removeProperty("--sf-cursor-y")}setColor(t){if(this.cursor){const e=this.cursor.querySelector("svg");if(e){const n=e.querySelector("path");n?n.setAttribute("fill",t):console.warn("[CursorManager.setColor] No path found in SVG")}else console.warn("[CursorManager.setColor] No SVG found in cursor")}else console.warn("[CursorManager.setColor] No cursor element");if(this.selectionElement){this.selectionElement.style.setProperty("--sf-selection-color",t);const e=this.colorToRgba(t,0);this.selectionElement.style.setProperty("--sf-selection-bg-color",e)}if(this.labelElement){this.labelElement.style.setProperty("--sf-cursor-label-bg",t);const e=this.getContrastingTextColor(t);this.labelElement.style.setProperty("--sf-cursor-label-text",e)}}getContrastingTextColor(t){const e=this.parseColorToRgb(t);if(!e)return"#fff";return(299*e.r+587*e.g+114*e.b)/1e3>150?"#333":"#fff"}parseColorToRgb(t){const e=document.createElement("div");e.style.color=t,document.body.appendChild(e);const n=window.getComputedStyle(e).color;document.body.removeChild(e);const i=n.match(/rgba?\((\d+),\s*(\d+),\s*(\d+)/);return i?{r:parseInt(i[1],10),g:parseInt(i[2],10),b:parseInt(i[3],10)}:null}colorToRgba(t,e){const n=document.createElement("div");n.style.color=t,document.body.appendChild(n);const i=window.getComputedStyle(n).color;document.body.removeChild(n);const s=i.match(/rgba?\((\d+),\s*(\d+),\s*(\d+)/);if(s){return`rgba(${s[1]}, ${s[2]}, ${s[3]}, ${e})`}return t}setLabel(t){var e;this.labelText=t,this.labelElement&&(t?(this.labelElement.textContent=t,(null==(e=this.cursor)?void 0:e.classList.contains("sf-cursor--visible"))&&this.labelElement.classList.add("sf-cursor-label--visible")):(this.labelElement.textContent="",this.labelElement.classList.remove("sf-cursor-label--visible")))}}const he=["utm_source","utm_medium","utm_campaign","utm_term","utm_content","utm_id","gclid","gclsrc","gad_source","dclid","gbraid","wbraid","fbclid","msclkid","li_fat_id","twclid","ttclid","ref","_ga","_gl"];function ue(t){if(!t)return t;try{let e;e=t.startsWith("/")||!t.includes("://")?new URL(t,window.location.origin):new URL(t);const n=function(){const t=new Map;try{const e=new URL(window.location.href);for(const n of he){const i=e.searchParams.get(n);null!==i&&t.set(n,i)}t.size>0&&(t.size,Array.from(t.keys()).join(", "))}catch(e){}return t}();if(0===n.size)return t;let i=0;for(const[t,s]of n)e.searchParams.has(t)||(e.searchParams.set(t,s),i++);return i>0?e.toString():t}catch(e){return t}}class pe{constructor(){e(this,"container",null),e(this,"buttons",[]),e(this,"buttonContainer",null),e(this,"scrollIndicator",null),e(this,"storeUnsubscribe",null),e(this,"storageManager",gt.getInstance()),e(this,"handleVideo90PercentReached",(t=>{this.showButtonsAt90Percent()}))}create(t){this.container=t,this.storeUnsubscribe=vt.subscribe(((t,e)=>{t.isMinimized!==(null==e?void 0:e.isMinimized)&&this.updateButtonPositions()})),t.addEventListener("video90PercentReached",this.handleVideo90PercentReached)}createButtons(t){if(!this.container)return;this.clearButtons(),this.buttonContainer=document.createElement("div");const e=t.length>4;let n="sf-choice-buttons-container";e&&(n+=" sf-choice-buttons-container--scrollable"),this.buttonContainer.className=n,t.length,this.updateCenterPlayButtonPosition(t.length),this.container.appendChild(this.buttonContainer),e&&(this.scrollIndicator=document.createElement("div"),this.scrollIndicator.className="sf-scroll-indicator",this.scrollIndicator.innerHTML='\n <svg width="16" height="16" viewBox="0 0 16 16" fill="currentColor">\n <path d="M8 12l-4-4h8l-4 4z"/>\n </svg>\n ',this.container.appendChild(this.scrollIndicator)),t.forEach((t=>{const e=document.createElement("button");e.textContent=t.text,e.dataset.buttonId=t.id,e.className=`sf-choice-button sf-choice-button--${t.action.type}`,t.style&&Object.entries(t.style).forEach((([t,n])=>{e.style.setProperty(`--custom-${t}`,String(n))})),e.addEventListener("click",(async e=>{await this.handleButtonClick(e,t)})),this.buttonContainer&&(this.buttonContainer.appendChild(e),this.buttons.push(e),t.id)})),e&&this.buttonContainer&&this.setupScrollIndicator(this.buttonContainer);bt().isMinimized&&this.buttonContainer.classList.add("sf-hidden")}showButtonsAt90Percent(){this.buttons.length>0&&(this.buttons.forEach(((t,e)=>{t.classList.add("sf-show-button")})),this.scrollIndicator&&this.scrollIndicator.classList.add("sf-show-scroll-indicator"))}setupScrollIndicator(t){if(!this.scrollIndicator)return;t.addEventListener("scroll",(()=>{if(!this.scrollIndicator)return;t.scrollHeight-t.scrollTop-t.clientHeight<zt?this.scrollIndicator.classList.add("sf-scroll-indicator--hidden"):this.scrollIndicator.classList.remove("sf-scroll-indicator--hidden")}))}updateCenterPlayButtonPosition(t){if(!this.container)return;const e=this.container.querySelector(".sf-player__center-play-button");if(e)if(t>0){let n;n=t>4?176:t*36+(t-1)*8,e.style.setProperty("--sf-button-container-height",`${n}px`),e.classList.add("sf-player__center-play-button--with-buttons")}else e.style.removeProperty("--sf-button-container-height"),e.classList.remove("sf-player__center-play-button--with-buttons")}clearButtons(){this.updateCenterPlayButtonPosition(0),this.buttons.forEach((t=>{t.parentElement&&t.parentElement.removeChild(t)})),this.buttonContainer&&this.buttonContainer.parentElement&&this.buttonContainer.parentElement.removeChild(this.buttonContainer),this.scrollIndicator&&this.scrollIndicator.parentElement&&this.scrollIndicator.parentElement.removeChild(this.scrollIndicator),this.buttons=[],this.buttonContainer=null,this.scrollIndicator=null}updateButtonPositions(){if(!this.buttonContainer||0===this.buttons.length)return;if(bt().isMinimized)return this.buttonContainer.classList.add("sf-hidden"),void(this.scrollIndicator&&this.scrollIndicator.classList.add("sf-hidden"));this.buttonContainer.classList.remove("sf-hidden"),this.scrollIndicator&&this.scrollIndicator.classList.remove("sf-hidden")}async handleButtonClick(t,e){var n,i,s,r,a,o;e.id,t.preventDefault(),t.stopPropagation();const l=bt();switch(e.action.type){case"next":l.play();break;case"goto":if(e.action.url){e.action.target,e.action.url,await this.flushAnalytics();const t=bt();if(t.manifest){vt.setState((t=>{t.currentStepId=e.action.target,t.manifest&&(t.progress[t.manifest.id]={...t.progress[t.manifest.id],lastStepId:e.action.target,lastProgressAt:Date.now(),lastVisited:(new Date).toISOString()})}));try{if(e.action.target,(null==(n=t.config)?void 0:n.token)&&(null==(i=t.user)?void 0:i.id)&&!(null==(s=t.user)?void 0:s.__isAnonymous)){const n=`https://player.saltfish.ai/clients/${t.config.token}/users/${t.user.id}/playlists/${t.manifest.id}`,i=await fetch(n,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({status:"in_progress",currentStepId:e.action.target})});i.ok?e.action.target:(i.statusText,i.status)}}catch(c){console.error("InteractionManager: Full error:",c)}if((null==(r=t.playlistOptions)?void 0:r.persistence)??!0){const n=null==(a=t.user)?void 0:a.id,i=bt();if(this.storageManager.setProgress(i.progress,n),e.action.target,null==(o=t.user)?void 0:o.__isAnonymous){const n=this.storageManager.getAnonymousUserData();n&&(n.watchedPlaylists=n.watchedPlaylists||{},n.watchedPlaylists[t.manifest.id]={status:"in_progress",currentStepId:e.action.target,timestamp:Date.now(),lastProgressAt:Date.now()},this.storageManager.setAnonymousUserData(n),e.action.target)}}}const l=ue(e.action.url);window.location.href=l}else e.action.target,l.goToStep(e.action.target);break;case"url":if(e.action.target,await this.flushAnalytics(),"completedWaitingForInteraction"===l.currentState)l.completePlaylist(),await new Promise((t=>setTimeout(t,It)));else{this.isCurrentStepLast(l)&&(l.goToStep("completed"),await new Promise((t=>setTimeout(t,It))))}const t=ue(e.action.target);window.open(t,"_blank");const{SaltfishPlayer:d}=await Promise.resolve().then((()=>Ve)),h=d.getInstance();h&&h.destroy();break;case"playlist":e.action.target;try{await this.flushAnalytics(),l.completePlaylist(),await new Promise((t=>setTimeout(t,It)));const{SaltfishPlayer:t}=await Promise.resolve().then((()=>Ve)),n=t.getInstance();n&&(e.action.target,await n.startPlaylist(e.action.target))}catch(c){console.error(`InteractionManager: Error starting playlist "${e.action.target}":`,c),e.action.target}break;default:e.action.type}if(l.manifest){const t={buttonId:e.id,actionType:e.action.type,actionTarget:e.action.target};JSON.stringify(t)}}isCurrentStepLast(t){if(!t.manifest||!t.currentStepId||!t.manifest.steps)return!1;const e=t.manifest.steps;return e.findIndex((e=>e.id===t.currentStepId))===e.length-1}async flushAnalytics(){try{const{SaltfishPlayer:t}=await Promise.resolve().then((()=>Ve)),e=t.getInstance(),n=e;if(e&&n.analyticsManager){const t=n.analyticsManager;"function"==typeof t.flush&&await t.flush()}}catch(t){}}reset(){this.clearButtons(),this.buttonContainer=null,this.scrollIndicator=null,this.container&&this.container.removeEventListener("video90PercentReached",this.handleVideo90PercentReached)}destroy(){this.storeUnsubscribe&&(this.storeUnsubscribe(),this.storeUnsubscribe=null),this.container&&this.container.removeEventListener("video90PercentReached",this.handleVideo90PercentReached),this.clearButtons(),this.container=null}}class me{constructor(t){e(this,"eventManager",null),t&&this.setEventManager(t)}setEventManager(t){this.eventManager=t,this.subscribeToEvents()}}class ge extends me{constructor(t){super(t),e(this,"config",null),e(this,"user",null),e(this,"eventQueue",[]),e(this,"isSending",!1),e(this,"flushInterval",null),e(this,"sessionId",null),e(this,"analyticsEnabled",!0)}subscribeToEvents(){this.eventManager&&(this.eventManager.on("playerPaused",(t=>{const e=bt(),n=this.getRunId();(null==e?void 0:e.manifest)&&e.currentStepId&&n&&this.trackEvent({type:"playerPaused",playlistId:e.manifest.id,stepId:e.currentStepId,runId:n,timestamp:Date.now()})})),this.eventManager.on("playerResumed",(t=>{const e=bt(),n=this.getRunId();(null==e?void 0:e.manifest)&&e.currentStepId&&n&&this.trackEvent({type:"playerResumed",playlistId:e.manifest.id,stepId:e.currentStepId,runId:n,timestamp:Date.now()})})),this.eventManager.on("stepStarted",(t=>{t.step.id,this.trackStepStarted(t.playlist.id,t.step.id)})),this.eventManager.on("stepEnded",(t=>{t.step.id,this.trackStepComplete(t.playlist.id,t.step.id)})),this.eventManager.on("playlistEnded",(t=>{t.playlist.id,this.trackPlaylistComplete(t.playlist.id)})),this.eventManager.on("error",(t=>{t.playlistId&&this.trackError(t.playlistId,t.error,t.stepId,t.errorType,t.videoUrl,t.mediaErrorCode,t.mediaErrorMessage,t.failureReason)})),this.eventManager.on("playerMinimized",(t=>{const e=bt(),n=this.getRunId();(null==e?void 0:e.manifest)&&e.currentStepId&&n&&this.trackEvent({type:"playerMinimized",playlistId:e.manifest.id,stepId:e.currentStepId,runId:n,timestamp:Date.now()})})),this.eventManager.on("playerMaximized",(t=>{const e=bt(),n=this.getRunId();(null==e?void 0:e.manifest)&&e.currentStepId&&n&&this.trackEvent({type:"playerMaximized",playlistId:e.manifest.id,stepId:e.currentStepId,runId:n,timestamp:Date.now()})})))}initialize(t,e){this.config=t,this.analyticsEnabled=!1!==t.enableAnalytics,e&&(this.sessionId=e),this.analyticsEnabled&&(this.flushInterval=window.setInterval((()=>{this.flushEvents()}),Mt))}setUser(t){this.user=t}trackPlaylistStart(t){if(!this.analyticsEnabled)return;const e=this.getRunId();e&&this.trackEvent({type:"playlistStart",playlistId:t,runId:e,timestamp:Date.now()})}trackPlaylistComplete(t){if(!this.analyticsEnabled)return;const e=this.getRunId();e&&this.trackEvent({type:"playlistComplete",playlistId:t,runId:e,timestamp:Date.now()})}trackStepStarted(t,e){if(!this.analyticsEnabled)return;const n=this.getRunId();n&&this.trackEvent({type:"stepStarted",playlistId:t,stepId:e,runId:n,timestamp:Date.now()})}trackStepComplete(t,e){if(!this.analyticsEnabled)return;const n=this.getRunId();n&&this.trackEvent({type:"stepComplete",playlistId:t,stepId:e,runId:n,timestamp:Date.now()})}trackInteraction(t,e,n){if(!this.analyticsEnabled)return;const i=this.getRunId();i&&this.trackEvent({type:"interaction",playlistId:t,stepId:e,runId:i,timestamp:Date.now(),data:n})}trackError(t,e,n,i,s,r,a,o){if(!this.analyticsEnabled)return;const l=this.getRunId();l&&this.trackEvent({type:"error",playlistId:t,stepId:n,runId:l,timestamp:Date.now(),data:{message:e.message,stack:e.stack,errorType:i||"unknown",videoUrl:s||null,mediaErrorCode:r||null,mediaErrorMessage:a||null,failureReason:o||"unknown"}})}trackEvent(t){this.analyticsEnabled&&(this.eventQueue.push(t),this.eventQueue.length>=10&&this.flushEvents())}async flush(){await this.flushEvents()}async flushEvents(){if(!this.isSending&&0!==this.eventQueue.length&&this.config&&this.analyticsEnabled){this.isSending=!0;try{const t=[...this.eventQueue];this.eventQueue=[];const e={token:this.config.token,sessionId:this.sessionId,user:this.user,events:t},n=await fetch("https://player.saltfish.ai/analytics",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(e)});if(!n.ok)throw this.eventQueue=[...t,...this.eventQueue],new Error(`Failed to send analytics events: ${n.statusText}`)}catch(t){console.error("Failed to send analytics events:",t)}finally{this.isSending=!1}}}destroy(){this.analyticsEnabled&&this.flushEvents(),null!==this.flushInterval&&(clearInterval(this.flushInterval),this.flushInterval=null),this.eventManager&&(this.eventManager=null),this.config=null,this.user=null,this.eventQueue=[],this.sessionId=null,this.analyticsEnabled=!0}getRunId(){try{return Le.getInstance().getRunId()}catch(t){return null}}}class fe{constructor(t){e(this,"sessionId"),e(this,"currentRunId",null),e(this,"storageManager"),this.storageManager=t||gt.getInstance(),this.sessionId=this.getOrCreateSession(),this.sessionId}getOrCreateSession(){if("undefined"==typeof window)return this.generateUniqueId();const t=this.storageManager.getSession();if(t){if(Date.now()-t.lastActivity<Tt)return t.sessionId,this.updateSessionActivity(t.sessionId),t.sessionId}const e=this.generateUniqueId();return this.updateSessionActivity(e),e}updateSessionActivity(t){if("undefined"==typeof window)return;const e={sessionId:t,lastActivity:Date.now()};this.storageManager.setSession(e)}generateUniqueId(){return"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,(function(t){const e=16*Math.random()|0;return("x"===t?e:3&e|8).toString(16)}))}getSessionId(){return this.updateSessionActivity(this.sessionId),this.sessionId}startNewRun(){return this.currentRunId=this.generateUniqueId(),this.currentRunId,this.updateSessionActivity(this.sessionId),this.currentRunId}getCurrentRunId(){return this.currentRunId}endCurrentRun(){this.currentRunId&&(this.currentRunId,this.currentRunId=null)}expireSession(){"undefined"!=typeof window&&(this.storageManager.clearSession(),this.sessionId),this.sessionId=this.generateUniqueId(),this.updateSessionActivity(this.sessionId),this.currentRunId=null,this.sessionId}destroy(){this.updateSessionActivity(this.sessionId),this.endCurrentRun()}}class ye{constructor(){e(this,"activeTransitions",new Map),e(this,"waitingForInteraction",!1),e(this,"isStateMachineValidating",!1),e(this,"triggerManager",null),e(this,"beforeUnloadHandler",null),e(this,"handleURLChange",(()=>{if(this.isStateMachineValidating)return;const t=Array.from(this.activeTransitions.entries()).filter((([t,e])=>{var n;return"url-path"===(null==(n=e.data)?void 0:n.type)}));let e=!1;if(t.length>0)for(const[n,i]of t)if(i.data&&this.isURLPathMatch(i.data.pattern)){e=!0;break}if(!e){if(!this.validateCurrentStepUrl())return}if(this.triggerManager&&this.triggerManager.evaluateAllTriggers(),e)for(const[n,i]of t){if(!i.data)continue;const{pattern:t,nextStepId:e}=i.data;if(this.isURLPathMatch(t)){gt.getInstance().clearPendingNavigation(),this.triggerTransition(e);break}}})),window.addEventListener("popstate",this.handleURLChange),this.monitorHistoryChanges()}setTriggerManager(t){this.triggerManager=t}monitorHistoryChanges(){const t=history.pushState,e=history.replaceState;history.pushState=(...e)=>{t.apply(history,e),this.handleURLChange()},history.replaceState=(...t)=>{e.apply(history,t),this.handleURLChange()}}setupTransitions(t,e=!1,n=!1){this.cleanupTransitions(),t.id,t.transitions.forEach((t=>{switch(t.type){case"dom-click":this.setupDOMClickTransition(t);break;case"timeout":n||this.setupTimeoutTransition(t,e);break;case"url-path":this.setupURLPathTransition(t);break;case"dom-element-visible":this.setupDOMElementVisibleTransition(t);break;default:t.type}}))}setupDOMClickTransition(t){if(!t.target)return;const e=t.target,n=t.nextStep,i=`dom-click-${e}-${Date.now()}`,s=new Map;let r=null;const a=t=>{0!==t.length&&(t.length,t.forEach((t=>{if(s.has(t))return;const e=async t=>{const e=t.target;if(this.willCauseHardRefresh(e)){t.preventDefault(),t.stopImmediatePropagation();await this.triggerTransitionWithProgress(n)&&this.reDispatchClick(t)}else this.triggerTransition(n)};s.set(t,e),t.addEventListener("click",e,{capture:!0})})))},o=t.expectedElement||t.expectedSize?oe(e,t.expectedElement,t.expectedSize):Array.from(document.querySelectorAll(e));a(o),r=new MutationObserver((n=>{for(const i of n)"childList"===i.type&&i.addedNodes.forEach((n=>{if(n.nodeType===Node.ELEMENT_NODE){const i=n;i.matches(e)&&(!t.expectedElement&&!t.expectedSize||le(i,t.expectedElement,t.expectedSize))&&a([i]);const s=i.querySelectorAll(e);if(s.length>0){const e=t.expectedElement||t.expectedSize?Array.from(s).filter((e=>le(e,t.expectedElement,t.expectedSize))):Array.from(s);e.length>0&&(e.length,a(e))}}}))})),r.observe(document.body,{childList:!0,subtree:!0}),this.activeTransitions.set(i,{handlers:s,cleanup:()=>{s.forEach(((t,e)=>{e.removeEventListener("click",t,{capture:!0})})),s.clear(),r&&(r.disconnect(),r=null)},data:{type:"dom-click",pattern:e,nextStepId:n}})}setupTimeoutTransition(t,e){const n=t.nextStep,i=t.timeout||0,s=`timeout-${i}-${Date.now()}`;let r=null;e?this.triggerTransition(n):r=window.setTimeout((()=>{this.triggerTransition(n)}),i),this.activeTransitions.set(s,{handlers:new Map,cleanup:()=>{null!==r&&(clearTimeout(r),r=null)},data:{type:"timeout",pattern:"",nextStepId:n}})}setupURLPathTransition(t){if(!t.target)return;const e=t.target,n=t.nextStep;this.savePendingNavigation(e,n),this.setupBeforeUnloadHandler(e,n);if(this.isURLPathMatch(e)){this.triggerTransition(n);const t=5;let e=0;const i=()=>{if(e>=t)return;e++;const s=bt();"waitingForInteraction"===s.currentState||"playing"===s.currentState?(s.currentState,this.triggerTransition(n)):e<t&&(s.currentState,setTimeout(i,Ct))};setTimeout(i,Ct)}const i=`url-path-${Date.now()}`,s=window.setInterval((()=>{this.isURLPathMatch(e)&&(clearInterval(s),gt.getInstance().clearPendingNavigation(),this.triggerTransition(n))}),kt);this.activeTransitions.set(i,{handlers:new Map,cleanup:()=>{clearInterval(s)},data:{type:"url-path",pattern:e,nextStepId:n}})}savePendingNavigation(t,e){const n=bt();if(!n.manifest)return;gt.getInstance().setPendingNavigation({playlistId:n.manifest.id,nextStepId:e,urlPattern:t,timestamp:Date.now()})}setupBeforeUnloadHandler(t,e){this.removeBeforeUnloadHandler(),this.beforeUnloadHandler=()=>{this.savePendingNavigation(t,e)},window.addEventListener("beforeunload",this.beforeUnloadHandler)}removeBeforeUnloadHandler(){this.beforeUnloadHandler&&(window.removeEventListener("beforeunload",this.beforeUnloadHandler),this.beforeUnloadHandler=null)}isURLPathMatch(t){if(!t)return!1;const e=window.location.href,n=window.location.pathname,i=t.replace(/[.*+?^${}()|[\]\\]/g,"\\$&").replace(/\\\*/g,".*"),s=new RegExp(i),r=s.test(e),a=s.test(n);return r||a}handleUrlRequirementFailure(t,e){e.pattern,e.matchType,this.cleanupTransitions();const n=window._saltfishPlayer;n&&"function"==typeof n.destroy&&n.destroy()}validateCurrentStepUrl(){const t=bt(),e=t.manifest,n=t.currentStepId;if(!e||!n)return!0;const i=e.steps.find((t=>t.id===n));if(!i||!i.urlRequirement)return!0;const s=Bt(i.urlRequirement);return s||this.handleUrlRequirementFailure(n,i.urlRequirement),s}triggerTransition(t){var e;const n=bt(),i=n.currentState;n.currentStepId;const s=n.isMinimized;"playing"!==i&&"waitingForInteraction"!==i||s||(this.cleanupTransitions(),n.goToStep?n.goToStep(t):null==(e=n.goToStep)||e.call(n,t))}async triggerTransitionWithProgress(t){const e=bt(),n=e.currentState;e.currentStepId;const i=e.isMinimized;if("playing"!==n&&"waitingForInteraction"!==n)return!1;if(i)return!1;try{return this.triggerTransition(t),await new Promise((t=>setTimeout(t,It))),!0}catch(s){return!1}}cleanupTransitions(){this.activeTransitions.forEach((t=>{t.cleanup()})),this.activeTransitions.clear(),this.waitingForInteraction=!1,this.removeBeforeUnloadHandler()}setWaitingForInteraction(t){this.waitingForInteraction=t}isWaitingForInteraction(){return this.waitingForInteraction}reset(){this.cleanupTransitions()}startStateMachineValidation(){this.isStateMachineValidating=!0}endStateMachineValidation(){this.isStateMachineValidating=!1}destroy(){this.cleanupTransitions(),window.removeEventListener("popstate",this.handleURLChange)}setupDOMElementVisibleTransition(t){if(!t.target)return;const e=t.target,n=t.nextStep,i=`dom-visible-${e}-${Date.now()}`;let s=null,r=null,a=null,o=null;const l=t=>{s||(a=t,s=new IntersectionObserver((t=>{t.forEach((t=>{var e;if(t.isIntersecting,t.intersectionRatio.toFixed(2),t.target.outerHTML.substring(0,100),t.isIntersecting&&t.target===a){const s=window.getComputedStyle(t.target);if(!("0"!==s.opacity&&"none"!==s.display&&"visible"===s.visibility&&"none"!==s.pointerEvents))return;this.triggerTransition(n),null==(e=this.activeTransitions.get(i))||e.cleanup(),this.activeTransitions.delete(i)}else if(t.target===a){const e=t.target.getBoundingClientRect();e.top.toFixed(0),e.left.toFixed(0),e.bottom.toFixed(0),e.right.toFixed(0),e.width.toFixed(0),e.height.toFixed(0)}}))}),{root:null,rootMargin:"0px",threshold:0}),s.observe(t),r&&(r.disconnect(),r=null))},c=t.expectedElement||t.expectedSize?ae(e,t.expectedElement,t.expectedSize):document.querySelector(e);c?l(c):(r=new MutationObserver((n=>{for(const i of n)if("childList"===i.type&&i.addedNodes.forEach((n=>{if(n.nodeType===Node.ELEMENT_NODE){const i=n;if(i.matches(e)&&(!t.expectedElement&&!t.expectedSize||le(i,t.expectedElement,t.expectedSize)))return void l(i);const s=t.expectedElement||t.expectedSize?ae(e,t.expectedElement,t.expectedSize):i.querySelector(e);if(s)return void l(s)}})),!r)break})),r.observe(document.body,{childList:!0,subtree:!0}),o=window.setInterval((()=>{if(!r)return void(o&&clearInterval(o));const n=t.expectedElement||t.expectedSize?ae(e,t.expectedElement,t.expectedSize):document.querySelector(e);n&&n.offsetWidth>0&&n.offsetHeight>0&&(o&&clearInterval(o),o=null,l(n))}),1e3)),this.activeTransitions.set(i,{handlers:new Map,cleanup:()=>{s&&(s.disconnect(),s=null),r&&(r.disconnect(),r=null),o&&(clearInterval(o),o=null),a=null},data:{type:"dom-element-visible",pattern:e,nextStepId:n}})}reDispatchClick(t){const e=t.target;if(e&&e instanceof HTMLElement)try{setTimeout((()=>{e.tagName,e.id&&e.id,e.className&&e.className.split(" ").join(".");const n=new MouseEvent("click",{bubbles:!0,cancelable:!0,view:window,button:t.button||0,buttons:t.buttons||1,clientX:t.clientX||0,clientY:t.clientY||0,ctrlKey:t.ctrlKey||!1,shiftKey:t.shiftKey||!1,altKey:t.altKey||!1,metaKey:t.metaKey||!1});e.dispatchEvent(n)}),10)}catch(n){}}willCauseHardRefresh(t){try{if("A"===t.tagName&&t.hasAttribute("href")){const e=t.getAttribute("href");if(!e)return!1;const n=new URL(e,window.location.href),i=new URL(window.location.href);if(n.origin!==i.origin)return n.origin,i.origin,!0;const s=t.getAttribute("target");return!(!s||"_self"===s)||("mailto:"===n.protocol||"tel:"===n.protocol||"sms:"===n.protocol||"javascript:"===n.protocol)&&(n.protocol,!0)}const e=t.closest("form");if(e&&e.hasAttribute("action")){const t=e.getAttribute("action");if(t&&"#"!==t&&""!==t)return!1}return t.tagName,!1}catch(e){return!1}}}class ve{constructor(){e(this,"triggeredPlaylists",[]),e(this,"triggeredPlaylistsSet",new Set),e(this,"isMonitoring",!1),e(this,"elementClickedListeners",new Map),e(this,"clickedElements",new Set),e(this,"elementVisibleObservers",new Map),e(this,"visibleElements",new Set)}registerTriggers(t){this.triggeredPlaylists=t.filter((t=>(t.hasTriggers??t.autoStart??!1)&&t.triggers)),this.triggeredPlaylists.length,this.triggeredPlaylists.forEach((t=>{var e,n,i,s;t.id,null==(e=t.triggers)||e.url,null==(n=t.triggers)||n.elementClicked,null==(i=t.triggers)||i.elementVisible,null==(s=t.triggers)||s.maxVisits})),this.setupElementClickListeners(),this.setupElementVisibleObservers()}startMonitoring(){this.isMonitoring||(this.isMonitoring=!0,this.evaluateAllTriggers())}stopMonitoring(){this.isMonitoring=!1}evaluateAllTriggers(){if(this.isMonitoring&&0!==this.triggeredPlaylists.length)for(const t of this.triggeredPlaylists){if(this.evaluatePlaylistTrigger(t)){t.id;break}}}evaluatePlaylistTrigger(t){if(!t.triggers)return!1;const{triggers:e}=t,n=t.id;if(this.triggeredPlaylistsSet.has(n))return!1;if(!bt().user)return!1;const i=[],s=this.getWatchedPlaylists(),r=this.evaluateMaxVisitsCondition(e.maxVisits,n,s);i.push(r);const a=this.evaluateURLCondition(e);i.push(a),e.url;const o=this.evaluatePlaylistSeenCondition(e.playlistSeen,s);i.push(o),JSON.stringify(e.playlistSeen);const l=this.evaluatePlaylistNotSeenCondition(e.playlistNotSeen,s);i.push(l),JSON.stringify(e.playlistNotSeen);const c=this.evaluateElementClickCondition(e.elementClicked);i.push(c),e.elementClicked;const d=this.evaluateElementVisibleCondition(e.elementVisible);i.push(d),e.elementVisible;const h=this.evaluateUserAttributesCondition(e.userAttributes);i.push(h),JSON.stringify(e.userAttributes);const u=this.applyOperators(i,e.operators);return e.operators.join(", "),!!u&&(this.triggerPlaylist(n),!0)}getWatchedPlaylists(){var t,e;const n=bt();if((null==(t=n.userData)?void 0:t.watchedPlaylists)&&Object.keys(n.userData.watchedPlaylists).length>0)return n.userData.watchedPlaylists;const i=gt.getInstance().getProgress(null==(e=n.user)?void 0:e.id);if(!i)return{};const s={};for(const r of Object.keys(i))s[r]={status:"in_progress",timestamp:Date.now()};return JSON.stringify(Object.keys(s)),s}evaluateMaxVisitsCondition(t,e,n){if(null===t)return!0;const i=n&&n[e];return((null==i?void 0:i.visitCount)??("completed"===(null==i?void 0:i.status)||"dismissed"===(null==i?void 0:i.status)?1:0))<t}normalizeUrl(t){return t.endsWith("/")&&t.lastIndexOf("/")>t.indexOf("://")+2?t.slice(0,-1):t}evaluateURLCondition(t){let e=t.url;if(!e)return!0;const n=this.normalizeUrl(window.location.href.split("#")[0]),i=window.location.pathname;if("regex"===t.urlMatchType)try{const t=new RegExp(e),s=t.test(n),r=t.test(i);return s||r}catch(c){return!1}"contains"!==t.urlMatchType||e.includes("*")||(e="*"+e+"*");const s=e.includes("*");s||t.urlMatchType&&"exact"!==t.urlMatchType&&"contains"!==t.urlMatchType||(e=this.normalizeUrl(e));let r=e.replace(/[.*+?^${}()|[\]\\]/g,"\\$&").replace(/\\\*/g,".*");s||(r="^"+r+"$");const a=new RegExp(r),o=a.test(n),l=a.test(i);return t.url,t.urlMatchType,o||l}evaluatePlaylistSeenCondition(t,e){if(!t||0===t.length)return!0;if(!e)return!1;for(const n of t){const t=e[n];if(!t||"completed"!==t.status&&"in_progress"!==t.status)return!1}return!0}evaluatePlaylistNotSeenCondition(t,e){if(!t||0===t.length)return!0;if(!e)return!0;for(const n of t){const t=e[n];if(t&&("completed"===t.status||"in_progress"===t.status))return!1}return!0}evaluateElementClickCondition(t){if(!t)return!0;return this.clickedElements.has(t)}evaluateElementVisibleCondition(t){if(!t)return!0;return this.visibleElements.has(t)}evaluateUserAttributesCondition(t){if(!t||0===t.length)return!0;const e=bt().user;if(!e)return!1;for(const n of t){const{attributeKey:t,attributeType:i,operator:s,value:r}=n,a=e[t];if(null==a)return!1;if(!this.compareValues(a,r,i,s))return!1}return!0}compareValues(t,e,n,i){try{switch(n){case"string":{const n=String(t),s=e;return this.applyOperator(n,s,i)}case"boolean":{const n="boolean"==typeof t?t:"true"===String(t).toLowerCase(),s="true"===e.toLowerCase();return"equals"===i?n===s:"notEquals"===i&&n!==s}case"int":{const n="number"==typeof t?t:parseFloat(String(t)),s=parseFloat(e);return!isNaN(n)&&!isNaN(s)&&this.applyOperator(n,s,i)}case"date":{const n=t instanceof Date?t:new Date(String(t)),s=new Date(e);return!isNaN(n.getTime())&&!isNaN(s.getTime())&&this.applyOperator(n.getTime(),s.getTime(),i)}default:return!1}}catch(s){return!1}}applyOperator(t,e,n){switch(n){case"equals":return t===e;case"notEquals":return t!==e;case"greaterThan":return t>e;case"lessThan":return t<e;default:return!1}}setupElementClickListeners(){this.clearElementClickListeners(),this.triggeredPlaylists.forEach((t=>{var e;(null==(e=t.triggers)?void 0:e.elementClicked)&&this.setupElementClickListener(t.id,t.triggers.elementClicked,t.triggers.elementClickedExpectedElement,t.triggers.elementClickedExpectedSize)}))}setupElementClickListener(t,e,n,i){try{const s=n||i?ae(e,n,i):document.querySelector(e);if(!s)return;if(!this.triggeredPlaylists.find((e=>e.id===t)))return;const r=t=>{t.preventDefault(),t.stopPropagation(),this.clickedElements.add(e),this.evaluateAllTriggers()};s.addEventListener("click",r);const a=`${t}-${e}`;this.elementClickedListeners.set(a,{element:s,listener:r,selector:e})}catch(s){}}clearElementClickListeners(){this.elementClickedListeners.forEach((({element:t,listener:e})=>{try{t.removeEventListener("click",e)}catch(n){console.error("TriggerManager: Error removing element click listener:",n)}})),this.elementClickedListeners.clear()}setupElementVisibleObservers(){this.clearElementVisibleObservers(),this.triggeredPlaylists.forEach((t=>{var e;(null==(e=t.triggers)?void 0:e.elementVisible)&&this.setupElementVisibleObserver(t.id,t.triggers.elementVisible,t.triggers.elementVisibleExpectedElement,t.triggers.elementVisibleExpectedSize)}))}setupElementVisibleObserver(t,e,n,i){try{const s=`${t}-${e}`;if(this.elementVisibleObservers.has(s))return;const r=t=>{const n=new IntersectionObserver((t=>{t.forEach((t=>{if(t.isIntersecting,t.intersectionRatio.toFixed(2),t.isIntersecting){const n=window.getComputedStyle(t.target);if(!("0"!==n.opacity&&"none"!==n.display&&"visible"===n.visibility&&"none"!==n.pointerEvents))return;this.visibleElements.add(e),this.evaluateAllTriggers()}else this.visibleElements.has(e)&&this.visibleElements.delete(e)}))}),{root:null,rootMargin:"0px",threshold:0});n.observe(t);const i=this.elementVisibleObservers.get(s);i?(i.mutationObserver&&i.mutationObserver.disconnect(),this.elementVisibleObservers.set(s,{observer:n,mutationObserver:null,selector:e})):this.elementVisibleObservers.set(s,{observer:n,mutationObserver:null,selector:e})},a=n||i?ae(e,n,i):document.querySelector(e);if(a)r(a);else{const t=new MutationObserver((t=>{for(const s of t)"childList"===s.type&&s.addedNodes.forEach((t=>{if(t.nodeType===Node.ELEMENT_NODE){const s=t;if(s.matches(e))(!n&&!i||le(s,n,i))&&r(s);else{const t=n||i?ae(e,n,i):s.querySelector(e);t&&r(t)}}}))}));t.observe(document.body,{childList:!0,subtree:!0}),this.elementVisibleObservers.set(s,{observer:null,mutationObserver:t,selector:e})}}catch(s){}}clearElementVisibleObservers(){this.elementVisibleObservers.forEach((({observer:t,mutationObserver:e})=>{try{t&&t.disconnect(),e&&e.disconnect()}catch(n){console.error("TriggerManager: Error removing element visibility observer:",n)}})),this.elementVisibleObservers.clear()}applyOperators(t,e){return 0!==t.length&&(1===t.length?t[0]:e&&0!==e.length&&e.includes("OR")?t.some((t=>t)):t.every((t=>t)))}async triggerPlaylist(t){this.triggeredPlaylistsSet.add(t);try{const e=window._saltfishPlayer;e&&"function"==typeof e.startPlaylist&&await e.startPlaylist(t,{_triggeredByTriggerManager:!0})}catch(e){this.triggeredPlaylistsSet.delete(t)}}resetTriggeredPlaylists(){this.triggeredPlaylistsSet.clear()}getTriggeredPlaylists(){return Array.from(this.triggeredPlaylistsSet)}markPlaylistAsTriggered(t){this.triggeredPlaylistsSet.has(t)||this.triggeredPlaylistsSet.add(t)}destroy(){this.stopMonitoring(),this.clearElementClickListeners(),this.clearElementVisibleObservers(),this.triggeredPlaylists=[],this.triggeredPlaylistsSet.clear(),this.clickedElements.clear(),this.visibleElements.clear()}}class be extends me{constructor(t){super(t)}subscribeToEvents(){this.eventManager&&this.eventManager.on("playlistStarted",(t=>{this.trackTestParticipation(t.playlist.id)}))}initializeTests(t){bt().setABTests(t)}assignUserToTests(t,e,n){var i,s;const r=bt(),a=r.abTests||[],o={...e};for(const l of a){const e=l.testType||"percentage";if("userList"!==e&&o[l.id])continue;let a=!1;if("userList"===e){a=!(!0===(null==(s=null==(i=r.user)?void 0:i.userData)?void 0:s.__isAnonymous))&&!0===(null==n?void 0:n[l.id])}else a=this.isUserInTest(t,l);o[l.id]={testId:l.id,assigned:a,assignedAt:Date.now()},l.name}return r.setABTestAssignments(o),o}isUserInTest(t,e){if(!e.percentage)return!1;const n=`${t}_${e.id}`;let i=0;for(let s=0;s<n.length;s++){i=(i<<5)-i+n.charCodeAt(s),i|=0}return Math.abs(i)%100<e.percentage}getFilteredPlaylists(t){const e=bt(),n=e.abTests||[],i=e.abTestAssignments||{};if(0===n.length)return t;const s=new Set;for(const a of n){const t=i[a.id];t&&t.assigned||(s.add(a.playlistId),a.playlistId,a.name)}const r=t.filter((t=>!s.has(t.id)));return t.length,r.length,r}trackTestParticipation(t){var e;const n=bt(),i=n.abTests||[],s=n.abTestAssignments||{},r=i.find((e=>e.playlistId===t));if(!r)return;const a=s[r.id];a&&a.assigned&&(r.testType,r.name,this.eventManager&&this.eventManager.trigger("abTestParticipation",{testId:r.id,testName:r.name,testType:r.testType||"percentage",playlistId:t,userId:null==(e=n.user)?void 0:e.id,timestamp:Date.now()}))}getAssignmentsForBackend(){return bt().abTestAssignments||{}}isPlaylistAvailable(t){const e=bt(),n=e.abTests||[],i=e.abTestAssignments||{},s=n.find((e=>e.playlistId===t));if(!s)return!0;const r=i[s.id];return r&&r.assigned}getActiveTestInfo(){const t=bt(),e=t.abTests||[],n=t.abTestAssignments||{};return e.map((t=>{var e;return{testId:t.id,testName:t.name,testType:t.testType||"percentage",assigned:(null==(e=n[t.id])?void 0:e.assigned)||!1}}))}}class we{constructor(){e(this,"listeners",new Map)}on(t,e){this.listeners.has(t)||this.listeners.set(t,new Set),this.listeners.get(t).add(e)}off(t,e){const n=this.listeners.get(t);return!!n&&n.delete(e)}trigger(t,e){const n=this.listeners.get(t);n&&0!==n.size&&("timestamp"in e||(e.timestamp=Date.now()),n.forEach((n=>{try{n(e)}catch(i){console.error(`Error in ${t} event handler:`,i)}})))}removeAllListeners(){this.listeners.clear()}getListenerCount(t){const e=this.listeners.get(t);return e?e.size:0}}class Se{async loadManifest(t){const{manifestPath:e,playlistOptions:n,savedProgress:i}=t;try{const t=await this.fetchManifest(e);this.validateManifest(t);const s=this.determineStartStep(t,n,i);return t.id,{manifest:t,startStepId:s}}catch(s){const t=s instanceof Error?s.message:"Unknown error";throw G("[PlaylistLoader] Failed to load manifest:",s),new Error(`Unable to load playlist manifest: ${t}`)}}async fetchManifest(t){try{const e=await fetch(t);if(e.status,e.statusText,!e.ok)throw new Error(`HTTP ${e.status}: ${e.statusText}`);return await e.json()}catch(e){throw G("[PlaylistLoader] Fetch/parse failed:",e),G("[PlaylistLoader] Manifest path:",t),new Error(`Failed to fetch manifest from "${t}": ${e instanceof Error?e.message:"Unknown error"}`)}}validateManifest(t){if(!t)throw new Error("Manifest is null or undefined");if("object"!=typeof t)throw new Error("Manifest must be an object");const e=t,n=["id","startStep","steps"];for(const s of n)if(!(s in e))throw new Error(`Manifest missing required field: ${s}`);if(!Array.isArray(e.steps))throw new Error("Manifest steps must be an array");const i=e.steps;if(0===i.length)throw new Error("Manifest must contain at least one step");if(!i.some((t=>"object"==typeof t&&null!==t&&"id"in t&&t.id===e.startStep)))throw new Error(`Start step '${e.startStep}' not found in steps array`);for(const s of i){if("object"!=typeof s||null===s)throw new Error("Each step must be an object");const t=s;if(!t.id)throw new Error("Each step must have an id");if(!t.transitions||!Array.isArray(t.transitions))throw new Error(`Step '${t.id}' must have transitions array`)}}determineStartStep(t,e,n){const i=e.persistence??t.isPersistent??!0,s=t.id,r=!0===e._triggeredByTriggerManager;let a=t.startStep;const o=this.checkPendingNavigation(t);if(o)return o.nextStepId,o.nextStepId;if(e.startNodeId){t.steps.find((t=>t.id===e.startNodeId))?(e.startNodeId,a=e.startNodeId):e.startNodeId}else if(r)a=t.startStep;else if(i&&n&&n[s]){const e=n[s];if("completed"===e.status)a=t.startStep;else{const{isValid:n,ageMs:i}=St(e);if(n){const n=e.currentStepId||e.lastStepId;if(n){t.steps.find((t=>t.id===n))&&(a=n)}}else a=t.startStep}}return a}checkPendingNavigation(t){const e=gt.getInstance(),n=e.getPendingNavigation();if(!n)return null;if(n.playlistId!==t.id)return n.playlistId,null;const i=Date.now()-n.timestamp;if(i>At)return e.clearPendingNavigation(),null;if(!this.isURLPathMatch(n.urlPattern))return n.urlPattern,e.clearPendingNavigation(),null;return t.steps.find((t=>t.id===n.nextStepId))?(n.nextStepId,Math.round(i/1e3),e.clearPendingNavigation(),n):(n.nextStepId,e.clearPendingNavigation(),null)}isURLPathMatch(t){if(!t)return!1;const e=window.location.href,n=window.location.pathname,i=t.replace(/[.*+?^${}()|[\]\\]/g,"\\$&").replace(/\\\*/g,".*"),s=new RegExp(i);return s.test(e)||s.test(n)}}class Ee extends me{constructor(t,n){super(t),e(this,"isUpdatingWatchedPlaylists",!1),e(this,"playlistLoader"),e(this,"storageManager"),this.playlistLoader=new Se,this.storageManager=n||gt.getInstance()}subscribeToEvents(){this.eventManager&&(this.eventManager.on("playlistStarted",(t=>{t.playlist.id,this.updateWatchedPlaylistStatus(t.playlist.id,"in_progress")})),this.eventManager.on("playlistEnded",(t=>{t.playlist.id,this.updateWatchedPlaylistStatus(t.playlist.id,"completed").catch((e=>{console.error(`PlaylistManager: Error in updateWatchedPlaylistStatus for playlist ${t.playlist.id}:`,e)}))})),this.eventManager.on("playlistDismissed",(t=>{t.playlist.id,this.updateWatchedPlaylistStatus(t.playlist.id,"dismissed")})),this.eventManager.on("stepStarted",(t=>{t.step.id,this.updateWatchedPlaylistStatus(t.playlist.id,"in_progress",t.step.id)})))}async updateWatchedPlaylistStatus(t,e,n){var i,s,r,a,o,l;if(!this.isUpdatingWatchedPlaylists){this.isUpdatingWatchedPlaylists=!0;try{const d=bt(),h=d.userData||{},u=h.watchedPlaylists||{},p=u[t],m=null==p?void 0:p.status,g=(null==p?void 0:p.visitCount)??0,f=("completed"===e||"dismissed"===e)&&m!==e,y={status:e,currentStepId:"completed"===e?null:n||d.currentStepId||null,timestamp:Date.now(),lastProgressAt:Date.now(),visitCount:f?g+1:g},v={...u,[t]:y};if(d.setUserData({...h,watchedPlaylists:v}),!(null==(i=null==d?void 0:d.config)?void 0:i.token)||!(null==(s=null==d?void 0:d.user)?void 0:s.id)||(null==(r=null==d?void 0:d.user)?void 0:r.__isAnonymous))return null==(a=null==d?void 0:d.config)||a.token,null==(o=null==d?void 0:d.user)||o.id,null==(l=null==d?void 0:d.user)||l.__isAnonymous,void this.updateAnonymousUserWatchedPlaylists(t,e,n||d.currentStepId||null);const b=`https://player.saltfish.ai/clients/${d.config.token}/users/${d.user.id}/playlists/${t}`;try{const t=await fetch(b,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({status:e,currentStepId:n||d.currentStepId||null})});if(!t.ok)throw new Error(`Failed to update watched playlist status: ${t.statusText} (${t.status})`)}catch(c){console.error(`PlaylistManager: Error updating watched playlist status for ${t}:`,c)}}finally{this.isUpdatingWatchedPlaylists=!1}}}updateAnonymousUserWatchedPlaylists(t,e,n){if("undefined"==typeof window)return;let i=this.storageManager.getAnonymousUserData()||{userId:"anonymous",userData:{},watchedPlaylists:{},timestamp:Date.now()};i.watchedPlaylists||(i.watchedPlaylists={});const s=i.watchedPlaylists[t],r=null==s?void 0:s.status,a=(null==s?void 0:s.visitCount)??0,o=("completed"===e||"dismissed"===e)&&r!==e;i.watchedPlaylists[t]={status:e,currentStepId:n||null,timestamp:Date.now(),lastProgressAt:Date.now(),visitCount:o?a+1:a},i.timestamp=Date.now(),this.storageManager.setAnonymousUserData(i)}async load(t,e){var n;try{const i=bt();if(!i)throw new Error("Store not available");const s=(null==(n=i.userData)?void 0:n.watchedPlaylists)||i.progress,r=await this.playlistLoader.loadManifest({manifestPath:t,playlistOptions:e,savedProgress:s}),{manifest:a,startStepId:o}=r,l=a.steps.find((t=>t.id===o));i.setManifest(a,o),l&&i.sendStateMachineEvent({type:"MANIFEST_LOADED",step:l})}catch(i){const t=bt(),e=i instanceof Error?i:new Error("Unknown error loading manifest");t?t.setError(e):console.error("[PlaylistManager] Cannot set error: Store not available",e)}}destroy(){this.eventManager&&(this.eventManager=null)}}class xe{constructor(t){e(this,"button"),e(this,"playerElement"),this.playerElement=t,this.button=document.createElement("button"),this.button.className="sf-player__minimize-button",this.button.innerHTML='\n <svg width="20" height="20" viewBox="0 0 256 256" fill="currentColor" xmlns="http://www.w3.org/2000/svg">\n <path d="M205.66,194.34a8,8,0,0,1-11.32,11.32L128,139.31,61.66,205.66a8,8,0,0,1-11.32-11.32L116.69,128,50.34,61.66A8,8,0,0,1,61.66,50.34L128,116.69l66.34-66.35a8,8,0,0,1,11.32,11.32L139.31,128Z"></path>\n </svg>\n ',this.button.addEventListener("click",this.handleClick.bind(this)),this.playerElement.appendChild(this.button),this.updateVisibility(bt().isMinimized)}handleClick(){const t=bt(),e=!t.isMinimized;e?t.minimize():t.maximize(),e?this.minimize():this.maximize()}minimize(){this.button.innerHTML='\n <svg width="18" height="18" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">\n <path d="M12 5v14M5 12h14" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>\n </svg>\n '}maximize(){this.button.innerHTML='\n <svg width="20" height="20" viewBox="0 0 256 256" fill="currentColor" xmlns="http://www.w3.org/2000/svg">\n <path d="M205.66,194.34a8,8,0,0,1-11.32,11.32L128,139.31,61.66,205.66a8,8,0,0,1-11.32-11.32L116.69,128,50.34,61.66A8,8,0,0,1,61.66,50.34L128,116.69l66.34-66.35a8,8,0,0,1,11.32,11.32L139.31,128Z"></path>\n </svg>\n '}updateVisibility(t){t?this.button.classList.add("sf-hidden"):this.button.classList.remove("sf-hidden")}destroy(){this.button.removeEventListener("click",this.handleClick.bind(this)),this.button.remove()}}class Me{constructor(t,n){e(this,"playButton"),e(this,"container"),e(this,"videoManager",null),this.container=t,this.videoManager=n||null,this.createButton()}createButton(){this.playButton=document.createElement("button"),this.playButton.className="sf-controls-container__play-button",this.playButton.innerHTML='\n <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">\n <path d="M8 5v14l11-7z" fill="currentColor"/>\n </svg>\n ',this.playButton.addEventListener("click",this.handlePlayClick.bind(this)),this.container.appendChild(this.playButton)}handlePlayClick(t){t&&t.stopPropagation();const e=bt();if("autoplayBlocked"===e.currentState)if(this.videoManager){this.videoManager.markUserInteraction(),this.videoManager.setMuted(!1);const t=this.videoManager.getVideoElement();t&&(t.loop=!1,t.currentTime=0)}else{const t=this.playButton.closest(".sf-player");if(t){const e=t.querySelector(".sf-video-container__video");e&&(e.muted=!1,e.loop=!1,e.currentTime=0)}}else this.videoManager?this.videoManager.markUserInteraction():console.warn("PlayPauseButton: VideoManager not available, falling back to store play");"paused"!==e.currentState&&"waitingForInteraction"!==e.currentState&&"autoplayBlocked"!==e.currentState||e.play()}destroy(){this.playButton.removeEventListener("click",this.handlePlayClick.bind(this)),this.playButton.remove()}}class Ie{constructor(t){e(this,"button"),e(this,"playerElement"),this.playerElement=t,this.button=document.createElement("button"),this.button.className="sf-player__exit-button",this.button.innerHTML='\n <svg width="18" height="18" viewBox="0 0 256 256" fill="currentColor" xmlns="http://www.w3.org/2000/svg">\n <path d="M205.66,194.34a8,8,0,0,1-11.32,11.32L128,139.31,61.66,205.66a8,8,0,0,1-11.32-11.32L116.69,128,50.34,61.66A8,8,0,0,1,61.66,50.34L128,116.69l66.34-66.35a8,8,0,0,1,11.32,11.32L139.31,128Z"></path>\n </svg>\n ',this.button.addEventListener("click",this.handleClick.bind(this)),this.playerElement.appendChild(this.button),this.updateVisibility(bt().isMinimized)}handleClick(t){t.stopPropagation();bt().sendStateMachineEvent({type:"EXIT"})}updateVisibility(t){t?this.button.classList.remove("sf-hidden"):this.button.classList.add("sf-hidden")}destroy(){this.button.removeEventListener("click",this.handleClick.bind(this)),this.button.remove()}}class Pe{constructor(t,n={}){e(this,"errorOverlay"),e(this,"container"),e(this,"options"),e(this,"isVisible",!1),this.container=t,this.options=n,this.createErrorDisplay()}createErrorDisplay(){this.errorOverlay=document.createElement("div"),this.errorOverlay.className=ct,this.errorOverlay.classList.add("sf-hidden");const t=document.createElement("div");t.className=ht;const e=document.createElement("p");e.className=ut,e.textContent=this.options.message||"Unable to load content",t.appendChild(e),this.errorOverlay.appendChild(t),this.container.appendChild(this.errorOverlay)}show(t){t&&this.updateOptions(t),this.errorOverlay.classList.remove("sf-hidden"),this.isVisible=!0,requestAnimationFrame((()=>{this.errorOverlay.classList.add(dt)}))}hide(){this.isVisible&&(this.errorOverlay.classList.remove(dt),setTimeout((()=>{this.errorOverlay.classList.add("sf-hidden"),this.isVisible=!1}),300))}updateOptions(t){if(this.options={...this.options,...t},void 0!==t.message){const e=this.errorOverlay.querySelector(`.${ut}`);e&&(e.textContent=t.message||"Unable to load content")}}static getErrorMessage(t,e){const n=(t instanceof Error?t.message:t).toLowerCase();return"video"===e||n.includes("video")||n.includes("cannot load video")?n.includes("no video url")||n.includes("video url provided")?"This step doesn't have a video to play":"Unable to load video content":"network"===e||n.includes("network")||n.includes("fetch")?"Connection issue detected":"playlist"===e||n.includes("playlist")?"Unable to load playlist":"initialization"===e||n.includes("token")||n.includes("initialize")?"Setup issue detected":"Unable to load content"}isShowing(){return this.isVisible}destroy(){this.errorOverlay&&this.errorOverlay.remove()}}class Ce{constructor(t){e(this,"container"),e(this,"spinnerElement",null),this.container=t}show(){this.spinnerElement?this.spinnerElement.classList.remove("sf-hidden"):(this.spinnerElement=document.createElement("div"),this.spinnerElement.className=`${pt}`,this.spinnerElement.innerHTML='\n <div class="sf-loading-spinner__content">\n <div class="sf-loading-spinner__icon">\n <svg width="60" height="60" viewBox="0 0 60 60" fill="none" xmlns="http://www.w3.org/2000/svg">\n \x3c!-- Static Saltfish logo in center --\x3e\n <g transform="translate(10, 10) scale(0.656)">\n <g clip-path="url(#saltfish-clip)">\n <path d="M61.0002 30.1906C61.0002 46.8644 47.4834 60.3812 30.8097 60.3812C14.136 60.3812 27.1659 46.8644 27.1659 30.1906C27.1659 13.5168 14.136 0 30.8097 0C47.4834 0 61.0002 13.5168 61.0002 30.1906Z" fill="black" fill-opacity="0.9"/>\n <path d="M24.13 29.8618C24.13 40.3565 15.6978 48.8642 5.29602 48.8642C-5.10576 48.8642 3.02294 40.3565 3.02294 29.8618C3.02294 19.3671 -5.10576 10.8594 5.29602 10.8594C15.6978 10.8594 24.13 19.3671 24.13 29.8618Z" fill="black" fill-opacity="0.9"/>\n </g>\n <defs>\n <clipPath id="saltfish-clip">\n <rect width="61" height="61" fill="white"/>\n </clipPath>\n </defs>\n </g>\n \n \x3c!-- Animated circular ring around logo --\x3e\n <circle cx="30" cy="30" r="28" \n stroke="black" stroke-width="2" \n fill="none" stroke-linecap="round"\n stroke-dasharray="8 6" stroke-opacity="0.3">\n <animateTransform attributeName="transform" \n type="rotate" \n values="0 30 30;360 30 30" \n dur="2s" \n repeatCount="indefinite"/>\n </circle>\n </svg>\n </div>\n <div class="sf-loading-spinner__text">Loading playlist...</div>\n </div>\n ',this.container.appendChild(this.spinnerElement))}hide(){this.spinnerElement&&this.spinnerElement.classList.add("sf-hidden")}updateMessage(t){if(this.spinnerElement){const e=this.spinnerElement.querySelector(".sf-loading-spinner__text");e&&(e.textContent=t)}}destroy(){this.spinnerElement&&(this.spinnerElement.remove(),this.spinnerElement=null)}}class _e{constructor(t){e(this,"shadowDOMManager"),e(this,"playerRoot",null),e(this,"playerElement",null),e(this,"minimizeButton",null),e(this,"exitButton",null),e(this,"playPauseButton",null),e(this,"errorDisplay",null),e(this,"loadingSpinner",null),e(this,"compactLabel",null),e(this,"playbackButtonsVisible",!1),e(this,"playButton",null),e(this,"centerPlayButton",null),e(this,"videoManager",null),e(this,"storeUnsubscribe",null),this.shadowDOMManager=t}createPlayerUI(t,e,n){if(this.videoManager=t,this.playerElement&&this.reset(),!this.playerRoot&&(this.shadowDOMManager.create(),this.playerRoot=this.shadowDOMManager.getRootElement(),!this.playerRoot))return void console.error("Failed to create player root element");this.playerElement=this.createPlayerElement(this.playerRoot),this.minimizeButton=new xe(this.playerElement),this.exitButton=new Ie(this.playerElement),t.create(this.playerElement);const i=this.createControlsContainer(this.playerElement);this.playPauseButton=new Me(i,t),this.createSaltfishLogo(this.playerElement),this.setupVideoContainerClickHandler(),e.create(),n.create(this.playerElement),this.initializeButtonManagement();const s=bt();this.handleMinimizeStateChange(s.isMinimized)}setupVideoContainerClickHandler(){var t;const e=null==(t=this.playerElement)?void 0:t.querySelector(".sf-video-container");e&&e.addEventListener("click",(t=>{var e;const n=bt();if(n.isMinimized)return t.stopPropagation(),void this.handleMinimizeClick();const i=t.target;if("BUTTON"===i.tagName||i.closest("button")||i.closest(".sf-controls-container"))return;const s=null==(e=this.playerElement)?void 0:e.classList.contains("sf-player--compact");"playing"===n.currentState?n.pause():!s||"idleMode"!==n.currentState&&"autoplayBlocked"!==n.currentState&&"paused"!==n.currentState||(this.handleAutoplayFallbackInteraction("compact bubble click"),n.play())}))}updatePosition(){var t;if(!this.playerRoot||!this.playerElement)return void console.warn("UIManager: updatePosition called but playerRoot or playerElement is null",{playerRoot:!!this.playerRoot,playerElement:!!this.playerElement});const e=bt();let n=(null==(t=e.playlistOptions)?void 0:t.position)||"bottom-right";if(e.currentStepId&&e.manifest){const t=e.manifest.steps.find((t=>t.id===e.currentStepId));(null==t?void 0:t.position)&&(n=t.position)}"bottom-left"!==n&&"bottom-right"!==n&&(console.warn(`UIManager: Invalid position "${n}", defaulting to bottom-right`),n="bottom-right"),this.playerRoot.classList.remove("sf-player-root--bottom-left","sf-player-root--bottom-right"),"bottom-left"===n?this.playerRoot.classList.add("sf-player-root--bottom-left"):this.playerRoot.classList.add("sf-player-root--bottom-right"),e.isMinimized?this.playerElement.classList.add(at):this.playerElement.classList.remove(at)}handleMinimizeClick(){if(!this.playerElement)return;const t=bt(),e=!t.isMinimized;e?t.minimize():t.maximize(),e?this.minimizeButton.minimize():this.minimizeButton.maximize()}handleMinimizeStateChange(t){this.exitButton&&this.exitButton.updateVisibility(t),this.minimizeButton&&this.minimizeButton.updateVisibility(t)}getPlayerElement(){return this.playerElement}getPlayerRoot(){return this.playerRoot}showError(t,e,n){if(!this.playerElement)return void console.warn("UIManager: Cannot show error display - player element not available");const i=Pe.getErrorMessage(t,e);this.errorDisplay||(this.errorDisplay=new Pe(this.playerElement,{message:i,...n})),this.errorDisplay.show({message:i,...n})}hideError(){this.errorDisplay&&this.errorDisplay.hide()}isErrorDisplayVisible(){var t;return(null==(t=this.errorDisplay)?void 0:t.isShowing())||!1}showLoading(t){this.playerElement?(this.loadingSpinner||(this.loadingSpinner=new Ce(this.playerElement)),this.loadingSpinner.show(),t&&this.loadingSpinner.updateMessage(t)):console.warn("UIManager: Cannot show loading spinner - player element not available")}hideLoading(){this.loadingSpinner&&this.loadingSpinner.hide()}updateLoadingMessage(t){this.loadingSpinner&&this.loadingSpinner.updateMessage(t)}showPlayer(){this.playerElement&&this.playerElement.classList.add("sf-player--visible")}createPlayerElement(t){const e=document.createElement("div");return e.className=rt,t.appendChild(e),e}createControlsContainer(t){const e=document.createElement("div");return e.className=ot,t.appendChild(e),e}createSaltfishLogo(t){var e;if(!1===(null==(e=bt().config)?void 0:e.showLogo))return;const n=document.createElement("div");n.className=lt,n.innerHTML='\n <svg viewBox="0 0 41 15" fill="none" xmlns="http://www.w3.org/2000/svg">\n <path d="M8.42034 7.49991C8.42034 9.67502 6.65707 11.4383 4.48196 11.4383C2.30685 11.4383 4.00664 9.67502 4.00664 7.49991C4.00664 5.3248 2.30685 3.56152 4.48196 3.56152C6.65707 3.56152 8.42034 5.3248 8.42034 7.49991Z" fill="white"/>\n <path d="M3.53097 7.43198C3.53097 8.96956 2.29707 10.216 0.774969 10.216C-0.747128 10.216 0.442349 8.96956 0.442349 7.43198C0.442349 5.8944 -0.747128 4.64795 0.774969 4.64795C2.29707 4.64795 3.53097 5.8944 3.53097 7.43198Z" fill="white"/>\n <path d="M15.0603 10.628C13.8603 10.628 12.9803 9.892 12.9803 8.372L13.6043 8.292C13.6043 9.492 14.1803 10.044 15.0603 10.044C15.8603 10.044 16.3243 9.612 16.3243 8.972C16.3243 8.252 15.8363 7.988 15.0603 7.788C13.7003 7.436 13.2523 6.996 13.2523 6.196C13.2523 5.396 13.9403 4.772 14.9803 4.772C16.0203 4.772 16.6923 5.396 16.6923 6.436L16.0683 6.516C16.0683 5.796 15.6203 5.356 14.9803 5.356C14.3403 5.356 13.8763 5.636 13.8763 6.196C13.8763 6.756 14.2843 7.004 15.0603 7.204C16.3723 7.548 16.9483 8.012 16.9483 8.972C16.9483 9.932 16.2603 10.628 15.0603 10.628ZM19.182 10.628C18.542 10.628 17.83 10.228 17.83 9.428C17.83 8.548 18.462 8.212 19.494 8.076C19.966 8.012 20.638 7.956 20.414 7.38C20.27 7.004 19.734 6.956 19.494 6.956C18.854 6.956 18.534 7.236 18.534 7.716L17.91 7.636C17.91 6.756 18.774 6.372 19.494 6.372C20.214 6.372 21.022 6.692 21.022 7.652V10.5H20.438V9.7C20.262 10.22 19.798 10.628 19.182 10.628ZM18.454 9.46C18.454 9.78 18.782 10.044 19.182 10.044C19.822 10.044 20.438 9.596 20.438 8.476V8.26C20.286 8.476 19.91 8.596 19.374 8.66C18.742 8.748 18.454 9.06 18.454 9.46ZM22.3044 10.5V4.82H22.9284V10.5H22.3044ZM25.6789 10.5C24.9909 10.5 24.6469 10.204 24.6469 9.508V7.084H23.9669V6.5H24.6469V5.292L25.1909 5.212V6.5H26.2309V7.084H25.1909V9.34C25.1909 9.836 25.3829 9.916 25.7749 9.916H26.2309V10.5H25.6789ZM27.7094 6.052C27.7094 5.116 28.0934 4.82 28.7814 4.82H29.3334V5.404H28.8774C28.4454 5.404 28.2934 5.484 28.2934 6.22V6.5H29.3334V7.084H28.2934V10.5H27.7094V7.084H27.0294V6.5H27.7094V6.052ZM30.2805 10.5V6.5H30.9045V10.5H30.2805ZM30.2165 5.86V5.108H30.9685V5.86H30.2165ZM33.7678 10.628C32.8078 10.628 32.0078 10.06 32.0078 9.02L32.5918 8.94C32.5918 9.66 33.2078 10.044 33.7678 10.044C34.3278 10.044 34.7678 9.86 34.7678 9.38C34.7678 8.9 34.4558 8.772 33.9998 8.708L33.2958 8.612C32.6638 8.524 32.2318 8.092 32.2318 7.532C32.2318 6.812 32.8478 6.372 33.7278 6.372C34.6078 6.372 35.1678 6.892 35.1678 7.612L34.5838 7.692C34.5838 7.212 34.2878 6.956 33.7278 6.956C33.2478 6.956 32.8558 7.132 32.8558 7.532C32.8558 7.852 33.0718 7.996 33.5438 8.068L34.1518 8.156C34.8558 8.26 35.3918 8.66 35.3918 9.38C35.3918 10.1 34.7278 10.628 33.7678 10.628ZM38.9252 7.868C38.9252 7.148 38.5812 6.956 38.1012 6.956C37.6212 6.956 36.9812 7.276 36.9812 8.636V10.5H36.3572V4.9H36.9812V7.364C37.1092 6.812 37.5652 6.372 38.3012 6.372C39.1812 6.372 39.5492 6.988 39.5492 7.868V10.5H38.9252V7.868Z" fill="white"/>\n </svg>\n ',t.appendChild(n),n.addEventListener("click",(t=>{var e;t.stopPropagation();const n=bt();"playing"===n.currentState&&n.pause();const i=null==(e=n.config)?void 0:e.token;i?window.open(`https://www.saltfish.ai/demos?clientId=${i}`,"_blank"):(console.warn("UIManager: No token available, falling back to saltfish.ai homepage"),window.open("https://www.saltfish.ai/","_blank"))}))}initializeButtonManagement(){this.playerElement&&this.videoManager?(this.storeUnsubscribe=vt.subscribe((t=>{this.updatePlayPauseButton(t.currentState)})),this.playButton=this.playerElement.querySelector(".sf-controls-container__play-button"),this.centerPlayButton=this.playerElement.querySelector(".sf-player__center-play-button"),this.centerPlayButton||this.createCenterPlayButton(),this.playButton||console.error("UIManager: Failed to find play button during initialization"),this.centerPlayButton):console.error("UIManager: Cannot initialize button management - missing player element or video manager")}displayPlaybackButtons(t){this.playbackButtonsVisible!==t&&(this.playbackButtonsVisible=t)}updatePlayPauseButton(t){this.playButton&&this.playButton.classList.add("sf-hidden"),!this.centerPlayButton&&this.playerElement&&(this.centerPlayButton=this.playerElement.querySelector(".sf-player__center-play-button"),this.centerPlayButton||this.createCenterPlayButton()),this.centerPlayButton&&("playing"===t||"completed"===t?(this.centerPlayButton.classList.remove("sf-player__center-play-button--visible"),this.centerPlayButton.classList.remove("sf-player__center-play-button--prominent")):(this.centerPlayButton.classList.add("sf-player__center-play-button--visible"),"autoplayBlocked"===t||"idleMode"===t?this.centerPlayButton.classList.add("sf-player__center-play-button--prominent"):this.centerPlayButton.classList.remove("sf-player__center-play-button--prominent")))}handleAutoplayFallbackInteraction(t){var e;const n=bt();if("autoplayBlocked"===n.currentState||"idleMode"===n.currentState)if(n.currentState,this.videoManager){this.videoManager.markUserInteraction(),this.videoManager.setMuted(!1);const t=this.videoManager.getVideoElement();t&&(t.loop=!1,t.currentTime=0)}else{const t=null==(e=this.playerElement)?void 0:e.querySelector(".sf-video-container__video");t&&(t.muted=!1,t.loop=!1,t.currentTime=0)}else this.videoManager&&this.videoManager.markUserInteraction()}createCenterPlayButton(){this.playerElement&&(this.centerPlayButton=document.createElement("button"),this.centerPlayButton.className="sf-player__center-play-button",this.centerPlayButton.innerHTML='\n <svg class="sf-player__center-play-button__play-icon" width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">\n <path d="M8 5v14l11-7z" fill="currentColor"/>\n </svg>\n <svg class="sf-player__center-play-button__pause-icon" width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">\n <path d="M6 4h4v16H6V4zm8 0h4v16h-4V4z" fill="currentColor"/>\n </svg>\n <svg class="sf-player__center-play-button__replay-icon" width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">\n <path d="M12 5V1L7 6l5 5V7c3.31 0 6 2.69 6 6s-2.69 6-6 6-6-2.69-6-6H4c0 4.42 3.58 8 8 8s8-3.58 8-8-3.58-8-8-8z" fill="currentColor"/>\n </svg>\n ',this.playerElement.appendChild(this.centerPlayButton),this.centerPlayButton.addEventListener("click",(t=>{t.stopPropagation(),t.preventDefault();const e=bt();this.handleAutoplayFallbackInteraction("center play button"),"paused"===e.currentState||"waitingForInteraction"===e.currentState||"completedWaitingForInteraction"===e.currentState||"autoplayBlocked"===e.currentState||"idleMode"===e.currentState||"error"===e.currentState?e.play():"playing"===e.currentState&&e.pause()})))}showCompactLabel(t){var e;if(!this.playerRoot||!t)return;this.hideCompactLabel();const n=bt();let i=(null==(e=n.playlistOptions)?void 0:e.position)||"bottom-right";if(n.currentStepId&&n.manifest){const t=n.manifest.steps.find((t=>t.id===n.currentStepId));(null==t?void 0:t.position)&&(i=t.position)}const s="bottom-right"===i?"sf-compact-label--left":"sf-compact-label--right";this.compactLabel=document.createElement("div"),this.compactLabel.className=`sf-compact-label ${s}`,this.compactLabel.textContent=t,this.compactLabel.style.cursor="pointer",this.compactLabel.style.pointerEvents="auto",this.compactLabel.addEventListener("click",(t=>{t.stopPropagation(),t.preventDefault();const e=bt();this.handleAutoplayFallbackInteraction("compact label"),"paused"!==e.currentState&&"waitingForInteraction"!==e.currentState&&"completedWaitingForInteraction"!==e.currentState&&"autoplayBlocked"!==e.currentState&&"idleMode"!==e.currentState&&"error"!==e.currentState||e.play()})),this.playerRoot.appendChild(this.compactLabel)}hideCompactLabel(){this.compactLabel&&this.compactLabel.parentNode&&(this.compactLabel.parentNode.removeChild(this.compactLabel),this.compactLabel=null)}reset(){this.minimizeButton&&(this.minimizeButton.destroy(),this.minimizeButton=null),this.exitButton&&(this.exitButton.destroy(),this.exitButton=null),this.playPauseButton&&(this.playPauseButton.destroy(),this.playPauseButton=null),this.errorDisplay&&(this.errorDisplay.destroy(),this.errorDisplay=null),this.loadingSpinner&&(this.loadingSpinner.destroy(),this.loadingSpinner=null),this.hideCompactLabel(),this.playerElement&&this.playerElement.parentNode&&this.playerElement.parentNode.removeChild(this.playerElement),this.playerRoot=null,this.playerElement=null}enablePlayButtonProminent(){this.centerPlayButton&&this.centerPlayButton.classList.add("sf-player__center-play-button--prominent")}disablePlayButtonProminent(){this.centerPlayButton&&this.centerPlayButton.classList.remove("sf-player__center-play-button--prominent")}destroy(){this.minimizeButton&&(this.minimizeButton.destroy(),this.minimizeButton=null),this.exitButton&&(this.exitButton.destroy(),this.exitButton=null),this.playPauseButton&&(this.playPauseButton.destroy(),this.playPauseButton=null),this.errorDisplay&&(this.errorDisplay.destroy(),this.errorDisplay=null),this.loadingSpinner&&(this.loadingSpinner.destroy(),this.loadingSpinner=null),this.storeUnsubscribe&&(this.storeUnsubscribe(),this.storeUnsubscribe=null),this.playbackButtonsVisible=!1,this.playButton=null,this.centerPlayButton=null,this.videoManager=null,this.shadowDOMManager.remove(),this.playerRoot=null,this.playerElement=null}}const ke=class t{constructor(t){e(this,"currentStepId",null),e(this,"stepTimeoutId",null),e(this,"destroyCallback",null),this.destroyCallback=t}update(t){const{currentStepId:e,currentState:n}=t;this.currentStepId;if(!("playing"===n||"waitingForInteraction"===n||"paused"===n||"autoplayBlocked"===n))return this.stepTimeoutId,void this.clearStepTimeout();const i=e!==this.currentStepId,s=null===this.stepTimeoutId;(i||s)&&(i&&this.currentStepId,this.setStepTimeout(e))}setStepTimeout(e){this.clearStepTimeout(),e&&(this.currentStepId=e,this.stepTimeoutId=window.setTimeout((()=>{this.destroyPlayer()}),t.STEP_TIMEOUT_MS))}clearStepTimeout(){null!==this.stepTimeoutId&&(this.currentStepId,window.clearTimeout(this.stepTimeoutId),this.stepTimeoutId=null)}setDestroyCallback(t){this.destroyCallback=t}destroyPlayer(){if(this.destroyCallback)try{this.destroyCallback()}catch(t){}}reset(){this.clearStepTimeout(),this.currentStepId=null}destroy(){this.clearStepTimeout(),this.currentStepId=null,this.destroyCallback=null}};e(ke,"STEP_TIMEOUT_MS",Pt);let Te=ke;class Ae{createManagers(){const t=gt.getInstance(),e=new fe(t),n=new Yt,i=new te,s=new we,r=new ge(s),a=new Ee(s,t),o=new be(s),l=new de,c=new pe,d=new ye,h=new ve,u=new Te((()=>{}));d.setTriggerManager(h);return{shadowDOMManager:n,videoManager:i,cursorManager:l,interactionManager:c,analyticsManager:r,sessionManager:e,transitionManager:d,triggerManager:h,abTestManager:o,eventManager:s,playlistManager:a,stepTimeoutManager:u,uiManager:new _e(n),storageManager:t}}resetManagers(t){try{t.videoManager.reset&&t.videoManager.reset(),t.cursorManager.reset&&t.cursorManager.reset(),t.interactionManager.reset&&t.interactionManager.reset(),t.transitionManager.reset&&t.transitionManager.reset(),t.uiManager.reset&&t.uiManager.reset(),t.stepTimeoutManager.reset&&t.stepTimeoutManager.reset()}catch(e){console.error("ManagerFactory: Error resetting managers:",e)}}destroyManagers(t){try{t.transitionManager.destroy(),t.triggerManager.destroy(),t.videoManager.destroy(),t.cursorManager.destroy(),t.interactionManager.destroy(),t.analyticsManager.destroy(),t.sessionManager.destroy(),t.playlistManager.destroy(),t.stepTimeoutManager.destroy(),t.uiManager.destroy()}catch(e){console.error("ManagerFactory: Error destroying managers:",e)}}}const ze=class t{constructor(){if(e(this,"playerInitializationService"),e(this,"userManagementService"),e(this,"playlistOrchestrator"),e(this,"stateMachineActionHandler"),e(this,"managerOrchestrator"),e(this,"managerFactory"),e(this,"isInitialized",!1),t.instance)throw new Error("SaltfishPlayer is a singleton. Use getInstance()");this.managerFactory=new Ae;const n=this.managerFactory.createManagers();this.playerInitializationService=new Lt(n),this.userManagementService=new Ot(n),this.playlistOrchestrator=new Ft(n),this.stateMachineActionHandler=new Ut(n),this.managerOrchestrator=new $t(n),this.userManagementService.setPlayerInitializationService(this.playerInitializationService),this.playerInitializationService.setUserManagementService(this.userManagementService),this.playerInitializationService.setPlaylistOrchestrator(this.playlistOrchestrator),this.playlistOrchestrator.setUserManagementService(this.userManagementService),this.playlistOrchestrator.setManagerOrchestrator(this.managerOrchestrator),this.playlistOrchestrator.setPlayerInitializationService(this.playerInitializationService),this.playlistOrchestrator.setStateMachineActionHandler(this.stateMachineActionHandler),this.stateMachineActionHandler.setDestroyCallback((()=>this.destroy())),n.stepTimeoutManager.setDestroyCallback((()=>this.destroy())),vt.subscribe((()=>this.managerOrchestrator.handleStoreChanges())),this.stateMachineActionHandler.registerStateMachineActions()}static getInstance(){return t.instance||(t.instance=new t),t.instance}getSessionId(){return this.managerOrchestrator.getManagers().sessionManager.getSessionId()}getRunId(){return this.managerOrchestrator.getManagers().sessionManager.getCurrentRunId()}async initialize(t){if(this.isInitialized)console.warn("Saltfish playlist Player is already initialized");else try{await this.playerInitializationService.initialize(t),this.isInitialized=!0,this.managerOrchestrator.setInitialized(!0),"undefined"!=typeof window&&(window._saltfishPlayer=this,window._cursorManager=this.getManagers().cursorManager)}catch(e){throw e}}identifyUser(t,e){this.userManagementService.identifyUser(t,e)}async identifyAnonymous(t){await this.userManagementService.identifyAnonymous(t)}async startPlaylist(t,e){await this.playlistOrchestrator.startPlaylist(t,e)}resetPlaylist(){this.playlistOrchestrator.resetPlaylist()}destroy(){if(this.isInitialized)try{this.managerOrchestrator.destroyAll(),this.isInitialized=!1}catch(t){console.error("SaltfishPlayer: Error during destruction:",t),this.isInitialized=!1}else console.warn("Saltfish playlist Player is not initialized")}on(t,e){this.managerOrchestrator.getManagers().eventManager.on(t,e)}off(t,e){return this.managerOrchestrator.getManagers().eventManager.off(t,e)}get videoManager(){return this.managerOrchestrator.getManagers().videoManager}getManagers(){return this.managerOrchestrator.getManagers()}getServices(){return{playerInitializationService:this.playerInitializationService,userManagementService:this.userManagementService,playlistOrchestrator:this.playlistOrchestrator,stateMachineActionHandler:this.stateMachineActionHandler,managerOrchestrator:this.managerOrchestrator}}};e(ze,"instance",null);let Le=ze;const Ve=Object.freeze(Object.defineProperty({__proto__:null,SaltfishPlayer:Le},Symbol.toStringTag,{value:"Module"})),Oe="0.3.67";const De=function(){const t=Le.getInstance();let e=!1,n=!1,i=null;const s=[],r={init:r=>{if(n)return q("Saltfish already initialized"),Promise.resolve();if(e&&i)return i;const a={enableAnalytics:!0,..."string"==typeof r?{token:r}:r};return q(`Saltfish initialized: analytics=${a.enableAnalytics}`),e=!0,i=t.initialize(a).then((()=>(n=!0,e=!1,(async()=>{if(0!==s.length)for(;s.length>0;){const e=s.shift();if(e)try{await e()}catch(t){G("Error executing queued command:",t)}}})()))).catch((t=>{throw e=!1,t("Saltfish initialization failed:",t),t})),i},identify:(i,r)=>{n||!e?t.identifyUser(i,r):s.push((async()=>{t.identifyUser(i,r)}))},identifyAnonymous:i=>{n||!e?t.identifyAnonymous(i):s.push((async()=>{t.identifyAnonymous(i)}))},startPlaylist:(r,a)=>!n&&e?new Promise(((e,n)=>{s.push((async()=>{try{await t.startPlaylist(r,a),e()}catch(i){n(i)}})),i&&i.catch(n)})):t.startPlaylist(r,a),on:(e,n)=>{t.on(e,n)},off:(e,n)=>t.off(e,n),resetPlaylist:()=>{n||e?n||!e?t.resetPlaylist():s.push((async()=>{t.resetPlaylist()})):Z("Cannot reset playlist - Saltfish not initialized")},destroy:()=>{n||e?(e||(n=!1,e=!1,i=null,s.length=0),t.destroy(),n=!1,e=!1,i=null):Z("Cannot destroy - Saltfish not initialized")},getSessionId:()=>t.getSessionId(),getRunId:()=>t.getRunId(),version:()=>Oe};return r.__dev__={getDeviceInfo:()=>Xt.getDeviceInfo()},r}();if("undefined"!=typeof window&&"undefined"!=typeof document&&!document.querySelector('meta[name="saltfish-player-loaded"]')){const t=document.createElement("meta");t.name="saltfish-player-loaded",t.content="true",document.head.appendChild(t)}return"undefined"!=typeof window&&(window.saltfish=De),De}));
|
|
8
8
|
|