saltfish 0.3.91 → 0.3.93
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/managers/TriggerManager.d.ts +12 -2
- package/dist/managers/TriggerManager.d.ts.map +1 -1
- package/dist/managers/UIManager.d.ts +7 -0
- package/dist/managers/UIManager.d.ts.map +1 -1
- package/dist/player.js +2 -2
- package/dist/player.min.js +2 -2
- package/dist/saltfish-playlist-player.es.js +77 -9
- package/dist/saltfish-playlist-player.umd.js +1 -1
- package/dist/types/index.d.ts +4 -0
- package/dist/types/index.d.ts.map +1 -1
- package/package.json +1 -1
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.93
|
|
4
4
|
* (c) 2026
|
|
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===g(t)?Reflect.ownKeys(t).forEach((n=>{e(n,t[n],t)})):t.forEach(((n,i)=>e(i,n,t)))}function g(t){const e=t[a];return e?e.type_:Array.isArray(t)?1:y(t)?2:v(t)?3:0}function m(t,e){return 2===g(t)?t.has(e):Object.prototype.hasOwnProperty.call(t,e)}function f(t,e,n){const i=g(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 M(t)||c(t)||!d(t)||(g(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 M(t){return Object.isFrozen(t)}var x,I={};function P(t){const e=I[t];return e||o(0),e}function C(){return x}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===x&&(x=t.parent_)}function A(t){return x={drafts_:[],parent_:x,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(M(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_&&!m(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)&&!M(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(!m(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===B(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=B(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||m(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!==B(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)}},U={};function B(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)=>{U[t]=function(){return arguments[0]=arguments[0][0],e.apply(this,arguments)}})),U.deleteProperty=function(t,e){return U.set.call(this,t,e,void 0)},U.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=U);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)||M(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)))}},j=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 W=t=>(e,n,i)=>(i.setState=(t,n,...i)=>{const s="function"==typeof t?j(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.runEntryActions(this.currentState)}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"}}},loading:{on:{MANIFEST_LOADED:{target:"paused"},ERROR:{target:"error"}},entry:["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"},ERROR:{target:"error"},COMPLETE_PLAYLIST:{target:"completed"},COMPLETE_PLAYLIST_WAITING_FOR_INTERACTION:{target:"completedWaitingForInteraction"}},entry:["startVideoPlayback","showVideoControls","hidePlayButton"],exit:["pauseVideoPlayback"]},paused:{on:{PLAY:{target:"playing"},START_IDLE_MODE:{target:"idleMode"},AUTOPLAY_FALLBACK:{target:"autoplayBlocked"},MINIMIZE:{target:"minimized"},TRANSITION_TO_STEP:{target:"playing"}},entry:["pauseVideoPlayback","showPlayButton"]},minimized:{on:{MAXIMIZE:{target:"playing"},EXIT:{target:"closing"}},entry:["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"}},entry:["showPlayButton"]},autoplayBlocked:{on:{PLAY:{target:"playing"},TRANSITION_TO_STEP:{target:"playing"},MINIMIZE:{target:"minimized"}},entry:["enterCompactMode","startMutedLoopedVideo","hideVideoControls","showPlayButton","enablePlayButtonProminent"],exit:["disablePlayButtonProminent","showVideoControls","exitCompactMode"]},idleMode:{on:{PLAY:{target:"playing"},TRANSITION_TO_STEP:{target:"playing"},MINIMIZE:{target:"minimized"}},entry:["startIdleModeVideo","hideVideoControls","showPlayButton","enablePlayButtonProminent"],exit:["disablePlayButtonProminent","showVideoControls","exitCompactMode"]},error:{on:{INITIALIZE:{target:"idle"},PLAY:{target:"playing"},AUTOPLAY_FALLBACK:{target:"autoplayBlocked"}},entry:["handleError","showPlayButton"],exit:["hideError"]},completedWaitingForInteraction:{on:{COMPLETE_PLAYLIST:{target:"completed"},INITIALIZE:{target:"idle"},TRANSITION_TO_STEP:{target:"playing"},PLAY:{target:"playing"},MINIMIZE:{target:"minimized"}},entry:["showPlayButton"]},completed:{on:{INITIALIZE:{target:"idle"}},entry:["trackPlaylistComplete"]},closing:{on:{},entry:["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",gt=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(gt,"instance",null);let mt=gt;const ft=mt.getInstance(),yt=i(W(((t,e)=>{let n=new K(J,{currentStep:null,error:null});const i=t=>n.send(t),s=e=>{const i=n.send(e);return t((t=>{t.currentState=i})),i};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}))},mergeUserFields:e=>{t((t=>{t.user&&Object.assign(t.user,e)}))},setUserData:e=>{t((t=>{var n;const i=(null==e?void 0:e.watchedPlaylists)||{},s=(null==(n=t.userData)?void 0:n.watchedPlaylists)||{},r={...i};for(const[e,a]of Object.entries(s)){if(!a)continue;const t=r[e],n="completed"===a.status||"dismissed"===a.status,i=!!t&&("completed"===t.status||"dismissed"===t.status);if(n&&!i)r[e]=a,a.status,null==t||t.status;else if(t){const n=Math.max(a.visitCount??0,t.visitCount??0);(t.visitCount??0)!==n&&(r[e]={...t,visitCount:n})}}t.userData={...e,watchedPlaylists:r}}))},updateWatchedPlaylist:(e,n,i)=>{t((t=>{t.userData||(t.userData={watchedPlaylists:{}}),t.userData.watchedPlaylists||(t.userData.watchedPlaylists={});const s=t.userData.watchedPlaylists[e],r=null==s?void 0:s.status,a=(null==s?void 0:s.visitCount)??0,o=("completed"===n||"dismissed"===n)&&r!==n,l=Date.now();t.userData.watchedPlaylists[e]={status:n,currentStepId:"completed"===n?null:i??t.currentStepId??null,timestamp:l,lastProgressAt:l,visitCount:o?a+1:a}}))},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:r}=e();if("completed"!==n){if(r&&r.steps.some((t=>t.id===n))){const e=r.steps.find((t=>t.id===n));t((t=>{var s,a,o;t.currentStepId=n,e&&(t.currentState=i({type:"TRANSITION_TO_STEP",step:e}),(t.position||(null==(s=t.playlistOptions)?void 0:s.position))&&(t.position={x:0,y:0})),t.progress[r.id]={...t.progress[r.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 s({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:()=>{s({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:t=>{s(t)},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 Mt{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 xt=3e4,It=100,Pt=12e4,Ct=500,_t=500,kt=5e3,Tt=18e5,At=6e4,zt=10;function Lt(t){try{let e=t.replace(/[?&]saltfish-share-id=[^&#]*/g,((e,n)=>{if(e.startsWith("?")){return t.substring(n+e.length).startsWith("&")?"?":""}return""}));return e=e.replace(/\?&/g,"?"),e=e.replace(/&&/g,"&"),e=e.replace(/\?$/g,""),e=e.replace(/&$/g,""),e}catch(e){return t}}function Vt(t){const{pattern:e,matchType:n}=t;if(!e)return!0;const i=Lt(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 Ot{constructor(t){e(this,"managers"),e(this,"userManagementService"),e(this,"playlistOrchestrator"),e(this,"shareLinkService"),e(this,"lastConfig",null),e(this,"boundVisibilityHandler",null),e(this,"lastUserDataFetchTimestamp",0),e(this,"currentUserId",null),e(this,"currentUserData"),e(this,"isAnonymousUser",!1),this.managers=t,this.shareLinkService=new Mt}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.3.81"})}),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){this.currentUserId=t,this.currentUserData=e,this.isAnonymousUser=!1,this.lastUserDataFetchTimestamp=Date.now(),r.firstIdentifiedAt&&i.mergeUserFields({firstIdentifiedAt:r.firstIdentifiedAt}),i.setUserData({watchedPlaylists:r.watchedPlaylists||{},language:r.language});const n=r.userListAssignments||{},s=r.abTestAssignments||{};this.managers.abTestManager.assignUserToTests(t,s,n),this.setupVisibilityChangeListener(),this.managers.eventManager.trigger("userDataLoaded",{timestamp:Date.now(),userId:t,userData:{watchedPlaylists:r.watchedPlaylists||{}}}),this.userManagementService&&this.userManagementService.resolveUserDataLoaded();const a=await this.checkAndResumeFromPendingNavigation();if(!(a||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),this.currentUserId=t,this.currentUserData=e,this.isAnonymousUser=!0,this.lastUserDataFetchTimestamp=Date.now();bt().setUserData({watchedPlaylists:s.watchedPlaylists||{},language:null==e?void 0:e.language}),this.setupVisibilityChangeListener(),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=Lt(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}setupVisibilityChangeListener(){"undefined"!=typeof window&&"undefined"!=typeof document&&(this.removeVisibilityChangeListener(),this.boundVisibilityHandler=()=>this.handleVisibilityChange(),document.addEventListener("visibilitychange",this.boundVisibilityHandler))}removeVisibilityChangeListener(){this.boundVisibilityHandler&&"undefined"!=typeof document&&(document.removeEventListener("visibilitychange",this.boundVisibilityHandler),this.boundVisibilityHandler=null)}async handleVisibilityChange(){if("visible"!==document.visibilityState)return;if(!this.currentUserId)return;if(Date.now()-this.lastUserDataFetchTimestamp<5e3)return;const t=bt().currentState;if(!["playing","paused","loading","waitingForInteraction","autoplayBlocked","minimized","idleMode"].includes(t))try{this.isAnonymousUser?await this.refreshAnonymousUserData():await this.refreshIdentifiedUserData()}catch(e){}}async refreshIdentifiedUserData(){var t;const e=bt();if((null==(t=e.config)?void 0:t.token)&&this.currentUserId){this.currentUserId;try{const t=await fetch(`https://player.saltfish.ai/clients/${e.config.token}/users/${this.currentUserId}`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({userData:this.currentUserData})});if(!t.ok)return;const n=await t.json();if(n.success){this.lastUserDataFetchTimestamp=Date.now(),n.firstIdentifiedAt&&e.mergeUserFields({firstIdentifiedAt:n.firstIdentifiedAt}),e.setUserData({watchedPlaylists:n.watchedPlaylists||{},language:n.language});const t=n.userListAssignments||{},i=n.abTestAssignments||{};this.managers.abTestManager.assignUserToTests(this.currentUserId,i,t),this.managers.triggerManager.evaluateAllTriggers()}}catch(n){}}}async refreshAnonymousUserData(){var t;if(!this.currentUserId)return;this.currentUserId,this.lastUserDataFetchTimestamp=Date.now();const e=this.managers.storageManager.getAnonymousUserData();if(e){bt().setUserData({watchedPlaylists:e.watchedPlaylists||{},language:null==(t=this.currentUserData)?void 0:t.language}),this.managers.triggerManager.evaluateAllTriggers()}}destroy(){this.removeVisibilityChangeListener(),this.lastConfig=null,this.currentUserId=null,this.currentUserData=void 0,this.lastUserDataFetchTimestamp=0,this.isAnonymousUser=!1}}function Dt(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 Ft{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=Dt(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=Dt(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 Ut{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((()=>qt));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 Bt{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),!0!==(null==e?void 0:e._startedFromShareLink)){if(!this.managers.abTestManager.isPlaylistAvailable(t))return}else null==e||e._startedFromShareLink;const h=new Ut,u=await h.validatePlaylistStart({playlistId:t,options:e,eventManager:this.managers.eventManager});if(!u.isValid)return;e=u.updatedOptions||e;const p=u.manifestPath,g=e||{};g?(c.setPlaylistOptions(g),g.position||c.setPlaylistOptions({...g,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 m=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.cursorManager.resetFirstAnimation(),await this.managers.playlistManager.load(p,{...g,persistence:m});const f=bt();if(f.manifest){const t=g.persistence??f.manifest.isPersistent??!0,e=f.playlistOptions||{};f.setPlaylistOptions({...e,...g,persistence:t})}if(g.startNodeId&&f.manifest){f.manifest.steps.find((t=>t.id===g.startNodeId))?f.goToStep(g.startNodeId):console.warn(`[PlaylistOrchestrator] startNodeId '${g.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);g._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(){}}class Nt{constructor(t,n){e(this,"listener",null),e(this,"videoElement",null),e(this,"stepId",null),this.managers=t,this.logPrefix=n}cleanup(t){if(t&&this.stepId&&t!==this.stepId)return this.logPrefix,void this.stepId;this.listener&&this.videoElement&&(this.videoElement.removeEventListener("timeupdate",this.listener),this.listener=null,this.videoElement=null,this.stepId=null)}schedule(t,e){this.cleanup();let n=t.showAtSeconds??0;if("number"==typeof n&&isFinite(n)||(this.logPrefix,n=0),n<0&&(this.logPrefix,n=0),n<=0)return this.logPrefix,void this.managers.cursorManager.animate(t);this.logPrefix;const i=this.managers.videoManager.getVideoElement();if(!i)return void this.logPrefix;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 this.logPrefix,r=!0,s=!0,this.cleanup(),void this.managers.cursorManager.animate(t);e>=n&&(s=!0,this.logPrefix,this.cleanup(),this.managers.cursorManager.animate(t))};this.listener=()=>{a()},this.videoElement=i,this.stepId=e,i.addEventListener("timeupdate",this.listener),i.addEventListener("ended",(()=>{if(s)return;const n=bt();if(n.currentStepId!==e)return this.logPrefix,n.currentStepId,void this.cleanup(e);i.duration;this.logPrefix,s=!0,this.managers.cursorManager.animate(t),this.cleanup()}),{once:!0})}}class Rt{constructor(t){e(this,"managers"),e(this,"destroyCallback",null),e(this,"cursorScheduler"),this.managers=t,this.cursorScheduler=new Nt(t,"StateMachineActionHandler")}setDestroyCallback(t){this.destroyCallback=t}registerStateMachineActions(){bt().registerStateMachineActions({startVideoPlayback:t=>this.handleStartVideoPlayback(t),startIdleModeVideo:t=>this.handleStartIdleModeVideo(t),handleError:t=>this.handleError(t),pauseVideoPlayback:()=>this.handlePauseVideoPlayback(),startMutedLoopedVideo:()=>this.handleStartMutedLoopedVideo(),trackPlaylistComplete:()=>this.handleTrackPlaylistComplete(),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.cursorScheduler.cleanup()}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(Vt(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);this.showOrHideAudioOverlay(e,i);try{this.managers.interactionManager.clearButtons(),e.buttons&&this.managers.interactionManager.createButtons(e.buttons);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));t&&this.managers.transitionManager.setupTransitions(e,!1,!0),this.managers.videoManager.setCompletionPolicy(t?"manual":"auto",(()=>this.handleStepVideoEnded(e,t))),this.managers.videoManager.loadVideo(n).then((()=>this.handleStepVideoLoaded(e,i))).catch((t=>this.handleStepVideoLoadError(t,e)))}catch(s){}}showOrHideAudioOverlay(t,e){if(e){const e=bt().manifest;this.managers.videoManager.showAudioFallbackOverlay(t.gifUrl,null==e?void 0:e.avatarThumbnailUrl)}else this.managers.videoManager.hideAudioFallbackOverlay()}handleStepVideoEnded(t,e){var n;const i=bt();if(!e){const e=t.transitions.find((t=>"timeout"===t.type));e&&e.timeout&&e.timeout>0?(e.timeout,this.managers.transitionManager.setupTransitions(t,!1)):this.managers.transitionManager.setupTransitions(t,!0);return void(t.transitions.some((t=>i.manifest.steps.some((e=>e.id===t.nextStep))))||i.sendStateMachineEvent({type:"COMPLETE_PLAYLIST"}))}const s=t.transitions.find((t=>"timeout"===t.type)),r=null==(n=t.buttons)?void 0:n.some((t=>"goto"===t.action.type||"next"===t.action.type));if(s&&!r){const e=s.timeout||0;s.nextStep,setTimeout((()=>{var e;const n=bt();n.currentStepId!==t.id||"waitingForInteraction"!==n.currentState&&"playing"!==n.currentState?n.currentState:(s.nextStep,null==(e=n.goToStep)||e.call(n,s.nextStep))}),e)}i.sendStateMachineEvent({type:"VIDEO_FINISHED_WAIT",step:t})}handleStepVideoLoaded(t,e){this.managers.uiManager.hideError(),this.loadTranscriptForStep(t),t.cursorAnimations&&t.cursorAnimations.length>0?(t.id,this.managers.cursorManager.setShouldShowCursor(!0),this.cursorScheduler.schedule(t.cursorAnimations[0],t.id)):(t.id,this.managers.cursorManager.setShouldShowCursor(!1)),e?this.managers.videoManager.startAudioVisualization():this.managers.videoManager.initializeAudioForVideo(),this.managers.videoManager.play();const n=this.findNextVideoUrl(t);n&&this.managers.videoManager.preloadNextVideo(n)}handleStepVideoLoadError(t,e){var n;const i=t instanceof Error?t:new Error(`Failed to load video: ${t}`);this.managers.uiManager.showError(i,"video");const s=bt(),r=t;this.managers.eventManager.trigger("error",{timestamp:Date.now(),playlistId:(null==(n=s.manifest)?void 0:n.id)||void 0,stepId:e.id,error:i,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})}loadTranscriptForStep(t){var e,n;const i=bt(),s=(null==(e=i.manifest)?void 0:e.captions)??!0,r=null==(n=i.userData)?void 0:n.language;let a=t.transcript;if(r&&t.translations&&t.translations[r]){const e=t.translations[r].transcript;e&&(a=e,t.id)}a?(t.id,this.managers.videoManager.loadTranscript(a,s)):(t.id,this.managers.videoManager.loadTranscript(null,!0))}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);this.managers.uiManager.showPlayer(),this.showOrHideAudioOverlay(e,i),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 Ht(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 $t(t){let e=null,n=null,i=null,s=null,r={playlistData:null,stepData:null},a=null;const o=()=>{a&&(clearTimeout(a),a=null),r.playlistData&&t.trigger("playlistStarted",{timestamp:Date.now(),playlist:r.playlistData}),r.stepData&&t.trigger("stepStarted",{timestamp:Date.now(),step:{id:r.stepData.id,title:r.stepData.title},playlist:{id:r.stepData.playlistId,title:r.stepData.playlistTitle}}),r={playlistData:null,stepData:null}};return vt.subscribe((l=>{var c;if(e===l.currentState&&i===l.isMinimized&&s===l.currentStepId)return;const d=e,h=n,u=i,p=s;n=e,e=l.currentState,i=l.isMinimized,s=l.currentStepId;const g={prevPreviousState:h,previousState:d,currentState:l.currentState,currentStepId:l.currentStepId,isMinimized:l.isMinimized};null==(c=l.manifest)||c.id,"playing"===g.previousState&&("autoplayBlocked"===g.currentState||"idleMode"===g.currentState?(a&&(clearTimeout(a),a=null),(r.playlistData||r.stepData)&&(r={playlistData:null,stepData:null})):(r.playlistData||r.stepData)&&o()),"autoplayBlocked"!==g.currentState&&"idleMode"!==g.currentState||"autoplayBlocked"===g.previousState||"idleMode"===g.previousState||l.manifest&&(l.manifest.id,t.trigger("bubbleShown",{timestamp:Date.now(),playlist:{id:l.manifest.id,title:l.manifest.name}})),function(t,e,n,i){const{prevPreviousState:s,previousState:r,currentState:a,currentStepId:o}=t,l="playing"===a&&"paused"===r&&"loading"===s,c="playing"===a&&("autoplayBlocked"===r||"idleMode"===r);if(e.manifest&&o){if(o===e.manifest.startStep){if(c)return e.manifest.id,void n.trigger("playlistStarted",{timestamp:Date.now(),playlist:{id:e.manifest.id,title:e.manifest.name}});if(l)return e.manifest.id,void(i.playlistData={id:e.manifest.id,title:e.manifest.name})}}"paused"===r&&"playing"===a?n.trigger("playerResumed",{timestamp:Date.now(),previousState:r,currentState:a}):"playing"===r&&"paused"===a&&n.trigger("playerPaused",{timestamp:Date.now(),previousState:r,currentState:a})}(g,l,t,r),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})}(g,0,t,u),function(t,e,n,i,s){var r,a,o;const{prevPreviousState:l,previousState:c,currentStepId:d,currentState:h}=t,u=e.currentStepId?((null==(r=e.manifest)?void 0:r.steps)||[]).find((t=>t.id===e.currentStepId)):null;null==u||u.id,null==(a=e.manifest)||a.id,e.manifest;const p=i&&e.manifest&&(i!==d||"waitingForInteraction"===h||"completed"===h);if(e.manifest,p){const t=((null==(o=e.manifest)?void 0:o.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 g=d!==i&&"playing"===h,m=("autoplayBlocked"===c||"idleMode"===c)&&"playing"===h&&i===d,f="loading"===l&&"paused"===c&&"playing"===h&&d,y=e.manifest&&d===e.manifest.startStep,v=y&&f,b=!y&&f;null==u||u.id,e.manifest,u&&e.manifest&&(g||m||b?(u.id,n.trigger("stepStarted",{timestamp:Date.now(),step:{id:u.id,title:u.title||u.id},playlist:{id:e.manifest.id,title:e.manifest.name}})):v&&(u.id,s.stepData={id:u.id,title:u.title||u.id,playlistId:e.manifest.id,playlistTitle:e.manifest.name}))}(g,l,t,p,r),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"})}(g,l,t),!r.playlistData&&!r.stepData||a||(a&&clearTimeout(a),a=setTimeout((()=>{(r.playlistData||r.stepData)&&o(),a=null}),500))}))}const Yt=class t{constructor(t){e(this,"managers"),e(this,"uiUpdaterUnsubscribe",null),e(this,"eventUpdaterUnsubscribe",null),e(this,"cursorScheduler"),e(this,"isInitialized",!1),this.managers=t,this.cursorScheduler=new Nt(t,"ManagerOrchestrator")}setInitialized(t){this.isInitialized=t}setupUpdaters(){this.uiUpdaterUnsubscribe&&this.uiUpdaterUnsubscribe(),this.eventUpdaterUnsubscribe&&this.eventUpdaterUnsubscribe();const t=this.managers.uiManager.getPlayerElement();t&&(this.uiUpdaterUnsubscribe=Ht(t,this.managers.cursorManager)),this.eventUpdaterUnsubscribe=$t(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()}}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.cursorScheduler.schedule(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.cursorScheduler.cleanup(),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.reset(),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.cursorScheduler.cleanup(),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(Yt,"prevState",{currentState:"idle",currentStepId:null,isMinimized:!1});let Xt=Yt;class jt{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: var(--sf-bar-height, 10%);\n background-color: var(--sf-bar-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 background-color: white;\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: var(--sf-progress-width, 0%);\n transition: var(--sf-progress-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/* Hidden state for fade transitions */\n.sf-transcript__word-container--hidden {\n opacity: 0;\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 sf-compact-label--clickable class */\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/* Clickable state - enables pointer events and cursor */\n.sf-compact-label--clickable {\n cursor: pointer;\n pointer-events: auto;\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 Wt{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(Wt,"cachedDeviceInfo",null);const qt=Object.freeze(Object.defineProperty({__proto__:null,DeviceDetector:Wt,isDeviceCompatible:t=>{if(!t||"both"===t)return!0;const e=Wt.getDeviceInfo();return"mobile"===t?e.isMobile||e.isTablet:"desktop"===t&&e.isDesktop}},Symbol.toStringTag,{value:"Module"})),Zt=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.classList.add("sf-transcript__word-container--hidden"),setTimeout((()=>{if(!this.transcriptContent)return;this.transcriptContent.innerHTML="";const t=i();t.classList.add("sf-transcript__word-container--hidden"),this.transcriptContent.appendChild(t),requestAnimationFrame((()=>{t.classList.remove("sf-transcript__word-container--hidden")}))}),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(Zt,"userCaptionPreference",null);let Gt=Zt;class Kt{constructor(t){e(this,"deviceInfo"),this.deviceInfo=t}updateDeviceInfo(t){this.deviceInfo=t}}class Jt extends Kt{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)}}))}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,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 Qt extends Kt{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}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(){}}function te(t=18){return`<svg width="${t}" height="${t}" viewBox="0 0 256 256" fill="currentColor" xmlns="http://www.w3.org/2000/svg"><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"/></svg>`}class ee{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("--sf-progress-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("--sf-progress-transition","none"),this.updateProgress())})),e(this,"handleSeeked",(()=>{this.progressBar&&this.videoElement&&(this.videoElement.paused||(this.updateProgress(),this.progressBar.offsetWidth,this.progressBar.style.setProperty("--sf-progress-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("--sf-progress-transition","none"),this.progressBar.style.setProperty("--sf-progress-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='<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polygon points="11 5 6 9 2 9 2 15 6 15 11 19 11 5" fill="none"/><path d="M15 9c0.8 0.8 1.5 1.9 1.5 3s-0.7 2.2-1.5 3" stroke="currentColor"/><path d="M19 7c1.6 1.6 2.5 3.8 2.5 6s-0.9 4.4-2.5 6" stroke="currentColor"/></svg>',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),this.attachProgressListeners(t)}attachProgressListeners(t){t&&(t.addEventListener("seeking",this.handleSeeking),t.addEventListener("seeked",this.handleSeeked),t.addEventListener("timeupdate",this.handleDetailedTimeUpdate))}detachProgressListeners(t){t&&(t.removeEventListener("seeking",this.handleSeeking),t.removeEventListener("seeked",this.handleSeeked),t.removeEventListener("timeupdate",this.handleDetailedTimeUpdate))}updateVideoElement(t){this.detachProgressListeners(this.videoElement),this.videoElement=t,this.attachProgressListeners(t)}reset(){this.stopProgressTracking(),this.buttonsShownAt90Percent=!1,this.lastTimeupdateEvent=0,this.progressBar&&(this.progressBar.style.setProperty("--sf-progress-transition","none"),this.progressBar.style.setProperty("--sf-progress-width","0%"))}reset90PercentTrigger(){this.buttonsShownAt90Percent=!1}destroy(){if(this.stopProgressTracking(),this.detachProgressListeners(this.videoElement),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("--sf-progress-transition","none"),this.progressBar.style.setProperty("--sf-progress-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("--sf-progress-transition"),s=Date.now()-this.lastTimeupdateEvent;this.progressBar.style.setProperty("--sf-progress-transition","none"),this.progressBar.style.setProperty("--sf-progress-width",`${n}%`),this.progressBar.offsetWidth,this.videoElement.ended?this.progressBar.style.setProperty("--sf-progress-transition","width 0.2s ease-out"):!this.videoElement.paused&&!this.videoElement.seeking&&i&&s<500&&this.progressBar.style.setProperty("--sf-progress-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?'<svg width="18" height="18" viewBox="0 0 256 256" fill="currentColor" xmlns="http://www.w3.org/2000/svg"><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"/></svg>':'<svg width="18" height="18" viewBox="0 0 256 256" fill="currentColor" xmlns="http://www.w3.org/2000/svg"><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"/></svg>'}updateCCButtonIcon(t){this.ccButton&&(this.ccButton.innerHTML=t?'<svg width="18" height="18" viewBox="0 0 256 256" fill="currentColor" xmlns="http://www.w3.org/2000/svg"><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"/></svg>':'<svg width="18" height="18" viewBox="0 0 256 256" fill="currentColor" xmlns="http://www.w3.org/2000/svg"><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"/><line x1="48" y1="48" x2="208" y2="208" stroke="currentColor" stroke-width="16" stroke-linecap="round"/></svg>')}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("--sf-progress-transition","none"),this.progressBar.style.setProperty("--sf-progress-width","0%"),this.progressBar.offsetWidth,this.progressBar.style.setProperty("--sf-progress-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 ne{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 ie{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=Wt.getDeviceInfo();this.deviceHandler=function(t){return t.isMobile?new Jt(t):new Qt(t)}(t),this.transcriptManager=new Gt,this.audioVisualizationManager=new ne,this.deviceChangeCleanup=Wt.onDeviceChange((t=>{this.deviceHandler.updateDeviceInfo(t)}))}getDeviceInfo(){return Wt.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 ee(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}forEachVideo(t){for(const e of[this.currentVideo,this.nextVideo])e&&t(e)}applyStoreMuteState(t){t.muted=bt().isMuted}clearAutoplayFallbackTimeout(){null!==this.autoplayFallbackTimeout&&(window.clearTimeout(this.autoplayFallbackTimeout),this.autoplayFallbackTimeout=null)}swapVideos(){const t=this.getActiveVideo(),e=this.getInactiveVideo();t&&e&&(t.pause(),this.applyStoreMuteState(e),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){if(!t||""===t.trim())throw new Error("Cannot load video: No video URL provided for this step");this.controls&&this.controls.reset90PercentTrigger(),this.applyStoreMuteState(n);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(i){if(console.error("VideoManager: Failed to load video:",i),i&&"object"==typeof i&&"videoUrl"in i)throw i;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();e?(this.nextVideoUrl=t,e.src=t,e.load(),e.preload="auto",this.applyStoreMuteState(e)):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,this.clearAutoplayFallbackTimeout(),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(),this.clearAutoplayFallbackTimeout(),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(){this.forEachVideo((t=>{t.addEventListener("ended",this.handleVideoEnded),t.addEventListener("error",this.handleVideoError)}))}removeEventListeners(){this.forEachVideo((t=>{t.removeEventListener("ended",this.handleVideoEnded),t.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,this.autoplayFallbackTimeout,this.clearAutoplayFallbackTimeout())}hasUserInteractedWith(){return this.hasUserInteracted}resetUserInteraction(){this.hasUserInteracted=!1,this.clearAutoplayFallbackTimeout()}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.setProperty("--sf-bar-height",`${r}%`);const a=180+Math.abs(n-5)/5*120;s.style.setProperty("--sf-bar-color",`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 se={tolerance:.3,minSize:1};function re(t){return t.trim().replace(/\s+/g," ")}function ae(t,e){if(t.tagName.toUpperCase()!==e.tagName.toUpperCase())return!1;return re(t.textContent||"")===re(e.textContent)}function oe(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 le(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 ce(t,e,n,i=se){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)oe(s,n)||ae(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=oe(o,i);if(t){r.push({element:o,score:-1,rejection:t});continue}const e=le(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(!oe(r,i))return r}return s[0]}function de(t,e,n,i=se){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)oe(s,n)||ae(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(oe(r,i))continue;le(r,n)>=t&&e.push(r)}return e.length>0&&e.length,e}const r=[];for(const a of s){oe(a,i)||r.push(a)}return r.length>0?r:Array.from(s)}function he(t,e,n,i=se){if(oe(t,i))return!1;if(e&&ae(t,e))return!0;if(n){const e=100*(1-i.tolerance);return le(t,n)>=e}return!0}async function ue(){const t=await async function(){try{return(await import("https://storage.saltfish.ai/libs/rrweb-snapshot-2.0.0-alpha.18.js")).snapshot(document)}catch(t){return console.warn("Failed to capture DOM snapshot:",t),null}}();if(!t)return null;try{return JSON.stringify(t)}catch(e){return console.warn("Failed to serialize DOM snapshot:",e),null}}function pe(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);(async()=>{try{const i={playlistId:t,stepId:e,failureReason:r,selector:n},s=await ue();s&&(i.domSnapshot=s),await fetch("https://player.saltfish.ai/element-errors",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(i)})}catch(i){console.warn("Failed to report element error:",i)}})()}function ge(t){const e=document.createElement("canvas");e.width=1,e.height=1;const n=e.getContext("2d");if(!n)return null;n.fillStyle=t,n.fillRect(0,0,1,1);const[i,s,r]=n.getImageData(0,0,1,1).data;return{r:i,g:s,b:r}}class me{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&&pe(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=ce(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='<svg xmlns="http://www.w3.org/2000/svg" width="40" height="40" viewBox="0 0 24 24" fill="none"><defs><filter id="cursor-shadow" x="-50%" y="-50%" width="200%" height="200%"><feDropShadow dx="0" dy="1" stdDeviation="1.2" flood-color="rgba(0, 0, 0, 0.22)"/></filter></defs><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)"/></svg>',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)}}this.selectionElement&&(this.selectionElement.style.setProperty("--sf-selection-color",t),this.selectionElement.style.setProperty("--sf-selection-bg-color",function(t,e){const n=ge(t);return n?`rgba(${n.r}, ${n.g}, ${n.b}, ${e})`:t}(t,0))),this.labelElement&&(this.labelElement.style.setProperty("--sf-cursor-label-bg",t),this.labelElement.style.setProperty("--sf-cursor-label-text",function(t){const e=ge(t);return e&&(299*e.r+587*e.g+114*e.b)/1e3>150?"#333":"#fff"}(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 fe=["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 ye(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 fe){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 ve{constructor(){e(this,"container",null),e(this,"buttons",[]),e(this,"buttonContainer",null),e(this,"scrollIndicator",null),e(this,"storeUnsubscribe",null),e(this,"storageManager",mt.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=ye(e.action.url);window.location.href=l}else e.action.target,l.goToStep(e.action.target);break;case"url":e.action.target,await this.flushAnalytics(),"completedWaitingForInteraction"===l.currentState?(l.completePlaylist(),await new Promise((t=>setTimeout(t,It)))):(l.goToStep("completed"),await new Promise((t=>setTimeout(t,It))));const t=ye(e.action.target);window.open(t,"_blank");const{SaltfishPlayer:d}=await Promise.resolve().then((()=>Be)),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((()=>Be)),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)}}async flushAnalytics(){try{const{SaltfishPlayer:t}=await Promise.resolve().then((()=>Be)),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 be{constructor(t){e(this,"eventManager",null),t&&this.setEventManager(t)}setEventManager(t){this.eventManager=t,this.subscribeToEvents()}}class we extends be{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),e(this,"boundVisibilityHandler",null)}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()})})),this.eventManager.on("bubbleShown",(t=>{t.playlist.id;const e=this.getRunId();e&&this.trackEvent({type:"bubbleShown",playlistId:t.playlist.id,runId:e,timestamp:Date.now()})})),this.eventManager.on("playlistStarted",(t=>{t.playlist.id,this.trackPlaylistStart(t.playlist.id)})))}initialize(t,e){this.config=t,this.analyticsEnabled=!1!==t.enableAnalytics,e&&(this.sessionId=e),this.analyticsEnabled&&(this.flushInterval=window.setInterval((()=>{this.flushEvents()}),xt),this.boundVisibilityHandler=this.handleVisibilityChange.bind(this),document.addEventListener("visibilitychange",this.boundVisibilityHandler))}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}}}handleVisibilityChange(){"hidden"===document.visibilityState&&this.flushWithBeacon()}flushWithBeacon(){if(0===this.eventQueue.length||!this.config||!this.analyticsEnabled)return;const t=[...this.eventQueue];this.eventQueue=[];const e={token:this.config.token,sessionId:this.sessionId,user:this.user,events:t};try{fetch("https://player.saltfish.ai/analytics",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(e),keepalive:!0})}catch(n){console.warn("AnalyticsManager: fetch keepalive failed, events returned to queue"),this.eventQueue=[...t,...this.eventQueue]}}destroy(){this.analyticsEnabled&&this.flushEvents(),null!==this.flushInterval&&(clearInterval(this.flushInterval),this.flushInterval=null),this.boundVisibilityHandler&&(document.removeEventListener("visibilitychange",this.boundVisibilityHandler),this.boundVisibilityHandler=null),this.eventManager&&(this.eventManager=null),this.config=null,this.user=null,this.eventQueue=[],this.sessionId=null,this.analyticsEnabled=!0}getRunId(){try{return Ue.getInstance().getRunId()}catch(t){return null}}}class Se{constructor(t){e(this,"sessionId"),e(this,"currentRunId",null),e(this,"storageManager"),this.storageManager=t||mt.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 Ee{constructor(){e(this,"activeTransitions",new Map),e(this,"waitingForInteraction",!1),e(this,"isStateMachineValidating",!1),e(this,"triggerManager",null),e(this,"beforeUnloadHandler",null),e(this,"originalPushState",null),e(this,"originalReplaceState",null),e(this,"handleURLChange",(()=>{if(this.isStateMachineValidating)return;this.triggerManager&&this.triggerManager.clearTriggeredForNonMatchingUrls();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 void(this.triggerManager&&this.triggerManager.evaluateAllTriggers())}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)){mt.getInstance().clearPendingNavigation(),this.triggerTransition(e);break}}})),window.addEventListener("popstate",this.handleURLChange),this.monitorHistoryChanges()}setTriggerManager(t){this.triggerManager=t}monitorHistoryChanges(){this.originalPushState=history.pushState,this.originalReplaceState=history.replaceState,history.pushState=(...t)=>{this.originalPushState.apply(history,t),this.handleURLChange()},history.replaceState=(...t)=>{this.originalReplaceState.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?de(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||he(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=>he(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),mt.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;mt.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=Lt(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.closePlaylist?n.closePlaylist():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=Vt(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),this.originalPushState&&(history.pushState=this.originalPushState,this.originalPushState=null),this.originalReplaceState&&(history.replaceState=this.originalReplaceState,this.originalReplaceState=null)}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?ce(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||he(i,t.expectedElement,t.expectedSize)))return void l(i);const s=t.expectedElement||t.expectedSize?ce(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?ce(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 Me{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||["AND"]).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=mt.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))+("in_progress"===(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(Lt(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)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?ce(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?ce(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||he(s,n,i))&&r(s);else{const t=n||i?ce(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)}}clearTriggeredForNonMatchingUrls(){var t;if(0===this.triggeredPlaylistsSet.size)return;const e=Array.from(this.triggeredPlaylistsSet);e.length,e.map((t=>t.substring(0,8))).join(", ");for(const n of e){const e=this.triggeredPlaylists.find((t=>t.id===n));if(!(null==(t=null==e?void 0:e.triggers)?void 0:t.url)){n.substring(0,8);continue}this.evaluateURLCondition(e.triggers)?n.substring(0,8):this.triggeredPlaylistsSet.delete(n)}}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 xe extends be{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,r,a;const o=bt(),l=o.abTests||[],c={...e};for(const d of l){const e=d.testType||"percentage";if("linked"===e)continue;if("userList"!==e&&c[d.id])continue;let r=!1;if("userList"===e){r=!(!0===(null==(s=null==(i=o.user)?void 0:i.userData)?void 0:s.__isAnonymous))&&!0===(null==n?void 0:n[d.id])}else r=this.isUserInTest(t,d);c[d.id]={testId:d.id,assigned:r,assignedAt:Date.now()},d.name}for(const d of l){if("linked"!==(d.testType||"percentage"))continue;const e=l.find((t=>t.id===d.linkedTestId));if(!e){d.linkedTestId,d.name,c[d.id]={testId:d.id,assigned:!1,assignedAt:Date.now()};continue}let i=!1;const s=e.testType||"percentage";if("percentage"===s)i=this.isUserInTestWithParentId(t,e.id,e.percentage||0);else if("userList"===s){i=!(!0===(null==(a=null==(r=o.user)?void 0:r.userData)?void 0:a.__isAnonymous))&&!0===(null==n?void 0:n[e.id])}c[d.id]={testId:d.id,assigned:i,assignedAt:Date.now()},d.name,e.name}return o.setABTestAssignments(c),c}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}isUserInTestWithParentId(t,e,n){if(!n)return!1;const i=`${t}_${e}`;let s=0;for(let r=0;r<i.length;r++){s=(s<<5)-s+i.charCodeAt(r),s|=0}return Math.abs(s)%100<n}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 Ie{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 Pe{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=mt.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 Ce extends be{constructor(t,n){super(t),e(this,"playlistLoader"),e(this,"storageManager"),this.playlistLoader=new Pe,this.storageManager=n||mt.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;const l=bt();l.updateWatchedPlaylist(t,e,n);const c=null==(s=null==(i=l.userData)?void 0:i.watchedPlaylists)?void 0:s[t];if(!(null==(r=null==l?void 0:l.config)?void 0:r.token)||!(null==(a=null==l?void 0:l.user)?void 0:a.id)||(null==(o=null==l?void 0:l.user)?void 0:o.__isAnonymous))return void(c&&this.persistAnonymousWatchedPlaylist(t,c));const d=`https://player.saltfish.ai/clients/${l.config.token}/users/${l.user.id}/playlists/${t}`;try{const t=await fetch(d,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({status:e,currentStepId:(null==c?void 0:c.currentStepId)??null})});if(!t.ok)throw new Error(`Failed to update watched playlist status: ${t.statusText} (${t.status})`)}catch(h){console.error(`PlaylistManager: Error updating watched playlist status for ${t}:`,h)}}persistAnonymousWatchedPlaylist(t,e){if("undefined"==typeof window)return;const n=this.storageManager.getAnonymousUserData()||{userId:"anonymous",userData:{},watchedPlaylists:{},timestamp:Date.now()};n.watchedPlaylists||(n.watchedPlaylists={}),n.watchedPlaylists[t]=e,n.timestamp=Date.now();this.storageManager.setAnonymousUserData(n);e.status}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 _e{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=te(20),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='<svg width="18" height="18" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M12 5v14M5 12h14" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg>'}maximize(){this.button.innerHTML=te(20)}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 ke{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='<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M8 5v14l11-7z" fill="currentColor"/></svg>',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 Te{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='<svg width="18" height="18" viewBox="0 0 256 256" fill="currentColor" xmlns="http://www.w3.org/2000/svg"><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"/></svg>',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 Ae{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 ze{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"><svg width="60" height="60" viewBox="0 0 60 60" fill="none" xmlns="http://www.w3.org/2000/svg"><g transform="translate(10, 10) scale(0.656)"><g clip-path="url(#saltfish-clip)"><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"/><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"/></g><defs><clipPath id="saltfish-clip"><rect width="61" height="61" fill="white"/></clipPath></defs></g><circle cx="30" cy="30" r="28" stroke="black" stroke-width="2" fill="none" stroke-linecap="round" stroke-dasharray="8 6" stroke-opacity="0.3"><animateTransform attributeName="transform" type="rotate" values="0 30 30;360 30 30" dur="2s" repeatCount="indefinite"/></circle></svg></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 Le{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 _e(this.playerElement),this.exitButton=new Te(this.playerElement),t.create(this.playerElement);const i=this.createControlsContainer(this.playerElement);this.playPauseButton=new ke(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=Ae.getErrorMessage(t,e);this.errorDisplay||(this.errorDisplay=new Ae(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 ze(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/?utm_source=player&utm_medium=logo&clientId=${i}`,"_blank"):(console.warn("UIManager: No token available, falling back to saltfish.ai homepage"),window.open("https://www.saltfish.ai/?utm_source=player&utm_medium=logo","_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.classList.add("sf-compact-label--clickable"),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 Ve=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(Ve,"STEP_TIMEOUT_MS",Pt);let Oe=Ve;class De{createManagers(){const t=mt.getInstance(),e=new Se(t),n=new jt,i=new ie,s=new Ie,r=new we(s),a=new Ce(s,t),o=new xe(s),l=new me,c=new ve,d=new Ee,h=new Me,u=new Oe((()=>{}));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 Le(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 Fe=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),e(this,"initializationPromise",null),t.instance)throw new Error("SaltfishPlayer is a singleton. Use getInstance()");this.managerFactory=new De;const n=this.managerFactory.createManagers();this.playerInitializationService=new Ot(n),this.userManagementService=new Ft(n),this.playlistOrchestrator=new Bt(n),this.stateMachineActionHandler=new Rt(n),this.managerOrchestrator=new Xt(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)return this.initializationPromise||(this.initializationPromise=(async()=>{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 this.initializationPromise=null,e}})()),this.initializationPromise;console.warn("Saltfish playlist Player is already initialized")}async identifyUser(t,e){this.initializationPromise&&await this.initializationPromise,this.userManagementService.identifyUser(t,e)}async identifyAnonymous(t){this.initializationPromise&&await this.initializationPromise,await this.userManagementService.identifyAnonymous(t)}async startPlaylist(t,e){await this.playlistOrchestrator.startPlaylist(t,e)}resetPlaylist(){this.playlistOrchestrator.resetPlaylist()}closePlaylist(){this.managerOrchestrator.cleanupPlaylist();vt.getState().resetForNewPlaylist()}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(Fe,"instance",null);let Ue=Fe;const Be=Object.freeze(Object.defineProperty({__proto__:null,SaltfishPlayer:Ue},Symbol.toStringTag,{value:"Module"})),Ne="0.3.91";const Re=function(){const t=Ue.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:()=>Ne};return r.__dev__={getDeviceInfo:()=>Wt.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=Re),Re}));
|
|
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===g(t)?Reflect.ownKeys(t).forEach((n=>{e(n,t[n],t)})):t.forEach(((n,i)=>e(i,n,t)))}function g(t){const e=t[a];return e?e.type_:Array.isArray(t)?1:y(t)?2:v(t)?3:0}function m(t,e){return 2===g(t)?t.has(e):Object.prototype.hasOwnProperty.call(t,e)}function f(t,e,n){const i=g(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)||(g(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_&&!m(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(!m(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===B(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=B(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||m(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!==B(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)}},U={};function B(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)=>{U[t]=function(){return arguments[0]=arguments[0][0],e.apply(this,arguments)}})),U.deleteProperty=function(t,e){return U.set.call(this,t,e,void 0)},U.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=U);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)))}},j=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 W=t=>(e,n,i)=>(i.setState=(t,n,...i)=>{const s="function"==typeof t?j(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.runEntryActions(this.currentState)}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"}}},loading:{on:{MANIFEST_LOADED:{target:"paused"},ERROR:{target:"error"}},entry:["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"},ERROR:{target:"error"},COMPLETE_PLAYLIST:{target:"completed"},COMPLETE_PLAYLIST_WAITING_FOR_INTERACTION:{target:"completedWaitingForInteraction"}},entry:["startVideoPlayback","showVideoControls","hidePlayButton"],exit:["pauseVideoPlayback"]},paused:{on:{PLAY:{target:"playing"},START_IDLE_MODE:{target:"idleMode"},AUTOPLAY_FALLBACK:{target:"autoplayBlocked"},MINIMIZE:{target:"minimized"},TRANSITION_TO_STEP:{target:"playing"}},entry:["pauseVideoPlayback","showPlayButton"]},minimized:{on:{MAXIMIZE:{target:"playing"},EXIT:{target:"closing"}},entry:["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"}},entry:["showPlayButton"]},autoplayBlocked:{on:{PLAY:{target:"playing"},TRANSITION_TO_STEP:{target:"playing"},MINIMIZE:{target:"minimized"}},entry:["enterCompactMode","startMutedLoopedVideo","hideVideoControls","showPlayButton","enablePlayButtonProminent"],exit:["disablePlayButtonProminent","showVideoControls","exitCompactMode"]},idleMode:{on:{PLAY:{target:"playing"},TRANSITION_TO_STEP:{target:"playing"},MINIMIZE:{target:"minimized"}},entry:["startIdleModeVideo","hideVideoControls","showPlayButton","enablePlayButtonProminent"],exit:["disablePlayButtonProminent","showVideoControls","exitCompactMode"]},error:{on:{INITIALIZE:{target:"idle"},PLAY:{target:"playing"},AUTOPLAY_FALLBACK:{target:"autoplayBlocked"}},entry:["handleError","showPlayButton"],exit:["hideError"]},completedWaitingForInteraction:{on:{COMPLETE_PLAYLIST:{target:"completed"},INITIALIZE:{target:"idle"},TRANSITION_TO_STEP:{target:"playing"},PLAY:{target:"playing"},MINIMIZE:{target:"minimized"}},entry:["showPlayButton"]},completed:{on:{INITIALIZE:{target:"idle"}},entry:["trackPlaylistComplete"]},closing:{on:{},entry:["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-player__bottom-bar",dt="sf-player__ai-badge",ht="sf-player__ai-badge-label",ut="sf-player__ai-badge-label--visible",pt="sf-error-display",gt="sf-error-display--visible",mt="sf-error-display__content",ft="sf-error-display__message",yt="sf-loading-spinner",vt=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(vt,"instance",null);let bt=vt;const wt=bt.getInstance(),St=i(W(((t,e)=>{let n=new K(J,{currentStep:null,error:null});const i=t=>n.send(t),s=e=>{const i=n.send(e);return t((t=>{t.currentState=i})),i};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}))},mergeUserFields:e=>{t((t=>{t.user&&Object.assign(t.user,e)}))},setUserData:e=>{t((t=>{var n;const i=(null==e?void 0:e.watchedPlaylists)||{},s=(null==(n=t.userData)?void 0:n.watchedPlaylists)||{},r={...i};for(const[e,a]of Object.entries(s)){if(!a)continue;const t=r[e],n="completed"===a.status||"dismissed"===a.status,i=!!t&&("completed"===t.status||"dismissed"===t.status);if(n&&!i)r[e]=a,a.status,null==t||t.status;else if(t){const n=Math.max(a.visitCount??0,t.visitCount??0);(t.visitCount??0)!==n&&(r[e]={...t,visitCount:n})}}t.userData={...e,watchedPlaylists:r}}))},updateWatchedPlaylist:(e,n,i)=>{t((t=>{t.userData||(t.userData={watchedPlaylists:{}}),t.userData.watchedPlaylists||(t.userData.watchedPlaylists={});const s=t.userData.watchedPlaylists[e],r=null==s?void 0:s.status,a=(null==s?void 0:s.visitCount)??0,o=("completed"===n||"dismissed"===n)&&r!==n,l=Date.now();t.userData.watchedPlaylists[e]={status:n,currentStepId:"completed"===n?null:i??t.currentStepId??null,timestamp:l,lastProgressAt:l,visitCount:o?a+1:a}}))},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:r}=e();if("completed"!==n){if(r&&r.steps.some((t=>t.id===n))){const e=r.steps.find((t=>t.id===n));t((t=>{var s,a,o;t.currentStepId=n,e&&(t.currentState=i({type:"TRANSITION_TO_STEP",step:e}),(t.position||(null==(s=t.playlistOptions)?void 0:s.position))&&(t.position={x:0,y:0})),t.progress[r.id]={...t.progress[r.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;wt.setProgress(t.progress,e)}}))}}else s({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:()=>{s({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:t=>{s(t)},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;wt.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)))}}}))),Et={getState:()=>St.getState(),setState:St.setState,subscribe:St.subscribe,destroy:St.destroy};function xt(){try{return Et.getState()}catch(t){throw new Error(`[storeUtils] Failed to access Saltfish store: ${t}`)}}function Mt(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 It(t,e=6e3){const n=Mt(t);if(!n)return{isValid:!1,ageMs:null,timestampMs:null};const i=Date.now()-n;return{isValid:i<=e,ageMs:i,timestampMs:n}}class Pt{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{xt().setError(t)}catch(e){console.error("Failed to update store with error:",e)}}static triggerErrorEvent(t,e,n){var i,s;try{const r=xt();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(Pt,"DEFAULT_OPTIONS",{severity:"error",shouldLog:!0,shouldThrow:!1,shouldUpdateStore:!1,shouldTriggerEvent:!1,shouldDestroy:!1});class Ct{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 Pt.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 _t=3e4,kt=100,Tt=12e4,At=500,zt=500,Lt=5e3,Vt=18e5,Ot=6e4,Dt=10;function Ft(t){try{let e=t.replace(/[?&]saltfish-share-id=[^&#]*/g,((e,n)=>{if(e.startsWith("?")){return t.substring(n+e.length).startsWith("&")?"?":""}return""}));return e=e.replace(/\?&/g,"?"),e=e.replace(/&&/g,"&"),e=e.replace(/\?$/g,""),e=e.replace(/&$/g,""),e}catch(e){return t}}function Ut(t){const{pattern:e,matchType:n}=t;if(!e)return!0;const i=Ft(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 Bt{constructor(t){e(this,"managers"),e(this,"userManagementService"),e(this,"playlistOrchestrator"),e(this,"shareLinkService"),e(this,"lastConfig",null),e(this,"boundVisibilityHandler",null),e(this,"lastUserDataFetchTimestamp",0),e(this,"currentUserId",null),e(this,"currentUserData"),e(this,"isAnonymousUser",!1),this.managers=t,this.shareLinkService=new Ct}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.3.81"})}),i=await n.json();if(!i.isValid)throw Pt.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=xt();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 Pt.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 Pt.handleInitializationError(n,{component:"PlayerInitializationService",method:"initialize"})}}async fetchUserData(t,e){var n;try{const i=xt();if(!(null==(n=i.config)?void 0:n.token))return void Pt.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){this.currentUserId=t,this.currentUserData=e,this.isAnonymousUser=!1,this.lastUserDataFetchTimestamp=Date.now(),r.firstIdentifiedAt&&i.mergeUserFields({firstIdentifiedAt:r.firstIdentifiedAt}),i.setUserData({watchedPlaylists:r.watchedPlaylists||{},language:r.language});const n=r.userListAssignments||{},s=r.abTestAssignments||{};this.managers.abTestManager.assignUserToTests(t,s,n),this.setupVisibilityChangeListener(),this.managers.eventManager.trigger("userDataLoaded",{timestamp:Date.now(),userId:t,userData:{watchedPlaylists:r.watchedPlaylists||{}}}),this.userManagementService&&this.userManagementService.resolveUserDataLoaded();const a=await this.checkAndResumeFromPendingNavigation();if(!(a||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){Pt.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),this.currentUserId=t,this.currentUserData=e,this.isAnonymousUser=!0,this.lastUserDataFetchTimestamp=Date.now();xt().setUserData({watchedPlaylists:s.watchedPlaylists||{},language:null==e?void 0:e.language}),this.setupVisibilityChangeListener(),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){Pt.handleNetworkError(n,{component:"PlayerInitializationService",method:"loadAnonymousUserData",userId:t})}}async checkAndResumeInProgressPlaylist(t){var e;if(!t)return!1;const n=xt(),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}=It(e);return!!n}));if(r){const[t,e]=r;Mt(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>Ot)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=Ft(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}setupVisibilityChangeListener(){"undefined"!=typeof window&&"undefined"!=typeof document&&(this.removeVisibilityChangeListener(),this.boundVisibilityHandler=()=>this.handleVisibilityChange(),document.addEventListener("visibilitychange",this.boundVisibilityHandler))}removeVisibilityChangeListener(){this.boundVisibilityHandler&&"undefined"!=typeof document&&(document.removeEventListener("visibilitychange",this.boundVisibilityHandler),this.boundVisibilityHandler=null)}async handleVisibilityChange(){if("visible"!==document.visibilityState)return;if(!this.currentUserId)return;if(Date.now()-this.lastUserDataFetchTimestamp<5e3)return;const t=xt().currentState;if(!["playing","paused","loading","waitingForInteraction","autoplayBlocked","minimized","idleMode"].includes(t))try{this.isAnonymousUser?await this.refreshAnonymousUserData():await this.refreshIdentifiedUserData()}catch(e){}}async refreshIdentifiedUserData(){var t;const e=xt();if((null==(t=e.config)?void 0:t.token)&&this.currentUserId){this.currentUserId;try{const t=await fetch(`https://player.saltfish.ai/clients/${e.config.token}/users/${this.currentUserId}`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({userData:this.currentUserData})});if(!t.ok)return;const n=await t.json();if(n.success){this.lastUserDataFetchTimestamp=Date.now(),n.firstIdentifiedAt&&e.mergeUserFields({firstIdentifiedAt:n.firstIdentifiedAt}),e.setUserData({watchedPlaylists:n.watchedPlaylists||{},language:n.language});const t=n.userListAssignments||{},i=n.abTestAssignments||{};this.managers.abTestManager.assignUserToTests(this.currentUserId,i,t),this.managers.triggerManager.evaluateAllTriggers()}}catch(n){}}}async refreshAnonymousUserData(){var t;if(!this.currentUserId)return;this.currentUserId,this.lastUserDataFetchTimestamp=Date.now();const e=this.managers.storageManager.getAnonymousUserData();if(e){xt().setUserData({watchedPlaylists:e.watchedPlaylists||{},language:null==(t=this.currentUserData)?void 0:t.language}),this.managers.triggerManager.evaluateAllTriggers()}}destroy(){this.removeVisibilityChangeListener(),this.lastConfig=null,this.currentUserId=null,this.currentUserData=void 0,this.lastUserDataFetchTimestamp=0,this.isAnonymousUser=!1}}function Nt(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 Rt{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=Nt(e.language);n={...e,language:t},e.language}this.lastUserIdentification={userId:t,userData:n};const i=xt();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=Nt(t.language);e={...t,language:n},t.language}const n=this.playerInitializationService.getOrCreateAnonymousUserId();this.lastUserIdentification={userId:n,userData:e};xt().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=xt(),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 Ht{async validatePlaylistStart(t){const{playlistId:e,options:n,eventManager:i}=t;try{const t=xt();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 Pt.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 Pt.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 Pt.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=xt();if(!r.user)return Pt.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=xt().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=xt();if(!s.user)return Pt.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=xt().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((()=>Jt));return i(n)?{isValid:!0}:(Pt.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 Pt.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),xt(),e()};t.on("userDataLoaded",s)}))}}class $t{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 Pt.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=xt();if(!c.config){if(!(null==(i=this.playerInitializationService)?void 0:i.getLastConfig()))throw Pt.createError("Saltfish Player must be initialized at least once before starting a playlist",{component:"PlaylistOrchestrator",method:"startPlaylist",playlistId:t});throw Pt.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),!0!==(null==e?void 0:e._startedFromShareLink)){if(!this.managers.abTestManager.isPlaylistAvailable(t))return}else null==e||e._startedFromShareLink;const h=new Ht,u=await h.validatePlaylistStart({playlistId:t,options:e,eventManager:this.managers.eventManager});if(!u.isValid)return;e=u.updatedOptions||e;const p=u.manifestPath,g=e||{};g?(c.setPlaylistOptions(g),g.position||c.setPlaylistOptions({...g,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 m=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],Et.setState((t=>{t.progress=e}))}}this.managers.cursorManager.resetFirstAnimation(),await this.managers.playlistManager.load(p,{...g,persistence:m});const f=xt();if(f.manifest){const t=g.persistence??f.manifest.isPersistent??!0,e=f.playlistOptions||{};f.setPlaylistOptions({...e,...g,persistence:t})}if(g.startNodeId&&f.manifest){f.manifest.steps.find((t=>t.id===g.startNodeId))?f.goToStep(g.startNodeId):console.warn(`[PlaylistOrchestrator] startNodeId '${g.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);g._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();xt().sendStateMachineEvent({type:"ERROR",error:l instanceof Error?l:new Error(String(l))}),Pt.handlePlaylistError(l,{component:"PlaylistOrchestrator",method:"startPlaylist",playlistId:t,errorType:"playlist_load_failed"})}}resetPlaylist(){const t=xt();t.manifest&&t.goToStep(t.manifest.startStep)}isInitialized(){return!!xt().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(){}}class Yt{constructor(t,n){e(this,"listener",null),e(this,"videoElement",null),e(this,"stepId",null),this.managers=t,this.logPrefix=n}cleanup(t){if(t&&this.stepId&&t!==this.stepId)return this.logPrefix,void this.stepId;this.listener&&this.videoElement&&(this.videoElement.removeEventListener("timeupdate",this.listener),this.listener=null,this.videoElement=null,this.stepId=null)}schedule(t,e){this.cleanup();let n=t.showAtSeconds??0;if("number"==typeof n&&isFinite(n)||(this.logPrefix,n=0),n<0&&(this.logPrefix,n=0),n<=0)return this.logPrefix,void this.managers.cursorManager.animate(t);this.logPrefix;const i=this.managers.videoManager.getVideoElement();if(!i)return void this.logPrefix;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 this.logPrefix,r=!0,s=!0,this.cleanup(),void this.managers.cursorManager.animate(t);e>=n&&(s=!0,this.logPrefix,this.cleanup(),this.managers.cursorManager.animate(t))};this.listener=()=>{a()},this.videoElement=i,this.stepId=e,i.addEventListener("timeupdate",this.listener),i.addEventListener("ended",(()=>{if(s)return;const n=xt();if(n.currentStepId!==e)return this.logPrefix,n.currentStepId,void this.cleanup(e);i.duration;this.logPrefix,s=!0,this.managers.cursorManager.animate(t),this.cleanup()}),{once:!0})}}class Xt{constructor(t){e(this,"managers"),e(this,"destroyCallback",null),e(this,"cursorScheduler"),this.managers=t,this.cursorScheduler=new Yt(t,"StateMachineActionHandler")}setDestroyCallback(t){this.destroyCallback=t}registerStateMachineActions(){xt().registerStateMachineActions({startVideoPlayback:t=>this.handleStartVideoPlayback(t),startIdleModeVideo:t=>this.handleStartIdleModeVideo(t),handleError:t=>this.handleError(t),pauseVideoPlayback:()=>this.handlePauseVideoPlayback(),startMutedLoopedVideo:()=>this.handleStartMutedLoopedVideo(),trackPlaylistComplete:()=>this.handleTrackPlaylistComplete(),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=xt().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=xt().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=xt();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.cursorScheduler.cleanup()}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(Ut(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);this.showOrHideAudioOverlay(e,i);try{this.managers.interactionManager.clearButtons(),e.buttons&&this.managers.interactionManager.createButtons(e.buttons);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));t&&this.managers.transitionManager.setupTransitions(e,!1,!0),this.managers.videoManager.setCompletionPolicy(t?"manual":"auto",(()=>this.handleStepVideoEnded(e,t))),this.managers.videoManager.loadVideo(n).then((()=>this.handleStepVideoLoaded(e,i))).catch((t=>this.handleStepVideoLoadError(t,e)))}catch(s){}}showOrHideAudioOverlay(t,e){if(e){const e=xt().manifest;this.managers.videoManager.showAudioFallbackOverlay(t.gifUrl,null==e?void 0:e.avatarThumbnailUrl)}else this.managers.videoManager.hideAudioFallbackOverlay()}handleStepVideoEnded(t,e){var n;const i=xt();if(!e){const e=t.transitions.find((t=>"timeout"===t.type));e&&e.timeout&&e.timeout>0?(e.timeout,this.managers.transitionManager.setupTransitions(t,!1)):this.managers.transitionManager.setupTransitions(t,!0);return void(t.transitions.some((t=>i.manifest.steps.some((e=>e.id===t.nextStep))))||i.sendStateMachineEvent({type:"COMPLETE_PLAYLIST"}))}const s=t.transitions.find((t=>"timeout"===t.type)),r=null==(n=t.buttons)?void 0:n.some((t=>"goto"===t.action.type||"next"===t.action.type));if(s&&!r){const e=s.timeout||0;s.nextStep,setTimeout((()=>{var e;const n=xt();n.currentStepId!==t.id||"waitingForInteraction"!==n.currentState&&"playing"!==n.currentState?n.currentState:(s.nextStep,null==(e=n.goToStep)||e.call(n,s.nextStep))}),e)}i.sendStateMachineEvent({type:"VIDEO_FINISHED_WAIT",step:t})}handleStepVideoLoaded(t,e){this.managers.uiManager.hideError(),this.loadTranscriptForStep(t),t.cursorAnimations&&t.cursorAnimations.length>0?(t.id,this.managers.cursorManager.setShouldShowCursor(!0),this.cursorScheduler.schedule(t.cursorAnimations[0],t.id)):(t.id,this.managers.cursorManager.setShouldShowCursor(!1)),e?this.managers.videoManager.startAudioVisualization():this.managers.videoManager.initializeAudioForVideo(),this.managers.videoManager.play();const n=this.findNextVideoUrl(t);n&&this.managers.videoManager.preloadNextVideo(n)}handleStepVideoLoadError(t,e){var n;const i=t instanceof Error?t:new Error(`Failed to load video: ${t}`);this.managers.uiManager.showError(i,"video");const s=xt(),r=t;this.managers.eventManager.trigger("error",{timestamp:Date.now(),playlistId:(null==(n=s.manifest)?void 0:n.id)||void 0,stepId:e.id,error:i,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})}loadTranscriptForStep(t){var e,n;const i=xt(),s=(null==(e=i.manifest)?void 0:e.captions)??!0,r=null==(n=i.userData)?void 0:n.language;let a=t.transcript;if(r&&t.translations&&t.translations[r]){const e=t.translations[r].transcript;e&&(a=e,t.id)}a?(t.id,this.managers.videoManager.loadTranscript(a,s)):(t.id,this.managers.videoManager.loadTranscript(null,!0))}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);this.managers.uiManager.showPlayer(),this.showOrHideAudioOverlay(e,i),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=xt();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=xt();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=xt();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=xt();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 jt(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 Et.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 Wt(t){let e=null,n=null,i=null,s=null,r={playlistData:null,stepData:null},a=null;const o=()=>{a&&(clearTimeout(a),a=null),r.playlistData&&t.trigger("playlistStarted",{timestamp:Date.now(),playlist:r.playlistData}),r.stepData&&t.trigger("stepStarted",{timestamp:Date.now(),step:{id:r.stepData.id,title:r.stepData.title},playlist:{id:r.stepData.playlistId,title:r.stepData.playlistTitle}}),r={playlistData:null,stepData:null}};return Et.subscribe((l=>{var c;if(e===l.currentState&&i===l.isMinimized&&s===l.currentStepId)return;const d=e,h=n,u=i,p=s;n=e,e=l.currentState,i=l.isMinimized,s=l.currentStepId;const g={prevPreviousState:h,previousState:d,currentState:l.currentState,currentStepId:l.currentStepId,isMinimized:l.isMinimized};null==(c=l.manifest)||c.id,"playing"===g.previousState&&("autoplayBlocked"===g.currentState||"idleMode"===g.currentState?(a&&(clearTimeout(a),a=null),(r.playlistData||r.stepData)&&(r={playlistData:null,stepData:null})):(r.playlistData||r.stepData)&&o()),"autoplayBlocked"!==g.currentState&&"idleMode"!==g.currentState||"autoplayBlocked"===g.previousState||"idleMode"===g.previousState||l.manifest&&(l.manifest.id,t.trigger("bubbleShown",{timestamp:Date.now(),playlist:{id:l.manifest.id,title:l.manifest.name}})),function(t,e,n,i){const{prevPreviousState:s,previousState:r,currentState:a,currentStepId:o}=t,l="playing"===a&&"paused"===r&&"loading"===s,c="playing"===a&&("autoplayBlocked"===r||"idleMode"===r);if(e.manifest&&o){if(o===e.manifest.startStep){if(c)return e.manifest.id,void n.trigger("playlistStarted",{timestamp:Date.now(),playlist:{id:e.manifest.id,title:e.manifest.name}});if(l)return e.manifest.id,void(i.playlistData={id:e.manifest.id,title:e.manifest.name})}}"paused"===r&&"playing"===a?n.trigger("playerResumed",{timestamp:Date.now(),previousState:r,currentState:a}):"playing"===r&&"paused"===a&&n.trigger("playerPaused",{timestamp:Date.now(),previousState:r,currentState:a})}(g,l,t,r),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})}(g,0,t,u),function(t,e,n,i,s){var r,a,o;const{prevPreviousState:l,previousState:c,currentStepId:d,currentState:h}=t,u=e.currentStepId?((null==(r=e.manifest)?void 0:r.steps)||[]).find((t=>t.id===e.currentStepId)):null;null==u||u.id,null==(a=e.manifest)||a.id,e.manifest;const p=i&&e.manifest&&(i!==d||"waitingForInteraction"===h||"completed"===h);if(e.manifest,p){const t=((null==(o=e.manifest)?void 0:o.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 g=d!==i&&"playing"===h,m=("autoplayBlocked"===c||"idleMode"===c)&&"playing"===h&&i===d,f="loading"===l&&"paused"===c&&"playing"===h&&d,y=e.manifest&&d===e.manifest.startStep,v=y&&f,b=!y&&f;null==u||u.id,e.manifest,u&&e.manifest&&(g||m||b?(u.id,n.trigger("stepStarted",{timestamp:Date.now(),step:{id:u.id,title:u.title||u.id},playlist:{id:e.manifest.id,title:e.manifest.name}})):v&&(u.id,s.stepData={id:u.id,title:u.title||u.id,playlistId:e.manifest.id,playlistTitle:e.manifest.name}))}(g,l,t,p,r),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"})}(g,l,t),!r.playlistData&&!r.stepData||a||(a&&clearTimeout(a),a=setTimeout((()=>{(r.playlistData||r.stepData)&&o(),a=null}),500))}))}const qt=class t{constructor(t){e(this,"managers"),e(this,"uiUpdaterUnsubscribe",null),e(this,"eventUpdaterUnsubscribe",null),e(this,"cursorScheduler"),e(this,"isInitialized",!1),this.managers=t,this.cursorScheduler=new Yt(t,"ManagerOrchestrator")}setInitialized(t){this.isInitialized=t}setupUpdaters(){this.uiUpdaterUnsubscribe&&this.uiUpdaterUnsubscribe(),this.eventUpdaterUnsubscribe&&this.eventUpdaterUnsubscribe();const t=this.managers.uiManager.getPlayerElement();t&&(this.uiUpdaterUnsubscribe=jt(t,this.managers.cursorManager)),this.eventUpdaterUnsubscribe=Wt(this.managers.eventManager);const e=Et.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()}}handleStoreChanges(){if(!this.isInitialized)return;const e=xt();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.cursorScheduler.schedule(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.cursorScheduler.cleanup(),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){Pt.handleCleanupError(t,{component:"ManagerOrchestrator",method:"cleanupCurrentPlaylist"})}}cleanupPlaylist(){var t;if(this.isInitialized)try{const e=xt();e.currentState,e.currentStepId,e.isMinimized,null==(t=e.manifest)||t.id,this.uiUpdaterUnsubscribe&&(this.uiUpdaterUnsubscribe(),this.uiUpdaterUnsubscribe=null),this.managers.transitionManager.reset(),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){Pt.handleCleanupError(e,{component:"ManagerOrchestrator",method:"cleanupPlaylist"})}else console.warn("Saltfish playlist Player is not initialized")}destroyAll(){var t;if(this.isInitialized)try{const e=xt();e.currentState,e.currentStepId,e.isMinimized,null==(t=e.manifest)||t.id,this.cursorScheduler.cleanup(),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){Pt.handleCleanupError(e,{component:"ManagerOrchestrator",method:"destroyAll"});try{this.isInitialized=!1;xt().reset()}catch(n){Pt.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(qt,"prevState",{currentState:"idle",currentStepId:null,isMinimized:!1});let Zt=qt;class Gt{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__bottom-bar,\n.sf-player--compact .sf-player__minimize-button {\n display: none;\n}\n\n/* Compact bubble still shows AI-generated footage, so keep a small AI badge.\n The whole bubble is clickable, so the badge must not intercept pointer\n events (no hover label). */\n.sf-player--compact .sf-player__ai-badge {\n /* Offsets keep the badge fully inside the circular bubble (also at the\n 90px mobile size) */\n right: 16px;\n bottom: 16px;\n height: 16px;\n pointer-events: none;\n}\n\n.sf-player--compact .sf-player__ai-badge svg {\n width: 12px;\n height: 12px;\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/* Bottom bar behind the Saltfish logo - keeps it legible on bright videos.\n Only rendered when the logo is shown (showLogo entitlement). */\n.sf-player__bottom-bar {\n position: absolute;\n bottom: 0;\n left: 0;\n right: 0;\n height: 32px;\n /* Soft fade with no hard top edge - stacks on the video's bottom\n gradient (0.6 black at the bottom edge), so the white logo stays\n legible without the strip reading as a solid bar */\n background: linear-gradient(to top, rgba(0, 0, 0, 0.45) 0%, rgba(0, 0, 0, 0) 100%);\n border-radius: 0 0 var(--sf-border-radius-md) var(--sf-border-radius-md);\n pointer-events: none;\n z-index: var(--sf-z-index-controls);\n}\n\n/* Saltfish logo */\n.sf-player__logo {\n position: absolute;\n bottom: 0;\n left: 0;\n right: 0;\n height: 26px;\n z-index: var(--sf-z-index-controls);\n opacity: 0.9;\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: 13px;\n}\n\n/* Logo hover state */\n.sf-player:hover .sf-player__logo {\n opacity: 1;\n}\n\n/* AI transparency badge (EU AI Act disclosure) - always visible, even for\n whitelabel clients that hide the Saltfish logo */\n.sf-player__ai-badge {\n position: absolute;\n bottom: 0;\n right: var(--sf-spacing-sm);\n height: 26px;\n display: flex;\n align-items: center;\n z-index: var(--sf-z-index-controls);\n opacity: 0.9;\n cursor: default;\n}\n\n.sf-player__ai-badge:hover {\n opacity: 1;\n}\n\n.sf-player__ai-badge svg {\n width: 16px;\n height: 16px;\n display: block;\n /* Self-contained contrast so the white badge stays visible on bright\n footage, including modes that hide the bottom gradient */\n filter: drop-shadow(0 1px 3px rgba(0, 0, 0, 0.35));\n}\n\n/* Disclosure text shown when hovering the AI badge */\n.sf-player__ai-badge-label {\n position: absolute;\n bottom: calc(100% + var(--sf-spacing-xs));\n right: 0;\n padding: 4px 8px;\n background: rgba(0, 0, 0, 0.8);\n color: #ffffff;\n font-size: 11px;\n line-height: 1.2;\n border-radius: var(--sf-border-radius-sm);\n white-space: nowrap;\n opacity: 0;\n visibility: hidden;\n transition: opacity var(--sf-transition-normal);\n pointer-events: none;\n}\n\n/* Hover only on devices that support it - on touch, tapping applies a\n sticky :hover that would keep the label stuck open */\n@media (hover: hover) {\n .sf-player__ai-badge:hover .sf-player__ai-badge-label {\n opacity: 1;\n visibility: visible;\n }\n}\n\n.sf-player__ai-badge-label--visible {\n opacity: 1;\n visibility: visible;\n}\n\n/* Hide logo and bottom bar when minimized; keep a small AI badge on the\n bubble since the avatar is still visible. The whole bubble is clickable,\n so the badge must not intercept pointer events (no hover label). */\n.sf-player--minimized .sf-player__logo,\n.sf-player--minimized .sf-player__bottom-bar {\n display: none;\n}\n\n.sf-player--minimized .sf-player__ai-badge {\n /* Offsets keep the badge fully inside the circular bubble (also at the\n 60px mobile size) */\n right: 11px;\n bottom: 11px;\n height: 10px;\n pointer-events: none;\n}\n\n.sf-player--minimized .sf-player__ai-badge svg {\n width: 10px;\n height: 10px;\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: var(--sf-bar-height, 10%);\n background-color: var(--sf-bar-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 background-color: white;\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: var(--sf-progress-width, 0%);\n transition: var(--sf-progress-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/* Hidden state for fade transitions */\n.sf-transcript__word-container--hidden {\n opacity: 0;\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 sf-compact-label--clickable class */\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/* Clickable state - enables pointer events and cursor */\n.sf-compact-label--clickable {\n cursor: pointer;\n pointer-events: auto;\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 Kt{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(Kt,"cachedDeviceInfo",null);const Jt=Object.freeze(Object.defineProperty({__proto__:null,DeviceDetector:Kt,isDeviceCompatible:t=>{if(!t||"both"===t)return!0;const e=Kt.getDeviceInfo();return"mobile"===t?e.isMobile||e.isTablet:"desktop"===t&&e.isDesktop}},Symbol.toStringTag,{value:"Module"})),Qt=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.classList.add("sf-transcript__word-container--hidden"),setTimeout((()=>{if(!this.transcriptContent)return;this.transcriptContent.innerHTML="";const t=i();t.classList.add("sf-transcript__word-container--hidden"),this.transcriptContent.appendChild(t),requestAnimationFrame((()=>{t.classList.remove("sf-transcript__word-container--hidden")}))}),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(Qt,"userCaptionPreference",null);let te=Qt;class ee{constructor(t){e(this,"deviceInfo"),this.deviceInfo=t}updateDeviceInfo(t){this.deviceInfo=t}}class ne extends ee{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)}}))}configureControlElement(t){}async handlePlayAttempt(t,e){const n=xt().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 ie extends ee{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}configureControlElement(t){}async handlePlayAttempt(t,e){const n=xt().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(){}}function se(t=18){return`<svg width="${t}" height="${t}" viewBox="0 0 256 256" fill="currentColor" xmlns="http://www.w3.org/2000/svg"><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"/></svg>`}class re{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("--sf-progress-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("--sf-progress-transition","none"),this.updateProgress())})),e(this,"handleSeeked",(()=>{this.progressBar&&this.videoElement&&(this.videoElement.paused||(this.updateProgress(),this.progressBar.offsetWidth,this.progressBar.style.setProperty("--sf-progress-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("--sf-progress-transition","none"),this.progressBar.style.setProperty("--sf-progress-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='<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polygon points="11 5 6 9 2 9 2 15 6 15 11 19 11 5" fill="none"/><path d="M15 9c0.8 0.8 1.5 1.9 1.5 3s-0.7 2.2-1.5 3" stroke="currentColor"/><path d="M19 7c1.6 1.6 2.5 3.8 2.5 6s-0.9 4.4-2.5 6" stroke="currentColor"/></svg>',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),this.attachProgressListeners(t)}attachProgressListeners(t){t&&(t.addEventListener("seeking",this.handleSeeking),t.addEventListener("seeked",this.handleSeeked),t.addEventListener("timeupdate",this.handleDetailedTimeUpdate))}detachProgressListeners(t){t&&(t.removeEventListener("seeking",this.handleSeeking),t.removeEventListener("seeked",this.handleSeeked),t.removeEventListener("timeupdate",this.handleDetailedTimeUpdate))}updateVideoElement(t){this.detachProgressListeners(this.videoElement),this.videoElement=t,this.attachProgressListeners(t)}reset(){this.stopProgressTracking(),this.buttonsShownAt90Percent=!1,this.lastTimeupdateEvent=0,this.progressBar&&(this.progressBar.style.setProperty("--sf-progress-transition","none"),this.progressBar.style.setProperty("--sf-progress-width","0%"))}reset90PercentTrigger(){this.buttonsShownAt90Percent=!1}destroy(){if(this.stopProgressTracking(),this.detachProgressListeners(this.videoElement),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("--sf-progress-transition","none"),this.progressBar.style.setProperty("--sf-progress-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("--sf-progress-transition"),s=Date.now()-this.lastTimeupdateEvent;this.progressBar.style.setProperty("--sf-progress-transition","none"),this.progressBar.style.setProperty("--sf-progress-width",`${n}%`),this.progressBar.offsetWidth,this.videoElement.ended?this.progressBar.style.setProperty("--sf-progress-transition","width 0.2s ease-out"):!this.videoElement.paused&&!this.videoElement.seeking&&i&&s<500&&this.progressBar.style.setProperty("--sf-progress-transition","width 0.1s linear")}}setMuted(t){xt().setMuted(t),this.updateMuteButtonIcon()}toggleMute(){const t=!xt().isMuted;this.setMuted(t),this.callbacks.onMuteToggle()}getMuted(){return xt().isMuted}updateMuteButtonIcon(){if(!this.muteButton)return;const t=xt().isMuted;this.muteButton.innerHTML=t?'<svg width="18" height="18" viewBox="0 0 256 256" fill="currentColor" xmlns="http://www.w3.org/2000/svg"><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"/></svg>':'<svg width="18" height="18" viewBox="0 0 256 256" fill="currentColor" xmlns="http://www.w3.org/2000/svg"><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"/></svg>'}updateCCButtonIcon(t){this.ccButton&&(this.ccButton.innerHTML=t?'<svg width="18" height="18" viewBox="0 0 256 256" fill="currentColor" xmlns="http://www.w3.org/2000/svg"><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"/></svg>':'<svg width="18" height="18" viewBox="0 0 256 256" fill="currentColor" xmlns="http://www.w3.org/2000/svg"><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"/><line x1="48" y1="48" x2="208" y2="208" stroke="currentColor" stroke-width="16" stroke-linecap="round"/></svg>')}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("--sf-progress-transition","none"),this.progressBar.style.setProperty("--sf-progress-width","0%"),this.progressBar.offsetWidth,this.progressBar.style.setProperty("--sf-progress-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 ae{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 oe{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=xt();"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=Kt.getDeviceInfo();this.deviceHandler=function(t){return t.isMobile?new ne(t):new ie(t)}(t),this.transcriptManager=new te,this.audioVisualizationManager=new ae,this.deviceChangeCleanup=Kt.onDeviceChange((t=>{this.deviceHandler.updateDeviceInfo(t)}))}getDeviceInfo(){return Kt.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);xt().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 re(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}forEachVideo(t){for(const e of[this.currentVideo,this.nextVideo])e&&t(e)}applyStoreMuteState(t){t.muted=xt().isMuted}clearAutoplayFallbackTimeout(){null!==this.autoplayFallbackTimeout&&(window.clearTimeout(this.autoplayFallbackTimeout),this.autoplayFallbackTimeout=null)}swapVideos(){const t=this.getActiveVideo(),e=this.getInactiveVideo();t&&e&&(t.pause(),this.applyStoreMuteState(e),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){if(!t||""===t.trim())throw new Error("Cannot load video: No video URL provided for this step");this.controls&&this.controls.reset90PercentTrigger(),this.applyStoreMuteState(n);try{this.controls&&this.controls.reset();const i=(null==(e=xt().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(i){if(console.error("VideoManager: Failed to load video:",i),i&&"object"==typeof i&&"videoUrl"in i)throw i;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();e?(this.nextVideoUrl=t,e.src=t,e.load(),e.preload="auto",this.applyStoreMuteState(e)):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=xt();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");xt().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,this.clearAutoplayFallbackTimeout(),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(),this.clearAutoplayFallbackTimeout(),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(){this.forEachVideo((t=>{t.addEventListener("ended",this.handleVideoEnded),t.addEventListener("error",this.handleVideoError)}))}removeEventListeners(){this.forEachVideo((t=>{t.removeEventListener("ended",this.handleVideoEnded),t.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,this.autoplayFallbackTimeout,this.clearAutoplayFallbackTimeout())}hasUserInteractedWith(){return this.hasUserInteracted}resetUserInteraction(){this.hasUserInteracted=!1,this.clearAutoplayFallbackTimeout()}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.setProperty("--sf-bar-height",`${r}%`);const a=180+Math.abs(n-5)/5*120;s.style.setProperty("--sf-bar-color",`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 le={tolerance:.3,minSize:1};function ce(t){return t.trim().replace(/\s+/g," ")}function de(t,e){if(t.tagName.toUpperCase()!==e.tagName.toUpperCase())return!1;return ce(t.textContent||"")===ce(e.textContent)}function he(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 ue(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 pe(t,e,n,i=le){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)he(s,n)||de(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=he(o,i);if(t){r.push({element:o,score:-1,rejection:t});continue}const e=ue(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(!he(r,i))return r}return s[0]}function ge(t,e,n,i=le){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)he(s,n)||de(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(he(r,i))continue;ue(r,n)>=t&&e.push(r)}return e.length>0&&e.length,e}const r=[];for(const a of s){he(a,i)||r.push(a)}return r.length>0?r:Array.from(s)}function me(t,e,n,i=le){if(he(t,i))return!1;if(e&&de(t,e))return!0;if(n){const e=100*(1-i.tolerance);return ue(t,n)>=e}return!0}async function fe(){const t=await async function(){try{return(await import("https://storage.saltfish.ai/libs/rrweb-snapshot-2.0.0-alpha.18.js")).snapshot(document)}catch(t){return console.warn("Failed to capture DOM snapshot:",t),null}}();if(!t)return null;try{return JSON.stringify(t)}catch(e){return console.warn("Failed to serialize DOM snapshot:",e),null}}function ye(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);(async()=>{try{const i={playlistId:t,stepId:e,failureReason:r,selector:n},s=await fe();s&&(i.domSnapshot=s),await fetch("https://player.saltfish.ai/element-errors",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(i)})}catch(i){console.warn("Failed to report element error:",i)}})()}function ve(t){const e=document.createElement("canvas");e.width=1,e.height=1;const n=e.getContext("2d");if(!n)return null;n.fillStyle=t,n.fillRect(0,0,1,1);const[i,s,r]=n.getImageData(0,0,1,1).data;return{r:i,g:s,b:r}}class be{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=St.getState(),r=null==(e=s.manifest)?void 0:e.id,o=s.currentStepId;r&&o&&ye(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=pe(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='<svg xmlns="http://www.w3.org/2000/svg" width="40" height="40" viewBox="0 0 24 24" fill="none"><defs><filter id="cursor-shadow" x="-50%" y="-50%" width="200%" height="200%"><feDropShadow dx="0" dy="1" stdDeviation="1.2" flood-color="rgba(0, 0, 0, 0.22)"/></filter></defs><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)"/></svg>',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"===St.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,zt))),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)}}this.selectionElement&&(this.selectionElement.style.setProperty("--sf-selection-color",t),this.selectionElement.style.setProperty("--sf-selection-bg-color",function(t,e){const n=ve(t);return n?`rgba(${n.r}, ${n.g}, ${n.b}, ${e})`:t}(t,0))),this.labelElement&&(this.labelElement.style.setProperty("--sf-cursor-label-bg",t),this.labelElement.style.setProperty("--sf-cursor-label-text",function(t){const e=ve(t);return e&&(299*e.r+587*e.g+114*e.b)/1e3>150?"#333":"#fff"}(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 we=["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 Se(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 we){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 Ee{constructor(){e(this,"container",null),e(this,"buttons",[]),e(this,"buttonContainer",null),e(this,"scrollIndicator",null),e(this,"storeUnsubscribe",null),e(this,"storageManager",bt.getInstance()),e(this,"handleVideo90PercentReached",(t=>{this.showButtonsAt90Percent()}))}create(t){this.container=t,this.storeUnsubscribe=Et.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);xt().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<Dt?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(xt().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=xt();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=xt();if(t.manifest){Et.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=xt();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=Se(e.action.url);window.location.href=l}else e.action.target,l.goToStep(e.action.target);break;case"url":e.action.target,await this.flushAnalytics(),"completedWaitingForInteraction"===l.currentState?(l.completePlaylist(),await new Promise((t=>setTimeout(t,kt)))):(l.goToStep("completed"),await new Promise((t=>setTimeout(t,kt))));const t=Se(e.action.target);window.open(t,"_blank");const{SaltfishPlayer:d}=await Promise.resolve().then((()=>$e)),h=d.getInstance();h&&h.destroy();break;case"playlist":e.action.target;try{await this.flushAnalytics(),l.completePlaylist(),await new Promise((t=>setTimeout(t,kt)));const{SaltfishPlayer:t}=await Promise.resolve().then((()=>$e)),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)}}async flushAnalytics(){try{const{SaltfishPlayer:t}=await Promise.resolve().then((()=>$e)),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 xe{constructor(t){e(this,"eventManager",null),t&&this.setEventManager(t)}setEventManager(t){this.eventManager=t,this.subscribeToEvents()}}class Me extends xe{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),e(this,"boundVisibilityHandler",null)}subscribeToEvents(){this.eventManager&&(this.eventManager.on("playerPaused",(t=>{const e=xt(),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=xt(),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=xt(),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=xt(),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()})})),this.eventManager.on("bubbleShown",(t=>{t.playlist.id;const e=this.getRunId();e&&this.trackEvent({type:"bubbleShown",playlistId:t.playlist.id,runId:e,timestamp:Date.now()})})),this.eventManager.on("playlistStarted",(t=>{t.playlist.id,this.trackPlaylistStart(t.playlist.id)})))}initialize(t,e){this.config=t,this.analyticsEnabled=!1!==t.enableAnalytics,e&&(this.sessionId=e),this.analyticsEnabled&&(this.flushInterval=window.setInterval((()=>{this.flushEvents()}),_t),this.boundVisibilityHandler=this.handleVisibilityChange.bind(this),document.addEventListener("visibilitychange",this.boundVisibilityHandler))}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}}}handleVisibilityChange(){"hidden"===document.visibilityState&&this.flushWithBeacon()}flushWithBeacon(){if(0===this.eventQueue.length||!this.config||!this.analyticsEnabled)return;const t=[...this.eventQueue];this.eventQueue=[];const e={token:this.config.token,sessionId:this.sessionId,user:this.user,events:t};try{fetch("https://player.saltfish.ai/analytics",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(e),keepalive:!0})}catch(n){console.warn("AnalyticsManager: fetch keepalive failed, events returned to queue"),this.eventQueue=[...t,...this.eventQueue]}}destroy(){this.analyticsEnabled&&this.flushEvents(),null!==this.flushInterval&&(clearInterval(this.flushInterval),this.flushInterval=null),this.boundVisibilityHandler&&(document.removeEventListener("visibilitychange",this.boundVisibilityHandler),this.boundVisibilityHandler=null),this.eventManager&&(this.eventManager=null),this.config=null,this.user=null,this.eventQueue=[],this.sessionId=null,this.analyticsEnabled=!0}getRunId(){try{return He.getInstance().getRunId()}catch(t){return null}}}class Ie{constructor(t){e(this,"sessionId"),e(this,"currentRunId",null),e(this,"storageManager"),this.storageManager=t||bt.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<Vt)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 Pe{constructor(){e(this,"activeTransitions",new Map),e(this,"waitingForInteraction",!1),e(this,"isStateMachineValidating",!1),e(this,"triggerManager",null),e(this,"beforeUnloadHandler",null),e(this,"originalPushState",null),e(this,"originalReplaceState",null),e(this,"handleURLChange",(()=>{if(this.isStateMachineValidating)return;this.triggerManager&&this.triggerManager.clearTriggeredForNonMatchingUrls();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 void(this.triggerManager&&this.triggerManager.evaluateAllTriggers())}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)){bt.getInstance().clearPendingNavigation(),this.triggerTransition(e);break}}})),window.addEventListener("popstate",this.handleURLChange),this.monitorHistoryChanges()}setTriggerManager(t){this.triggerManager=t}monitorHistoryChanges(){this.originalPushState=history.pushState,this.originalReplaceState=history.replaceState,history.pushState=(...t)=>{this.originalPushState.apply(history,t),this.handleURLChange()},history.replaceState=(...t)=>{this.originalReplaceState.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?ge(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||me(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=>me(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=xt();"waitingForInteraction"===s.currentState||"playing"===s.currentState?(s.currentState,this.triggerTransition(n)):e<t&&(s.currentState,setTimeout(i,At))};setTimeout(i,At)}const i=`url-path-${Date.now()}`,s=window.setInterval((()=>{this.isURLPathMatch(e)&&(clearInterval(s),bt.getInstance().clearPendingNavigation(),this.triggerTransition(n))}),Lt);this.activeTransitions.set(i,{handlers:new Map,cleanup:()=>{clearInterval(s)},data:{type:"url-path",pattern:e,nextStepId:n}})}savePendingNavigation(t,e){const n=xt();if(!n.manifest)return;bt.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=Ft(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.closePlaylist?n.closePlaylist():n&&"function"==typeof n.destroy&&n.destroy()}validateCurrentStepUrl(){const t=xt(),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=Ut(i.urlRequirement);return s||this.handleUrlRequirementFailure(n,i.urlRequirement),s}triggerTransition(t){var e;const n=xt(),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=xt(),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,kt))),!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),this.originalPushState&&(history.pushState=this.originalPushState,this.originalPushState=null),this.originalReplaceState&&(history.replaceState=this.originalReplaceState,this.originalReplaceState=null)}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?pe(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||me(i,t.expectedElement,t.expectedSize)))return void l(i);const s=t.expectedElement||t.expectedSize?pe(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?pe(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 Ce{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(!xt().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||["AND"]).join(", "),!!u&&(this.triggerPlaylist(n),!0)}getWatchedPlaylists(){var t,e;const n=xt();if((null==(t=n.userData)?void 0:t.watchedPlaylists)&&Object.keys(n.userData.watchedPlaylists).length>0)return n.userData.watchedPlaylists;const i=bt.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))+("in_progress"===(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(Ft(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){if(!e[n])return!1;if(this.isPlaylistCurrentlyActive(n))return!1}return!0}isPlaylistCurrentlyActive(t){var e;const n=xt();if((null==(e=n.manifest)?void 0:e.id)!==t)return!1;return!["idle","completed","closing","error"].includes(n.currentState)}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=xt().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?pe(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?pe(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||me(s,n,i))&&r(s);else{const t=n||i?pe(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)}}clearTriggeredForNonMatchingUrls(){var t;if(0===this.triggeredPlaylistsSet.size)return;const e=Array.from(this.triggeredPlaylistsSet);e.length,e.map((t=>t.substring(0,8))).join(", ");for(const n of e){const e=this.triggeredPlaylists.find((t=>t.id===n));if(!(null==(t=null==e?void 0:e.triggers)?void 0:t.url)){n.substring(0,8);continue}this.evaluateURLCondition(e.triggers)?n.substring(0,8):this.triggeredPlaylistsSet.delete(n)}}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 _e extends xe{constructor(t){super(t)}subscribeToEvents(){this.eventManager&&this.eventManager.on("playlistStarted",(t=>{this.trackTestParticipation(t.playlist.id)}))}initializeTests(t){xt().setABTests(t)}assignUserToTests(t,e,n){var i,s,r,a;const o=xt(),l=o.abTests||[],c={...e};for(const d of l){const e=d.testType||"percentage";if("linked"===e)continue;if("userList"!==e&&c[d.id])continue;let r=!1;if("userList"===e){r=!(!0===(null==(s=null==(i=o.user)?void 0:i.userData)?void 0:s.__isAnonymous))&&!0===(null==n?void 0:n[d.id])}else r=this.isUserInTest(t,d);c[d.id]={testId:d.id,assigned:r,assignedAt:Date.now()},d.name}for(const d of l){if("linked"!==(d.testType||"percentage"))continue;const e=l.find((t=>t.id===d.linkedTestId));if(!e){d.linkedTestId,d.name,c[d.id]={testId:d.id,assigned:!1,assignedAt:Date.now()};continue}let i=!1;const s=e.testType||"percentage";if("percentage"===s)i=this.isUserInTestWithParentId(t,e.id,e.percentage||0);else if("userList"===s){i=!(!0===(null==(a=null==(r=o.user)?void 0:r.userData)?void 0:a.__isAnonymous))&&!0===(null==n?void 0:n[e.id])}c[d.id]={testId:d.id,assigned:i,assignedAt:Date.now()},d.name,e.name}return o.setABTestAssignments(c),c}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}isUserInTestWithParentId(t,e,n){if(!n)return!1;const i=`${t}_${e}`;let s=0;for(let r=0;r<i.length;r++){s=(s<<5)-s+i.charCodeAt(r),s|=0}return Math.abs(s)%100<n}getFilteredPlaylists(t){const e=xt(),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=xt(),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 xt().abTestAssignments||{}}isPlaylistAvailable(t){const e=xt(),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=xt(),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 ke{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 Te{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}=It(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=bt.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>Ot)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 Ae extends xe{constructor(t,n){super(t),e(this,"playlistLoader"),e(this,"storageManager"),this.playlistLoader=new Te,this.storageManager=n||bt.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;const l=xt();l.updateWatchedPlaylist(t,e,n);const c=null==(s=null==(i=l.userData)?void 0:i.watchedPlaylists)?void 0:s[t];if(!(null==(r=null==l?void 0:l.config)?void 0:r.token)||!(null==(a=null==l?void 0:l.user)?void 0:a.id)||(null==(o=null==l?void 0:l.user)?void 0:o.__isAnonymous))return void(c&&this.persistAnonymousWatchedPlaylist(t,c));const d=`https://player.saltfish.ai/clients/${l.config.token}/users/${l.user.id}/playlists/${t}`;try{const t=await fetch(d,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({status:e,currentStepId:(null==c?void 0:c.currentStepId)??null})});if(!t.ok)throw new Error(`Failed to update watched playlist status: ${t.statusText} (${t.status})`)}catch(h){console.error(`PlaylistManager: Error updating watched playlist status for ${t}:`,h)}}persistAnonymousWatchedPlaylist(t,e){if("undefined"==typeof window)return;const n=this.storageManager.getAnonymousUserData()||{userId:"anonymous",userData:{},watchedPlaylists:{},timestamp:Date.now()};n.watchedPlaylists||(n.watchedPlaylists={}),n.watchedPlaylists[t]=e,n.timestamp=Date.now();this.storageManager.setAnonymousUserData(n);e.status}async load(t,e){var n;try{const i=xt();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=xt(),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 ze{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=se(20),this.button.addEventListener("click",this.handleClick.bind(this)),this.playerElement.appendChild(this.button),this.updateVisibility(xt().isMinimized)}handleClick(){const t=xt(),e=!t.isMinimized;e?t.minimize():t.maximize(),e?this.minimize():this.maximize()}minimize(){this.button.innerHTML='<svg width="18" height="18" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M12 5v14M5 12h14" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg>'}maximize(){this.button.innerHTML=se(20)}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 Le{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='<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M8 5v14l11-7z" fill="currentColor"/></svg>',this.playButton.addEventListener("click",this.handlePlayClick.bind(this)),this.container.appendChild(this.playButton)}handlePlayClick(t){t&&t.stopPropagation();const e=xt();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 Ve{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='<svg width="18" height="18" viewBox="0 0 256 256" fill="currentColor" xmlns="http://www.w3.org/2000/svg"><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"/></svg>',this.button.addEventListener("click",this.handleClick.bind(this)),this.playerElement.appendChild(this.button),this.updateVisibility(xt().isMinimized)}handleClick(t){t.stopPropagation();xt().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 Oe{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=pt,this.errorOverlay.classList.add("sf-hidden");const t=document.createElement("div");t.className=mt;const e=document.createElement("p");e.className=ft,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(gt)}))}hide(){this.isVisible&&(this.errorOverlay.classList.remove(gt),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(`.${ft}`);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 De{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=`${yt}`,this.spinnerElement.innerHTML='\n <div class="sf-loading-spinner__content">\n <div class="sf-loading-spinner__icon"><svg width="60" height="60" viewBox="0 0 60 60" fill="none" xmlns="http://www.w3.org/2000/svg"><g transform="translate(10, 10) scale(0.656)"><g clip-path="url(#saltfish-clip)"><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"/><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"/></g><defs><clipPath id="saltfish-clip"><rect width="61" height="61" fill="white"/></clipPath></defs></g><circle cx="30" cy="30" r="28" stroke="black" stroke-width="2" fill="none" stroke-linecap="round" stroke-dasharray="8 6" stroke-opacity="0.3"><animateTransform attributeName="transform" type="rotate" values="0 30 30;360 30 30" dur="2s" repeatCount="indefinite"/></circle></svg></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 Fe{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 ze(this.playerElement),this.exitButton=new Ve(this.playerElement),t.create(this.playerElement);const i=this.createControlsContainer(this.playerElement);this.playPauseButton=new Le(i,t),this.createSaltfishLogo(this.playerElement),this.createAiBadge(this.playerElement),this.setupVideoContainerClickHandler(),e.create(),n.create(this.playerElement),this.initializeButtonManagement();const s=xt();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=xt();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=xt();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=xt(),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=Oe.getErrorMessage(t,e);this.errorDisplay||(this.errorDisplay=new Oe(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 De(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=xt().config)?void 0:e.showLogo))return;const n=document.createElement("div");n.className=ct,t.appendChild(n);const i=document.createElement("div");i.className=lt,i.innerHTML='\n <svg viewBox="0 0 59 14" fill="none" xmlns="http://www.w3.org/2000/svg">\n <path d="M20.5011 11.1967C19.8292 11.1967 19.2433 11.0697 18.7434 10.8156C18.2435 10.5616 17.8461 10.2133 17.5511 9.77082C17.2643 9.32012 17.0963 8.79977 17.0471 8.20976L18.1534 8.13601C18.2108 8.57032 18.3378 8.93907 18.5345 9.24227C18.7311 9.54547 18.9933 9.77492 19.3211 9.93061C19.6571 10.0863 20.0586 10.1642 20.5257 10.1642C20.9355 10.1642 21.2837 10.1109 21.5705 10.0044C21.8573 9.89783 22.0745 9.74214 22.222 9.53727C22.3777 9.33241 22.4555 9.08248 22.4555 8.78747C22.4555 8.51705 22.39 8.27941 22.2589 8.07455C22.136 7.86149 21.8942 7.66892 21.5337 7.49683C21.1813 7.31655 20.6568 7.14037 19.9603 6.96829C19.2884 6.7962 18.7516 6.60773 18.3501 6.40286C17.9567 6.198 17.6699 5.94807 17.4896 5.65306C17.3176 5.35806 17.2315 4.9934 17.2315 4.55909C17.2315 4.06742 17.3462 3.63721 17.5757 3.26845C17.8133 2.8915 18.1493 2.6006 18.5836 2.39573C19.0179 2.18267 19.5342 2.07615 20.1324 2.07615C20.7716 2.07615 21.3206 2.19906 21.7795 2.4449C22.2384 2.68254 22.603 3.01032 22.8735 3.42824C23.1439 3.84617 23.3119 4.32145 23.3774 4.85409L22.2712 4.92785C22.222 4.57548 22.1073 4.26409 21.927 3.99367C21.7549 3.71505 21.5173 3.4979 21.2141 3.3422C20.9109 3.18651 20.5421 3.10866 20.1078 3.10866C19.567 3.10866 19.1368 3.23977 18.8172 3.502C18.4976 3.75603 18.3378 4.092 18.3378 4.50992C18.3378 4.78034 18.3992 5.00569 18.5222 5.18597C18.6533 5.35806 18.8827 5.51376 19.2105 5.65306C19.5383 5.78417 20.0095 5.92758 20.6241 6.08328C21.3534 6.26356 21.9311 6.48071 22.3572 6.73474C22.7915 6.98058 23.0988 7.26739 23.2791 7.59517C23.4676 7.92295 23.5618 8.2958 23.5618 8.71372C23.5618 9.22178 23.4307 9.66429 23.1685 10.0412C22.9062 10.41 22.5457 10.6968 22.0868 10.9017C21.6279 11.0983 21.0993 11.1967 20.5011 11.1967ZM26.7873 11.1475C26.1154 11.1475 25.5787 10.9918 25.1771 10.6804C24.7838 10.369 24.5871 9.93471 24.5871 9.37748C24.5871 8.82025 24.751 8.38184 25.0788 8.06226C25.4066 7.74267 25.9269 7.51732 26.6398 7.38621L28.9507 6.95599C28.9507 6.40696 28.8196 5.99723 28.5574 5.72681C28.3033 5.45639 27.9182 5.32118 27.4019 5.32118C26.9512 5.32118 26.5948 5.42362 26.3325 5.62848C26.0703 5.82515 25.89 6.11196 25.7917 6.48891L24.6977 6.40286C24.8207 5.78827 25.1157 5.2925 25.5827 4.91555C26.058 4.53041 26.6644 4.33784 27.4019 4.33784C28.2378 4.33784 28.877 4.57548 29.3195 5.05076C29.762 5.51785 29.9832 6.16522 29.9832 6.99287V9.68478C29.9832 9.83228 30.0078 9.93881 30.057 10.0044C30.1143 10.0617 30.2045 10.0904 30.3274 10.0904H30.5855V11C30.5527 11.0082 30.4995 11.0123 30.4257 11.0123C30.352 11.0205 30.2741 11.0246 30.1922 11.0246C29.8972 11.0246 29.6554 10.9795 29.467 10.8894C29.2867 10.791 29.1556 10.6435 29.0736 10.4469C28.9917 10.242 28.9507 9.97568 28.9507 9.6479L29.0736 9.67248C29.0163 9.9511 28.877 10.2051 28.6557 10.4346C28.4344 10.6558 28.1599 10.832 27.8322 10.9631C27.5044 11.086 27.1561 11.1475 26.7873 11.1475ZM26.8857 10.2379C27.32 10.2379 27.6887 10.156 27.9919 9.99207C28.3033 9.81999 28.541 9.59054 28.7049 9.30373C28.8688 9.00873 28.9507 8.68095 28.9507 8.32039V7.8533L26.8365 8.24663C26.394 8.32858 26.0867 8.4556 25.9146 8.62768C25.7507 8.79157 25.6688 9.00873 25.6688 9.27915C25.6688 9.58234 25.7753 9.81999 25.9884 9.99207C26.2096 10.156 26.5087 10.2379 26.8857 10.2379ZM32.6507 11C32.2738 11 31.9665 10.9017 31.7288 10.705C31.4912 10.5083 31.3724 10.1969 31.3724 9.77082V2.27281H32.4049V9.68478C32.4049 9.81589 32.4377 9.91832 32.5032 9.99207C32.577 10.0576 32.6794 10.0904 32.8105 10.0904H33.3759V11H32.6507ZM36.3546 11C35.7646 11 35.3262 10.8648 35.0394 10.5944C34.7608 10.324 34.6215 9.90193 34.6215 9.32831V2.96116H35.654V9.30373C35.654 9.59873 35.7195 9.8036 35.8506 9.91832C35.9817 10.033 36.1825 10.0904 36.4529 10.0904H37.3871V11H36.3546ZM33.6627 5.39493V4.48534H37.3871V5.39493H33.6627ZM38.6952 11V3.89533C38.6952 3.41186 38.8345 3.02261 39.1132 2.72761C39.3918 2.42441 39.8261 2.27281 40.4161 2.27281H41.4486V3.18241H40.4898C40.2358 3.18241 40.0432 3.25206 39.9121 3.39137C39.7892 3.53068 39.7277 3.72325 39.7277 3.96908V11H38.6952ZM37.8102 5.39493V4.48534H41.3626V5.39493H37.8102ZM42.7147 11V4.48534H43.7472V11H42.7147ZM42.6901 3.46512V2.26052H43.7717V3.46512H42.6901ZM47.6594 11.1475C47.0776 11.1475 46.5818 11.0533 46.1721 10.8648C45.7706 10.6763 45.4551 10.4182 45.2256 10.0904C45.0044 9.75443 44.8774 9.37338 44.8446 8.94727L45.9263 8.87352C45.9918 9.26685 46.1598 9.58234 46.4302 9.81999C46.7007 10.0494 47.1104 10.1642 47.6594 10.1642C48.1019 10.1642 48.4543 10.0945 48.7165 9.9552C48.9869 9.80769 49.1221 9.57415 49.1221 9.25456C49.1221 9.08248 49.0812 8.93907 48.9992 8.82435C48.9173 8.70963 48.7575 8.61129 48.5198 8.52935C48.2822 8.43921 47.9298 8.35316 47.4627 8.27122C46.84 8.15649 46.3483 8.01719 45.9877 7.8533C45.6354 7.68121 45.3813 7.47225 45.2256 7.22641C45.0781 6.97238 45.0044 6.67328 45.0044 6.32911C45.0044 5.7473 45.2174 5.27202 45.6436 4.90326C46.0697 4.52631 46.6761 4.33784 47.4627 4.33784C47.9954 4.33784 48.442 4.43617 48.8026 4.63284C49.1713 4.82132 49.4581 5.07535 49.663 5.39493C49.876 5.70633 50.0153 6.0505 50.0809 6.42745L48.9992 6.5012C48.9501 6.27175 48.8599 6.07098 48.7288 5.8989C48.5977 5.71862 48.4256 5.57931 48.2125 5.48098C47.9995 5.37445 47.7455 5.32118 47.4505 5.32118C46.9834 5.32118 46.6392 5.41132 46.4179 5.5916C46.1967 5.77188 46.0861 6.00133 46.0861 6.27994C46.0861 6.493 46.1352 6.66919 46.2336 6.80849C46.3401 6.93961 46.5081 7.05023 46.7375 7.14037C46.967 7.22232 47.2743 7.29607 47.6594 7.36162C48.3232 7.47635 48.8394 7.61565 49.2082 7.77955C49.5769 7.94344 49.8351 8.1442 49.9826 8.38184C50.1301 8.61949 50.2038 8.91039 50.2038 9.25456C50.2038 9.6561 50.0891 10.0003 49.8596 10.2871C49.6384 10.5657 49.3352 10.7787 48.9501 10.9262C48.5731 11.0738 48.1429 11.1475 47.6594 11.1475ZM51.3058 11V2.27281H52.3383V5.92348L52.2154 5.8989C52.2973 5.53834 52.4366 5.24334 52.6333 5.01389C52.8299 4.78444 53.0717 4.61645 53.3585 4.50992C53.6453 4.3952 53.9608 4.33784 54.305 4.33784C54.7721 4.33784 55.1654 4.44437 55.485 4.65743C55.8128 4.86229 56.0586 5.1532 56.2225 5.53014C56.3946 5.8989 56.4806 6.32501 56.4806 6.80849V11H55.4481V7.1035C55.4481 6.47252 55.3334 6.00543 55.1039 5.70223C54.8827 5.39903 54.5426 5.24743 54.0837 5.24743C53.5593 5.24743 53.1372 5.40723 52.8177 5.72681C52.4981 6.0464 52.3383 6.50939 52.3383 7.11579V11H51.3058Z" fill="white"/>\n <rect width="13.1858" height="13.1858" rx="0.670462" fill="white"/>\n <path d="M10.2634 6.59634C10.2634 8.62107 8.62202 10.2624 6.59729 10.2624C4.57256 10.2624 6.15483 8.62107 6.15483 6.59634C6.15483 4.57161 4.57256 2.93024 6.59729 2.93024C8.62202 2.93024 10.2634 4.57161 10.2634 6.59634Z" fill="black"/>\n <path d="M5.78564 6.55629C5.78564 7.83069 4.76169 8.86379 3.49858 8.86379C2.23547 8.86379 3.22255 7.83069 3.22255 6.55629C3.22255 5.28189 2.23547 4.24878 3.49858 4.24878C4.76169 4.24878 5.78564 5.28189 5.78564 6.55629Z" fill="black"/>\n </svg>\n ',t.appendChild(i),i.addEventListener("click",(t=>{var e;t.stopPropagation();const n=xt();"playing"===n.currentState&&n.pause();const i=null==(e=n.config)?void 0:e.token;i?window.open(`https://www.saltfish.ai/?utm_source=player&utm_medium=logo&clientId=${i}`,"_blank"):(console.warn("UIManager: No token available, falling back to saltfish.ai homepage"),window.open("https://www.saltfish.ai/?utm_source=player&utm_medium=logo","_blank"))}))}createAiBadge(t){const e="Contains AI-generated content";t.setAttribute("data-ai-generated","true");const n=document.createElement("div");n.className=dt,n.setAttribute("role","img"),n.setAttribute("aria-label",e),n.innerHTML='\n <svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" aria-hidden="true">\n <circle cx="12" cy="12" r="11" fill="#ffffff" stroke="rgba(0, 0, 0, 0.4)" stroke-width="1"/>\n <path fill-rule="evenodd" clip-rule="evenodd" d="M9.4 8 L11.5 8 L14 16 L11.7 16 L11.28 14.55 L9.62 14.55 L9.2 16 L6.9 16 Z M10.45 10.2 L11.15 12.85 L9.75 12.85 Z" fill="#1d1d1b"/>\n <path d="M14.8 8h2.3v8h-2.3z" fill="#1d1d1b"/>\n </svg>\n ';const i=document.createElement("span");let s;i.className=ht,i.textContent=e,i.setAttribute("aria-hidden","true"),n.appendChild(i),n.addEventListener("click",(t=>{t.stopPropagation();const e=i.classList.toggle(ut);window.clearTimeout(s),e&&(s=window.setTimeout((()=>{i.classList.remove(ut)}),3e3))})),t.appendChild(n)}initializeButtonManagement(){this.playerElement&&this.videoManager?(this.storeUnsubscribe=Et.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=xt();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=xt();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=xt();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.classList.add("sf-compact-label--clickable"),this.compactLabel.addEventListener("click",(t=>{t.stopPropagation(),t.preventDefault();const e=xt();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 Ue=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(Ue,"STEP_TIMEOUT_MS",Tt);let Be=Ue;class Ne{createManagers(){const t=bt.getInstance(),e=new Ie(t),n=new Gt,i=new oe,s=new ke,r=new Me(s),a=new Ae(s,t),o=new _e(s),l=new be,c=new Ee,d=new Pe,h=new Ce,u=new Be((()=>{}));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 Fe(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 Re=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),e(this,"initializationPromise",null),t.instance)throw new Error("SaltfishPlayer is a singleton. Use getInstance()");this.managerFactory=new Ne;const n=this.managerFactory.createManagers();this.playerInitializationService=new Bt(n),this.userManagementService=new Rt(n),this.playlistOrchestrator=new $t(n),this.stateMachineActionHandler=new Xt(n),this.managerOrchestrator=new Zt(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())),Et.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)return this.initializationPromise||(this.initializationPromise=(async()=>{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 this.initializationPromise=null,e}})()),this.initializationPromise;console.warn("Saltfish playlist Player is already initialized")}async identifyUser(t,e){this.initializationPromise&&await this.initializationPromise,this.userManagementService.identifyUser(t,e)}async identifyAnonymous(t){this.initializationPromise&&await this.initializationPromise,await this.userManagementService.identifyAnonymous(t)}async startPlaylist(t,e){await this.playlistOrchestrator.startPlaylist(t,e)}resetPlaylist(){this.playlistOrchestrator.resetPlaylist()}closePlaylist(){this.managerOrchestrator.cleanupPlaylist();Et.getState().resetForNewPlaylist()}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(Re,"instance",null);let He=Re;const $e=Object.freeze(Object.defineProperty({__proto__:null,SaltfishPlayer:He},Symbol.toStringTag,{value:"Module"})),Ye="0.3.93";const Xe=function(){const t=He.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:()=>Ye};return r.__dev__={getDeviceInfo:()=>Kt.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=Xe),Xe}));
|
|
8
8
|
|