{"version":3,"file":"shoppable-videos-section.min.js","mappings":"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","sources":["webpack://lange/../node_modules/@integrabeauty/assert/src/index.ts","webpack://lange/./lib/dom-ready.ts","webpack://lange/./sections/shoppable-videos/shoppable-video-player/index.ts","webpack://lange/./lib/video.ts","webpack://lange/./sections/shoppable-videos/index.ts"],"sourcesContent":["/**\n * Throws an assertion error if the given condition is falsy.\n *\n * @param expression any expression, although one that evaluates to true or false is preferred by\n * convention\n * @param message optional error text\n */\nexport function assert(expression: unknown, message?: string) {\n  if (!expression) {\n    throw new AssertionError(message);\n  }\n}\n\nexport class AssertionError extends Error {\n  constructor(message = 'Assertion error') {\n    super(message);\n    this.name = this.constructor.name;\n  }\n}\n","/**\n * Releases the handle returned from the ready() function.\n *\n * This is idempotent. Additional calls are pointless but harmless.\n */\nexport type ReleaseHandle = () => void;\n\n/**\n * A subset of events that pertain to document ready state.\n */\ntype LoadingEventMap = Pick<DocumentEventMap, 'DOMContentLoaded' | 'load'>;\n\n/**\n * Calls the provided callback when the document is ready. This works both when the document is\n * already ready and when it is not, so callers do not have to care. This exists because it ensures\n * that each caller consistently expresses its dependency on document readiness, and to save a bit\n * of boilerplate.\n *\n * A document is considered ready when it has been parsed. This corresponds to the ready state of\n * 'interactive'. When the document has been fully loaded, the ready state is 'complete'. The\n * callback runs either way, so callers do not have to check which one they are in.\n *\n * Ready means the html is parsed and the DOM is there to query. It does not mean the page's other\n * scripts have run. Deferred scripts and module scripts run after the ready state turns\n * 'interactive' and before DOMContentLoaded fires, so a callback here can run before them. When a\n * caller needs some other script to have run already, this is the wrong tool, and it should wait on\n * whatever that script produces instead.\n *\n * That remedy has a catch of its own when the calling bundle is loaded with async. An async bundle\n * can execute after DOMContentLoaded has already fired, so a plain listener for that event never\n * runs and the work silently never happens. Nothing here can detect that, because by the time this\n * file executes the event is long gone. Catching it needs something registered at parse time,\n * before any bundle loads.\n *\n * There is a second trap right next to that one, and it applies only when waiting for\n * DOMContentLoaded. The ready state stays 'interactive' after DOMContentLoaded has fired, all the\n * way until 'complete', so the ready state cannot tell you whether DOMContentLoaded is still coming\n * or has already gone. Waiting for load is not exposed to this, because the ready state turns\n * 'complete' and load fires in the same task, so seeing 'complete' means load has fired too.\n *\n * When the document is already ready, the callback is invoked via setTimeout. This way, if the\n * callback throws, the error surfaces to the global error handler in a way that is similar to what\n * happens when an event listener throws.\n *\n * We might one day want to move this to an NPM library.\n *\n * Beware of a quirk here. setTimeout yields, and the busier the frontend, the longer it takes to\n * fire. Page load is exactly when the frontend is busiest. The timeout is a floor and not a\n * guarantee, so there is no real bound on how long that yield lasts. What this means is that using\n * this library can introduce more delay than you might expect. Compare code that runs on async load\n * and checks ready state and invokes immediately to code that runs after setTimeout. The former\n * runs in the same tick, the latter runs in \"some later tick\". That later tick can be surprisingly\n * much later. That can cause initial paint issues.\n *\n * @see https://developer.mozilla.org/en-US/docs/Web/API/Document/readyState\n * @see https://developer.mozilla.org/en-US/docs/Web/API/Document/DOMContentLoaded_event\n * @see https://html.spec.whatwg.org/multipage/parsing.html#the-end\n */\nexport function ready(callback: (event?: Event) => void,\n  type: keyof LoadingEventMap = 'DOMContentLoaded') {\n  if (document.readyState === 'complete' || (type === 'DOMContentLoaded' &&\n    document.readyState === 'interactive')) {\n    const timer = setTimeout(callback, 0);\n    const handle: ReleaseHandle = () => clearTimeout(timer);\n    return handle;\n  } else {\n    addEventListener(type, callback);\n    const handle: ReleaseHandle = () => removeEventListener(type, callback);\n    return handle;\n  }\n}\n","import { assert } from '@integrabeauty/assert';\nimport type { CustomElement } from '@integrabeauty/custom-elements';\nimport { ready, type ReleaseHandle } from '../../../lib/dom-ready.js';\nimport { play } from '../../../lib/video.js';\nimport html from './index.html';\nimport styles from './index.scss';\n\ninterface ShoppableVideo {\n  affiliate_display_name: string;\n\n  alt: string | null;\n  aspect_ratio: number;\n\n  /**\n   * url to the .vtt captions file\n   */\n  captions: string;\n\n  /**\n   * millisecond duration of the video\n   */\n  duration: number;\n\n  /**\n   * ID of the video media\n   */\n  id: number;\n\n  /**\n   * type of media file, should be 'video'\n   */\n  media_type: string;\n  metaobject_handle: string;\n  metaobject_id: number;\n  metaobject_type: string;\n  metaobject_url: string | null;\n  position: null;\n\n  /**\n   * URL of the poster image of the video\n   */\n  preview_image: string;\n  primary_variant: {\n    id: number;\n\n    /**\n     * URL of the variant image, or null when the section could not resolve one\n     */\n    image: string | null;\n    options: string;\n    product_id: number;\n  };\n  products: {\n    /**\n     * URL of product image, or null when the section could not resolve one\n     */\n    featured_image: string | null;\n    handle: string;\n    id: number;\n    subtitle: string;\n    title: string;\n  }[];\n  sources: {\n    /**\n     * file type\n     *\n     * @example 'mp4'\n     */\n    format: string;\n    height: number;\n    mime_type: string;\n    url: string;\n    width: number;\n  }[];\n\n  /**\n   * metaobject handles are a snake case composite of metaobject type and a special ID. This field\n   * isolates only the id and strips out the metaobject type. it's an alphanumeric value.\n   *\n   * @example 'r1o6yxen'\n   */\n  video_id: string;\n}\n\ninterface VideoPlayState {\n  [id: string]: 'paused' | 'playing' | 'promise-to-play';\n}\n\n/**\n * A fullscreen feed of short videos, in the style of Instagram/TikTok.\n *\n * Each video has a carousel of the products it features. The tap to view product details of one of\n * the products in the carousel is why this is called \"shoppable\" as that is low friction.\n *\n * It shows as a modal whose open state and current video are tied to the URL and browser history.\n * That lets a shared or advertised link open straight to a specific video, and lets back and\n * forward navigation open, close, or switch the player to match.\n *\n * The video list is read from a JSON script on the page.\n *\n * The shopper moves between videos by keyboard, mouse, or touchscreen.\n *\n * As a video is watched it emits progress events at a few view milestones, which other code\n * consumes for analytics.\n */\nclass ShoppableVideoPlayer extends HTMLElement implements CustomElement {\n  public static get observedAttributes() {\n    return [\n      'hidden'\n    ];\n  }\n\n  declare readonly dataset: {\n    /**\n     * Play the video with the specified id\n     */\n    videoId: string;\n  };\n\n  private declare videos: ShoppableVideo[];\n  private muted = false;\n  private paused = false;\n  private videoPlayState: VideoPlayState = {};\n  private watchedAnalyticsCache: { [id: string]: boolean; } = {};\n  private declare loaderTimer: ReturnType<typeof setTimeout>;\n  private declare scrollTimer: ReturnType<typeof setTimeout>;\n  private lastKnownScrollPosition = 0;\n  private lastKnownTouchPosition = 0;\n  private lastKnownProductScrollPosition = 0;\n\n  private videoWidth = 600;\n\n  private mouseDownOnProducts = false;\n\n  private onVideoEventBound = this.onVideoEvent.bind(this);\n  private onVideoClickBound = this.onVideoClick.bind(this);\n  private onTimeUpdateBound = this.onTimeUpdate.bind(this);\n  private onPlayClickBound = this.onPlayClick.bind(this);\n  private onCaptionCueChangeBound = this.onCaptionCueChange.bind(this);\n  private onCaptionsControlClickBound = this.onCaptionsControlClick.bind(this);\n  private onCloseClickBound = this.onCloseClick.bind(this);\n  private onMuteClickBound = this.onMuteClick.bind(this);\n  private onPreviousClickBound = this.onPreviousClick.bind(this);\n  private onNextClickBound = this.onNextClick.bind(this);\n  private onWheelBound = this.onWheel.bind(this);\n  private onTouchStartBound = this.onTouchStart.bind(this);\n  private onTouchMoveBound = this.onTouchMove.bind(this);\n  private onMouseDownBound = this.onMouseDown.bind(this);\n  private onMouseMoveBound = this.onMouseMove.bind(this);\n  private onProductMoveBound = this.onProductMove.bind(this);\n  private onProductsWheelBound = this.onProductsWheel.bind(this);\n  private onPopStateBound = this.onPopState.bind(this);\n  private onReadyBound = this.onReady.bind(this);\n  private onWindowResizeBound = this.onWindowResize.bind(this);\n  private onScreenChangeBound = this.onScreenChange.bind(this);\n  private onKeyboardEventBound = this.onKeyboardEvent.bind(this);\n  private declare releaseReady: ReleaseHandle;\n\n  public connectedCallback() {\n    this.initializeShadowRoot();\n\n    addEventListener('popstate', this.onPopStateBound);\n\n    this.releaseReady = ready(this.onReadyBound);\n\n    this.addEventListener('keydown', this.onKeyboardEventBound);\n    this.addEventListener('keyup', this.onKeyboardEventBound);\n\n    addEventListener('resize', this.onWindowResizeBound);\n    addEventListener('change', this.onScreenChangeBound);\n\n    this.init();\n  }\n\n  public disconnectedCallback() {\n    if (this.releaseReady) {\n      this.releaseReady();\n    }\n\n    removeEventListener('popstate', this.onPopStateBound);\n\n    const playEl = this.shadowRoot.getElementById('play');\n    playEl?.removeEventListener('click', this.onPlayClickBound);\n\n    const closeEl = this.shadowRoot.getElementById('close');\n    closeEl?.removeEventListener('click', this.onCloseClickBound);\n\n    const muteEl = this.shadowRoot.getElementById('mute');\n    muteEl?.removeEventListener('click', this.onMuteClickBound);\n\n    const previousEl = this.shadowRoot.getElementById('previous');\n    previousEl?.removeEventListener('click', this.onPreviousClickBound);\n\n    const nextEl = this.shadowRoot.getElementById('next');\n    nextEl?.removeEventListener('click', this.onNextClickBound);\n\n    const videosEl = this.shadowRoot.querySelector<HTMLElement>('.videos');\n    videosEl?.removeEventListener('touchstart', this.onTouchStartBound);\n    videosEl?.removeEventListener('touchmove', this.onTouchMoveBound);\n    videosEl?.removeEventListener('mousedown', this.onMouseDownBound);\n    videosEl?.removeEventListener('mousemove', this.onMouseMoveBound);\n    videosEl?.removeEventListener('wheel', this.onWheelBound);\n\n    const captionsControlEl = this.shadowRoot.getElementById('captions-control');\n    captionsControlEl?.removeEventListener('click', this.onCaptionsControlClickBound);\n\n    this.removeEventListener('keydown', this.onKeyboardEventBound);\n    this.removeEventListener('keyup', this.onKeyboardEventBound);\n\n    removeEventListener('resize', this.onWindowResizeBound);\n    removeEventListener('change', this.onScreenChangeBound);\n\n    const videoEl = this.shadowRoot.querySelector<HTMLVideoElement>('.active video');\n    if (videoEl) {\n      this.removeVideoListeners(videoEl);\n    }\n\n    const productsEl = this.shadowRoot.querySelectorAll<HTMLElement>('.products.scrollable');\n    for (const productEl of productsEl) {\n      productEl.removeEventListener('wheel', this.onProductsWheelBound);\n    }\n  }\n\n  private initializeShadowRoot() {\n    if (!this.shadowRoot) {\n      this.attachShadow({ mode: 'open' });\n      this.shadowRoot.innerHTML = `<style>${styles}</style>${html}`;\n    }\n  }\n\n  private onKeyboardEvent(event: KeyboardEvent) {\n    if (event.type === 'keydown') {\n      return;\n    }\n\n    if (event.code === 'Escape') {\n      this.closePlayer();\n    } else if (['ArrowLeft', 'ArrowUp'].includes(event.code)) {\n      this.navigateToVideo(false);\n    } else if (['ArrowRight', 'ArrowDown'].includes(event.code)) {\n      this.navigateToVideo(true);\n    }\n  }\n\n  private showPlayer() {\n    const currentSection = this.closest('section');\n    if (currentSection instanceof HTMLElement) {\n      const carousel = currentSection.querySelector('carousel-element');\n\n      if (carousel instanceof HTMLElement) {\n        carousel.inert = true;\n      }\n    }\n\n    const event = new Event('modal-open-requested', { bubbles: true, composed: true });\n    this.dispatchEvent(event);\n\n    // put keyboard focus on the first interactive element\n    const closeButton = this.shadowRoot.querySelector<HTMLButtonElement>('#close');\n    closeButton.focus({ focusVisible: true });\n  }\n\n  public attributeChangedCallback(name: string, oldValue: string, newValue: string) {\n    this.initializeShadowRoot();\n\n    if (this.isConnected && oldValue !== newValue) {\n      // We used to watch data-hidden here and treat any falsy newValue as un-hiding. That does not\n      // work with the native attribute, because setting it gives us an empty string, which is also\n      // falsy, so we would show the player when we meant to hide it. Read the property instead. It\n      // is already in sync with the attribute by the time we get here.\n\n      if (name === 'hidden' && !this.hidden) {\n        this.showPlayer();\n      }\n\n      if (!this.videos) {\n        this.init();\n      }\n\n      if (this.dataset.videoId) {\n        // close the player if there are no videos\n        if (this.videos.length === 0) {\n          this.closePlayer();\n          return;\n        }\n\n        let index = this.videos.findIndex(v => v.video_id === this.dataset.videoId);\n        if (index === -1) {\n          // If the video no longer exists (e.g., when a stale URL is shared or advertised), fall\n          // back to showing the first video\n          index = 0;\n        }\n\n        const videoId = this.videos[index].video_id;\n\n        this.activatePlayerAtIndex(index);\n        this.activateVideo(videoId);\n        this.updateVideoContainerWidth({ type: 'attributeChanged' });\n      }\n    }\n  }\n\n  private activatePlayerAtIndex(index: number) {\n    let prevIndex = index - 1;\n    if (prevIndex < 0) {\n      prevIndex = this.videos.length - 1;\n    }\n\n    let nextIndex = index + 1;\n    if (nextIndex >= this.videos.length) {\n      nextIndex = 0;\n    }\n\n    const videosEl = this.shadowRoot.querySelector('.videos');\n    const currentVideo = this.createVideoWrapperElement(this.videos[index], index);\n    videosEl.appendChild(currentVideo);\n\n    if (nextIndex !== index) {\n      const nextVideo = this.createVideoWrapperElement(this.videos[nextIndex], nextIndex);\n      videosEl.appendChild(nextVideo);\n    }\n\n    if ((prevIndex !== index) && (prevIndex !== nextIndex)) {\n      // we add previous in the end to allow current to load first\n      const previousVideo = this.createVideoWrapperElement(this.videos[prevIndex], prevIndex);\n      videosEl.insertBefore(previousVideo, currentVideo);\n    }\n  }\n\n  private showLoader() {\n    clearTimeout(this.loaderTimer);\n    this.loaderTimer = setTimeout(() => {\n      const loader = this.shadowRoot.getElementById('loader');\n      loader?.classList.remove('display-hide');\n    }, 300);\n  }\n\n  private hideLoader() {\n    clearTimeout(this.loaderTimer);\n\n    const loader = this.shadowRoot.getElementById('loader');\n    loader?.classList.add('display-hide');\n  }\n\n  private activateVideo(id: string) {\n    assert(id, 'activate video invalid id');\n\n    // Since the onScroll method will activate videos on each event emitted, we must first check if\n    // that video ID is already active before proceeding.\n    const activeEl = this.shadowRoot.querySelector<HTMLElement>('.video.active');\n    if (activeEl?.dataset.id === id) {\n      return;\n    }\n\n    // On load there is no initially active video, so we must confirm the element was found\n    if (activeEl) {\n      activeEl.classList.remove('active');\n      const videoEl = activeEl.querySelector('video');\n      videoEl.pause();\n      videoEl.textTracks[0].mode = 'disabled';\n      this.videoPlayState[videoEl.parentElement.dataset.id] = 'paused';\n      videoEl.currentTime = 0;\n      this.removeVideoListeners(videoEl);\n\n      const products = videoEl.parentElement.querySelector<HTMLElement>('.products');\n      if (products) {\n        products.inert = true;\n      }\n    }\n\n    const targetVideoDiv = this.shadowRoot.querySelector(`[data-id=\"${id}\"]`);\n    if (!targetVideoDiv) {\n      return;\n    }\n\n    targetVideoDiv.classList.add('active');\n\n    // The progress bar is shared by every video, and only the active video's time updates move it.\n    // Without a reset it keeps the previous video's progress until the new one plays, and when the\n    // browser refuses to autoplay the new one, that leftover progress stays on screen.\n    this.updateProgress(0);\n\n    const targetProducts = targetVideoDiv.querySelector<HTMLElement>('.products');\n    if (targetProducts) {\n      targetProducts.inert = false;\n    }\n\n    const video = targetVideoDiv.querySelector('video');\n    this.addVideoListeners(video);\n    video.muted = this.muted;\n    video.textTracks[0].mode = 'showing';\n\n    if (this.dataset.videoId !== id) {\n      this.dataset.videoId = id;\n    }\n\n    updateUrlParamVideoId(id);\n    this.playVideo(video);\n  }\n\n  private navigateToVideo(forward: boolean) {\n    this.hideLoader();\n    const videos = this.shadowRoot.querySelector('.videos');\n    if (!videos) {\n      return;\n    }\n\n    const active = videos.querySelector<HTMLElement>('.video.active');\n    if (!active) {\n      return;\n    }\n\n    // Compute the index to which to navigate\n    let targetIndex = parseInt(active.dataset.index, 10) + (forward ? 1 : -1);\n\n    // Wrap around the index if out of bounds to achieve infinite looping.\n    if (forward) {\n      if (targetIndex >= this.videos.length) {\n        targetIndex = 0;\n      }\n    } else {\n      if (targetIndex < 0) {\n        targetIndex = this.videos.length - 1;\n      }\n    }\n\n    const target = videos.querySelector<HTMLElement>(`.video[data-index=\"${targetIndex}\"`);\n    this.activateVideo(target.dataset.id);\n\n    let addIndex = forward ? targetIndex + 1 : targetIndex - 1;\n    if (addIndex >= this.videos.length) {\n      addIndex = 0;\n    } else if (addIndex < 0) {\n      addIndex = this.videos.length - 1;\n    }\n\n    const toBeRemoved = forward ? videos.firstElementChild : videos.lastElementChild;\n    videos.removeChild(toBeRemoved);\n\n    let toBeAdded: Element;\n\n    if (toBeRemoved.classList.contains('active')) {\n      // if we have less than 4 videos, it can happen that the video to be removed is the active\n      // video; we need to add the active video back; it keeps the listeners and css classes\n      toBeAdded = toBeRemoved;\n    } else {\n      // create a new video element to be added\n      toBeAdded = this.createVideoWrapperElement(this.videos[addIndex], addIndex);\n    }\n\n    if (forward) {\n      videos.appendChild(toBeAdded);\n    } else {\n      videos.prepend(toBeAdded);\n    }\n  }\n\n  private onNextClick(_event: MouseEvent) {\n    this.navigateToVideo(true);\n  }\n\n  private onPreviousClick(_event: MouseEvent) {\n    this.navigateToVideo(false);\n  }\n\n  private onCaptionCueChange(_event: Event) {\n    const activeVideo = this.shadowRoot.querySelector<HTMLVideoElement>('.video.active video');\n    if (!activeVideo) {\n      return;\n    }\n\n    // Carefully obtain the cue. We have to be careful here because of poor browser support and\n    // strange situations where activeCues is undefined. We also have to hard cast the cue type from\n    // the base TextTrackCue type into the VTTCue subtype so as to gain access to the cue.text\n    // property. This hard cast is not safe.\n\n    let cue;\n    if (activeVideo.textTracks?.length > 0) {\n      const track = activeVideo.textTracks[0];\n      if (track?.activeCues?.length > 0) {\n        cue = <VTTCue>track.activeCues[0];\n      }\n    }\n\n    const captions = this.shadowRoot.querySelector('.video.active .captions');\n    captions.textContent = cue?.text || '';\n\n    if (cue?.text) {\n      captions.classList.remove('empty');\n    } else {\n      captions.classList.add('empty');\n    }\n  }\n\n  private onCaptionsControlClick(_event: MouseEvent) {\n    const captionsOffIcon = this.shadowRoot.getElementById('captions-off');\n    const captionsOnIcon = this.shadowRoot.getElementById('captions-on');\n    const videos = this.shadowRoot.querySelector('.videos');\n\n    // Toggle captions\n    if (videos.classList.contains('hide-captions')) {\n      captionsOffIcon.classList.add('display-hide');\n      captionsOnIcon.classList.remove('display-hide');\n      videos.classList.remove('hide-captions');\n      writeCaptionsEnabled(true);\n      this.setVideoStatus('Captions enabled');\n    } else {\n      captionsOffIcon.classList.remove('display-hide');\n      captionsOnIcon.classList.add('display-hide');\n      videos.classList.add('hide-captions');\n      writeCaptionsEnabled(false);\n      this.setVideoStatus('Captions disabled');\n    }\n  }\n\n  private onReady() {\n    if (!this.isConnected) {\n      return;\n    }\n\n    const playEl = this.shadowRoot.getElementById('play');\n    playEl.addEventListener('click', this.onPlayClickBound);\n\n    const closeEl = this.shadowRoot.getElementById('close');\n    closeEl.addEventListener('click', this.onCloseClickBound);\n\n    const muteEl = this.shadowRoot.getElementById('mute');\n    muteEl.addEventListener('click', this.onMuteClickBound);\n\n    const previousEl = this.shadowRoot.getElementById('previous');\n    previousEl.addEventListener('click', this.onPreviousClickBound);\n\n    const nextEl = this.shadowRoot.getElementById('next');\n    nextEl.addEventListener('click', this.onNextClickBound);\n\n    const videosEl = this.shadowRoot.querySelector<HTMLElement>('.videos');\n    videosEl.addEventListener('touchstart', this.onTouchStartBound, { passive: true });\n    videosEl.addEventListener('touchmove', this.onTouchMoveBound, { passive: false });\n    videosEl.addEventListener('mousedown', this.onMouseDownBound);\n    videosEl.addEventListener('mousemove', this.onMouseMoveBound);\n    videosEl.addEventListener('wheel', this.onWheelBound, { passive: false });\n\n    const captionsControlEl = this.shadowRoot.getElementById('captions-control');\n    captionsControlEl.addEventListener('click', this.onCaptionsControlClickBound);\n\n    const captionsEnabled = readCaptionsEnabled();\n    if (captionsEnabled) {\n      const captionsOffIcon = this.shadowRoot.getElementById('captions-off');\n      const captionsOnIcon = this.shadowRoot.getElementById('captions-on');\n      const videos = this.shadowRoot.querySelector('.videos');\n\n      captionsOffIcon.classList.add('display-hide');\n      captionsOnIcon.classList.remove('display-hide');\n      videos.classList.remove('hide-captions');\n    }\n\n    this.updateIconPositions();\n  }\n\n  private onScreenChange(event: Event) {\n    this.updateVideoContainerWidth(event);\n    this.updateIconPositions();\n  }\n\n  private onWindowResize(event: Event) {\n    this.updateVideoContainerWidth(event);\n    this.updateIconPositions();\n  }\n\n  private updateVideoContainerWidth(event: Pick<Event, 'type'>) {\n    const width = Math.floor(innerHeight * 0.56);\n    if (innerWidth < 600) {\n      this.videoWidth = innerWidth;\n    } else if (width < 600) {\n      this.videoWidth = width;\n    } else {\n      this.videoWidth = 600;\n    }\n\n    const containerEl = this.shadowRoot.querySelector<HTMLElement>('.container');\n    containerEl.style.minWidth = `${this.videoWidth}px`;\n\n    const progressEl = this.shadowRoot.querySelector<HTMLElement>('.progress-bar');\n    progressEl.style.maxWidth = `${this.videoWidth}px`;\n\n    const productEl = this.shadowRoot.querySelector<HTMLElement>('.active .product.only-card');\n    if (productEl) {\n      productEl.style.width = `${this.videoWidth - 32}px`;\n    } else {\n      if (event.type === 'resize' || event.type === 'change') {\n        // do not log, this is normal, e.g. when resizing with devtools open\n      }\n    }\n\n    const captionsEl = this.shadowRoot.querySelector<HTMLElement>('.active .captions');\n    if (captionsEl) {\n      captionsEl.style.width = `${this.videoWidth - 32}px`;\n    } else {\n      if (event.type === 'resize' || event.type === 'change') {\n        // do not log, this is normal, e.g. when resizing with devtools open\n      }\n    }\n\n    const box = containerEl.getBoundingClientRect();\n    progressEl.style.left = `${box.left}px`;\n  }\n\n  private updateIconPositions() {\n    const closeEl = this.shadowRoot.getElementById('close');\n    const menuEl = this.shadowRoot.querySelector<HTMLElement>('.menu');\n\n    if (innerWidth > 767) {\n      const offset = (innerWidth - this.videoWidth) / 2 - 60;\n\n      closeEl.style.left = `${offset}px`;\n      menuEl.style.right = `${offset}px`;\n    } else {\n      closeEl.style.left = '16px';\n      menuEl.style.right = '16px';\n    }\n  }\n\n  private onPopState(_event: Event) {\n    const urlParams = new URLSearchParams(location.search);\n    const videoId = urlParams.get('video_id');\n    if (videoId) {\n      this.dataset.videoId = videoId;\n      this.hidden = false;\n    } else if (!this.hidden) {\n      // Go through closePlayer rather than just hiding. Hiding on its own leaves the carousel inert\n      // and leaves the modal manager thinking a modal is still open, so the backdrop and the scroll\n      // lock stay up with nothing on screen to explain them.\n      this.closePlayer();\n    }\n  }\n\n  private onMouseDown(event: MouseEvent) {\n    const products = this.shadowRoot.querySelector<HTMLElement>('.active .products');\n    if (!products) {\n      return;\n    }\n\n    const bounds = products.getBoundingClientRect();\n\n    if (event.clientY > bounds.y && event.clientY < bounds.y + bounds.height &&\n      event.clientX > bounds.x && event.clientX < bounds.x + bounds.width) {\n      this.lastKnownTouchPosition = event.pageX - products.offsetLeft;\n      this.lastKnownProductScrollPosition = products.scrollLeft;\n      this.mouseDownOnProducts = true;\n\n      return;\n    }\n\n    this.mouseDownOnProducts = false;\n    this.lastKnownTouchPosition = event.clientY;\n  }\n\n  private onMouseMove(event: MouseEvent) {\n    if (event.buttons === 1 && this.mouseDownOnProducts) {\n      return;\n    }\n\n    if (this.mouseDownOnProducts && event.buttons !== 1) {\n      this.mouseDownOnProducts = false;\n    }\n\n    if (event.buttons !== 1 || (this.lastKnownTouchPosition === 0 && !this.mouseDownOnProducts)) {\n      return;\n    }\n\n    clearTimeout(this.scrollTimer);\n\n    this.scrollTimer = setTimeout(() => {\n      if (this.lastKnownTouchPosition < event.clientY) {\n        this.navigateToVideo(false);\n      } else if (this.lastKnownTouchPosition > event.clientY) {\n        this.navigateToVideo(true);\n      }\n\n      this.lastKnownScrollPosition = 0;\n      clearTimeout(this.scrollTimer);\n    }, 100);\n  }\n\n  private onProductMove(event: MouseEvent) {\n    if (event.buttons === 1 && this.mouseDownOnProducts) {\n      event.preventDefault();\n      const products = this.shadowRoot.querySelector<HTMLElement>('.active .products');\n      const x = event.pageX - products.offsetLeft;\n      const walk = (x - this.lastKnownTouchPosition) * 50;\n      const moveTo = this.lastKnownProductScrollPosition - walk;\n\n      products.scrollTo({\n        top: 0,\n        left: moveTo,\n        behavior: 'smooth'\n      });\n    }\n  }\n\n  private onTouchStart(event: TouchEvent) {\n    const products = this.shadowRoot.querySelector('.active .products');\n\n    // For unclear reasons this element is sometimes not found. In this case treat this as an in\n    // bounds touch and do nothing. This is not logged at the warning level because we do not care\n    // about error diagnostics for this error.\n    if (!products) {\n      console.log('active products element not found');\n      this.lastKnownTouchPosition = 0;\n      return;\n    }\n\n    const bounds = products.getBoundingClientRect();\n    if (event.touches[0].clientY > bounds.y &&\n      event.touches[0].clientY < bounds.y + bounds.height &&\n      event.touches[0].clientX > bounds.x &&\n      event.touches[0].clientX < bounds.x + bounds.width) {\n      this.lastKnownTouchPosition = 0;\n      return;\n    }\n\n    this.lastKnownTouchPosition = event.touches[0].clientY;\n  }\n\n  private onTouchMove(event: TouchEvent) {\n    if (this.lastKnownTouchPosition === 0) {\n      return;\n    }\n\n    clearTimeout(this.scrollTimer);\n\n    this.scrollTimer = setTimeout(() => {\n      if (this.lastKnownTouchPosition < event.touches[0].clientY) {\n        this.navigateToVideo(false);\n      } else if (this.lastKnownTouchPosition > event.touches[0].clientY) {\n        this.navigateToVideo(true);\n      }\n\n      this.lastKnownScrollPosition = 0;\n      clearTimeout(this.scrollTimer);\n    }, 100);\n  }\n\n  private isWheelEventInBounds(event: WheelEvent) {\n    const element = this.shadowRoot.querySelector('.active .products');\n    const rect = element.getBoundingClientRect();\n    return event.clientY > rect.y && event.clientY < rect.y + rect.height &&\n      event.clientX > rect.x && event.clientX < rect.x + rect.width;\n  }\n\n  private onWheel(event: WheelEvent) {\n    if (this.isWheelEventInBounds(event)) {\n      return;\n    }\n\n    event.preventDefault();\n    event.stopPropagation();\n\n    clearTimeout(this.scrollTimer);\n\n    if (!(event.target instanceof Element)) {\n      return;\n    }\n\n    if (this.lastKnownScrollPosition === 0) {\n      this.lastKnownScrollPosition = event.target.scrollTop;\n    }\n\n    this.scrollTimer = setTimeout(() => {\n      if (event.deltaY > 0) {\n        this.navigateToVideo(true);\n      } else if (event.deltaY < 0) {\n        this.navigateToVideo(false);\n      }\n\n      this.lastKnownScrollPosition = 0;\n      clearTimeout(this.scrollTimer);\n    }, 100);\n  }\n\n  private onProductsWheel(event: WheelEvent) {\n    if (!this.isWheelEventInBounds(event)) {\n      return;\n    }\n\n    event.preventDefault();\n    event.stopPropagation();\n\n    if (event.deltaY !== 0) {\n      const products = this.shadowRoot.querySelector('.active .products');\n      products.scrollLeft = products.scrollLeft - event.deltaY;\n    }\n  }\n\n  private playVideo(video: HTMLVideoElement) {\n    assert(video);\n\n    const playIcon = this.shadowRoot.getElementById('play');\n    if (this.paused) {\n      playIcon.classList.remove('display-hide');\n      return;\n    } else {\n      playIcon.classList.add('display-hide');\n    }\n\n    if (!video.paused) {\n      return;\n    }\n\n    if (this.hidden) {\n      return;\n    }\n\n    const id = video.parentElement.dataset.id;\n    const playState = this.videoPlayState[id];\n    if (playState && playState !== 'paused') {\n      return;\n    }\n\n    this.videoPlayState[id] = 'promise-to-play';\n\n    play(video)\n      .then(_ => {\n        this.videoPlayState[id] = 'playing';\n        this.setVideoStatus('Playing video ' + this.getVideoNumber(id));\n      })\n      .catch(error => {\n        this.videoPlayState[id] = video.paused || video.ended ?\n          'paused' :\n          undefined;\n\n        // Autoplay is best effort. Restrictive in-app browsers and low power mode refuse it even\n        // after a user gesture, and interrupted or unsupported sources reject too. None of it is\n        // actionable, so keep a debug breadcrumb and never warn.\n        console.debug(error);\n\n        // A refused start leaves the video sitting still with nothing to say why, so offer the play\n        // button for a tap to start it. iPhone Safari refuses a video with sound started from a\n        // swipe with a NotAllowedError. Only the video still on screen gets the button, since the\n        // one the visitor just swiped away from rejects too when the swipe pauses it.\n        if (video.paused && video.parentElement.classList.contains('active')) {\n          const playIcon = this.shadowRoot.getElementById('play');\n          playIcon.classList.remove('display-hide');\n        }\n      });\n  }\n\n  /**\n   * Get the video number (1-based index) for the given video ID\n   *\n   * We do not have any titles or other identifiers for the videos, so we just use their position in\n   * the list when announcing which video is playing.\n   */\n  private getVideoNumber(id: string) {\n    const index = this.videos.findIndex(v => v.video_id === id);\n    return index + 1;\n  }\n\n  /**\n   * Sets the video status message for screen readers\n   */\n  private setVideoStatus(message: string) {\n    const statusEl = this.shadowRoot.getElementById('video-status');\n    if (statusEl) {\n      statusEl.textContent = message;\n    }\n  }\n\n  private onPlayClick(_event: MouseEvent) {\n    this.paused = false;\n    const video = this.shadowRoot.querySelector<HTMLVideoElement>('.active video');\n    this.playVideo(video);\n    const playIcon = this.shadowRoot.getElementById('play');\n    playIcon.classList.add('display-hide');\n  }\n\n  /**\n   * clicking on the video toggles play/pause\n   */\n  private onVideoClick(_event: MouseEvent) {\n    const video = this.shadowRoot.querySelector<HTMLVideoElement>('.active video');\n\n    if (video.paused) {\n      this.paused = false;\n      this.playVideo(video);\n    } else {\n      this.paused = true;\n      this.pauseVideo(video);\n    }\n  }\n\n  private pauseVideo(video: HTMLVideoElement) {\n    this.paused = true;\n    const videoId = video.parentElement.dataset.id;\n    video.pause();\n    this.videoPlayState[videoId] = 'paused';\n\n    this.setVideoStatus('Video paused');\n\n    const playIcon = this.shadowRoot.getElementById('play');\n    playIcon.classList.remove('display-hide');\n  }\n\n  private onTimeUpdate(event: Event) {\n    const video = event.target;\n\n    if (!(video instanceof HTMLVideoElement)) {\n      return;\n    }\n\n    if (!video.parentElement.classList.contains('active')) {\n      return;\n    }\n\n    // Only the play and playing events hide the play button, and only a short list of other video\n    // events hides the loader. Either one can still be put back on screen after those fire, such as\n    // by a late rejection of an interrupted play request, or a stalled event iPhone Safari sends on\n    // a video that keeps playing. Time updates keep firing while the video plays, so they clear\n    // whatever is left over.\n    if (!video.paused) {\n      this.hideLoader();\n      const playIcon = this.shadowRoot.getElementById('play');\n      playIcon.classList.add('display-hide');\n    }\n\n    const percentDuration = video.currentTime / video.duration * 100;\n    this.updateProgress(percentDuration);\n    this.trackViewMilestones(video.parentElement.dataset.id, percentDuration);\n  }\n\n  private updateProgress(percentDuration: number) {\n    const progress = this.shadowRoot.querySelector<HTMLElement>('.progress-value');\n    progress.style.width = percentDuration + '%';\n  }\n\n  /**\n   * Dispatches a viewed event the first time playback of a video passes each milestone. The 98\n   * percent milestone is cached under the key suffix 100.\n   */\n  private trackViewMilestones(id: string, percentDuration: number) {\n    const milestones = [\n      { key: `${id}_3`, reached: percentDuration > 3 },\n      { key: `${id}_50`, reached: percentDuration >= 50 },\n      { key: `${id}_100`, reached: percentDuration >= 98 }\n    ];\n\n    const videoObject = this.videos.find(video => video.video_id === id);\n\n    for (const milestone of milestones) {\n      if (this.watchedAnalyticsCache[milestone.key] || !milestone.reached) {\n        continue;\n      }\n\n      this.watchedAnalyticsCache[milestone.key] = true;\n\n      type Detail = WindowEventMap['shoppable-video-viewed']['detail'];\n      const viewEvent = new CustomEvent<Detail>('shoppable-video-viewed', {\n        bubbles: true,\n        composed: true,\n        detail: {\n          affiliate_display_name: videoObject.affiliate_display_name,\n          percent_viewed: percentDuration,\n          video_id: id\n        }\n      });\n      this.dispatchEvent(viewEvent);\n    }\n  }\n\n  private onMuteClick(_event: MouseEvent) {\n    const video = this.shadowRoot.querySelector<HTMLVideoElement>('.active video');\n    if (!video) {\n      return;\n    }\n\n    video.muted = !video.muted;\n    this.muted = video.muted;\n\n    const mute = this.shadowRoot.getElementById('mute');\n    if (video.muted) {\n      mute.querySelector('.volume-off').classList.remove('display-hide');\n      mute.querySelector('.volume-on').classList.add('display-hide');\n      this.setVideoStatus('Video muted');\n    } else {\n      mute.querySelector('.volume-off').classList.add('display-hide');\n      mute.querySelector('.volume-on').classList.remove('display-hide');\n      this.setVideoStatus('Video unmuted');\n    }\n  }\n\n  private onCloseClick(_event: MouseEvent) {\n    this.closePlayer();\n  }\n\n  private onVideoEvent(event: Event) {\n    if (event.type === 'play' || event.type === 'playing') {\n      this.hideLoader();\n      const playButton = this.shadowRoot.getElementById('play');\n      playButton.classList.add('display-hide');\n      return;\n    }\n\n    if (['waiting', 'error', 'stalled'].includes(event.type)) {\n      this.showLoader();\n    } else {\n      this.hideLoader();\n    }\n  }\n\n  private init() {\n    const mute = this.shadowRoot.getElementById('mute');\n    if (this.muted) {\n      mute.querySelector('.volume-off').classList.remove('display-hide');\n      mute.querySelector('.volume-on').classList.add('display-hide');\n    } else {\n      mute.querySelector('.volume-off').classList.add('display-hide');\n      mute.querySelector('.volume-on').classList.remove('display-hide');\n    }\n\n    // if already initialized do nothing\n    if (this.videos) {\n      return;\n    }\n\n    const scriptTag = document.getElementById('shoppable-video-data');\n    this.videos = <ShoppableVideo[]> JSON.parse(scriptTag.textContent);\n\n    for (const video of this.videos) {\n      this.videoPlayState[video.video_id] = 'paused';\n    }\n  }\n\n  private closePlayer() {\n    const playIcon = this.shadowRoot.getElementById('play');\n    playIcon.classList.add('display-hide');\n\n    const id = this.dataset.videoId;\n\n    this.hidden = true;\n    this.dataset.videoId = '';\n\n    const videosEl = this.shadowRoot.querySelector('.videos');\n    videosEl.innerHTML = '';\n    this.videoPlayState = {};\n\n    updateUrlParamVideoId();\n\n    type Detail = WindowEventMap['shoppable-video-player-closed']['detail'];\n    const event = new CustomEvent<Detail>('shoppable-video-player-closed', {\n      bubbles: true,\n      composed: true,\n      detail: { video_id: id }\n    });\n    this.dispatchEvent(event);\n\n    const currentSection = this.closest('section');\n    if (currentSection instanceof HTMLElement) {\n      const carousel = currentSection.querySelector('carousel-element');\n\n      if (carousel instanceof HTMLElement) {\n        carousel.inert = false;\n      }\n    }\n\n    const closeEvent = new Event('modal-close-requested', { bubbles: true, composed: true });\n    this.dispatchEvent(closeEvent);\n  }\n\n  /**\n   * @see https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/video#events\n   */\n  private createVideoWrapperElement(video: ShoppableVideo, index: number) {\n    const videoWrapperEl = document.createElement('div');\n    videoWrapperEl.classList.add('video');\n    videoWrapperEl.dataset.id = video.video_id;\n    videoWrapperEl.dataset.index = index.toString();\n\n    const videoEl = this.createVideoElement(video);\n    videoWrapperEl.append(videoEl);\n\n    const productsEl = this.createProductsCarousel(video);\n    videoWrapperEl.append(productsEl);\n\n    const captionsDiv = document.createElement('div');\n    captionsDiv.classList.add('captions');\n    captionsDiv.classList.add('empty');\n\n    videoWrapperEl.append(captionsDiv);\n\n    return videoWrapperEl;\n  }\n\n  private addVideoListeners(videoEl: HTMLVideoElement) {\n    videoEl.addEventListener('click', this.onVideoClickBound);\n    videoEl.addEventListener('timeupdate', this.onTimeUpdateBound);\n    videoEl.addEventListener('canplay', this.onVideoEventBound);\n    videoEl.addEventListener('canplaythrough', this.onVideoEventBound);\n    videoEl.addEventListener('error', this.onVideoEventBound);\n    videoEl.addEventListener('loadeddata', this.onVideoEventBound);\n    videoEl.addEventListener('loadedmetadata', this.onVideoEventBound);\n    videoEl.addEventListener('loadstart', this.onVideoEventBound);\n    videoEl.addEventListener('play', this.onVideoEventBound);\n    videoEl.addEventListener('playing', this.onVideoEventBound);\n    videoEl.addEventListener('ratechange', this.onVideoEventBound);\n    videoEl.addEventListener('stalled', this.onVideoEventBound);\n    videoEl.addEventListener('suspend', this.onVideoEventBound);\n    videoEl.addEventListener('waiting', this.onVideoEventBound);\n  }\n\n  private removeVideoListeners(videoEl: HTMLVideoElement) {\n    videoEl.removeEventListener('click', this.onVideoClickBound);\n    videoEl.removeEventListener('timeupdate', this.onTimeUpdateBound);\n    videoEl.removeEventListener('canplay', this.onVideoEventBound);\n    videoEl.removeEventListener('canplaythrough', this.onVideoEventBound);\n    videoEl.removeEventListener('error', this.onVideoEventBound);\n    videoEl.removeEventListener('loadeddata', this.onVideoEventBound);\n    videoEl.removeEventListener('loadedmetadata', this.onVideoEventBound);\n    videoEl.removeEventListener('loadstart', this.onVideoEventBound);\n    videoEl.removeEventListener('play', this.onVideoEventBound);\n    videoEl.removeEventListener('playing', this.onVideoEventBound);\n    videoEl.removeEventListener('ratechange', this.onVideoEventBound);\n    videoEl.removeEventListener('stalled', this.onVideoEventBound);\n    videoEl.removeEventListener('suspend', this.onVideoEventBound);\n    videoEl.removeEventListener('waiting', this.onVideoEventBound);\n  }\n\n  private createVideoElement(video: ShoppableVideo) {\n    const videoEl = document.createElement('video');\n    videoEl.setAttribute('loop', 'loop');\n    videoEl.setAttribute('poster', video.preview_image);\n    videoEl.setAttribute('preload', 'auto');\n    videoEl.setAttribute('muted', '');\n    videoEl.setAttribute('playsinline', '');\n    videoEl.setAttribute('controlslist', 'nofullscreen');\n    videoEl.setAttribute('disablepictureinpicture', '');\n    videoEl.setAttribute('disableremoteplayback', '');\n\n    videoEl.controls = false;\n\n    const mp4Source = video.sources.find(source => source.mime_type === 'video/mp4');\n    if (mp4Source) {\n      videoEl.setAttribute('src', mp4Source.url);\n    }\n\n    const track = this.createTrackElement(video);\n    videoEl.append(track);\n\n    return videoEl;\n  }\n\n  private createTrackElement(video: ShoppableVideo) {\n    const track = document.createElement('track');\n    track.label = 'English';\n    track.kind = 'metadata';\n    track.srclang = 'en';\n    track.src = video.captions;\n    track.default = true;\n    track.addEventListener('cuechange', this.onCaptionCueChangeBound);\n    return track;\n  }\n\n  private createProductsCarousel(video: ShoppableVideo) {\n    const productsEl = document.createElement('div');\n    productsEl.classList.add('products');\n\n    // this will be cleared once the video becomes active\n    productsEl.inert = true;\n\n    if (video.products.length > 1) {\n      productsEl.classList.add('scrollable');\n      productsEl.addEventListener('wheel', this.onProductsWheelBound, { passive: false });\n    }\n\n    for (const product of video.products) {\n      const productEl = document.createElement('a');\n      productEl.classList.add('product');\n\n      // links and images can be dragged by default, which paints a translucent copy of the card\n      // while the user is trying to swipe the carousel sideways\n      productEl.draggable = false;\n\n      productEl.addEventListener('mousemove', this.onProductMoveBound);\n\n      const url = new URL(product.handle, location.origin);\n      if (video.primary_variant.product_id === product.id) {\n        url.searchParams.set('variant', video.primary_variant.id.toString());\n      }\n\n      productEl.href = url.toString();\n\n      let thumb = product.featured_image;\n      if (video.primary_variant.product_id === product.id) {\n        thumb = video.primary_variant.image;\n      }\n\n      const productImage = document.createElement('img');\n      // thumb is null when the section could not resolve a product image, so skip src rather than\n      // request /null\n      if (thumb) {\n        productImage.setAttribute('src', thumb);\n      }\n\n      productImage.setAttribute('alt', '');\n\n      // turning off drag on the link does not cover the image inside it\n      productImage.draggable = false;\n\n      productEl.append(productImage);\n\n      const titleEl = document.createElement('div');\n      titleEl.classList.add('title-subtitle');\n\n      let title = product.title;\n      if (video.primary_variant.product_id === product.id) {\n        title += ` ${video.primary_variant.options}`;\n      }\n\n      const productTitle = document.createElement('h2');\n      productTitle.innerHTML = title;\n\n      titleEl.appendChild(productTitle);\n\n      const productSubTitle = document.createElement('h3');\n      productSubTitle.textContent = product.subtitle;\n\n      titleEl.appendChild(productSubTitle);\n\n      productEl.append(titleEl);\n\n      productsEl.append(productEl);\n    }\n\n    return productsEl;\n  }\n}\n\nfunction readCaptionsEnabled() {\n  try {\n    return localStorage.getItem('video_captions_enabled') === 'true';\n  } catch (error) {\n    // ignore\n  }\n}\n\nfunction writeCaptionsEnabled(enabled: boolean) {\n  try {\n    localStorage.setItem('video_captions_enabled', enabled ? 'true' : 'false');\n  } catch (error) {\n    // ignore\n  }\n}\n\n/**\n * Either set or clear the video parameter id. There are both use cases to support. For example,\n * when closing the player we want to revert back to the url without the parameter in the url.\n */\nfunction updateUrlParamVideoId(videoId?: string) {\n  const url = new URL(location.href);\n  const data: Record<any, any> = {};\n\n  if (videoId) {\n    url.searchParams.set('video_id', videoId);\n    data.video_id = videoId;\n  } else {\n    url.searchParams.delete('video_id');\n  }\n\n  history.replaceState(data, '', url);\n}\n\ntype ShoppableVideoViewedEvent = CustomEvent<{\n  affiliate_display_name?: string;\n  percent_viewed?: number;\n  video_id: string;\n}>;\n\ntype ShoppableVideoPlayerClosedEvent = CustomEvent<{\n  video_id: string;\n}>;\n\ndeclare global {\n  interface GlobalEventHandlersEventMap {\n    'shoppable-video-player-closed': ShoppableVideoPlayerClosedEvent;\n    'shoppable-video-viewed': ShoppableVideoViewedEvent;\n  }\n\n  interface HTMLElementTagNameMap {\n    'shoppable-video-player': ShoppableVideoPlayer;\n  }\n}\n\nif (!customElements.get('shoppable-video-player')) {\n  customElements.define('shoppable-video-player', ShoppableVideoPlayer);\n}\n","/**\n * Try to play a video, and always report the outcome as a promise.\n *\n * Do not inline this function. Playing a video is inconsistent across browsers in several ways, and\n * wrapping the call in an async function is what smooths all of them over at once.\n *\n * Some browsers have no `play` function on the element at all, so the call throws a TypeError. Some\n * have one that returns undefined instead of a promise, which is how `play` worked before the spec\n * gained a return value. Some return a promise that rejects later, which is the modern behavior and\n * is how a browser reports that it refused to autoplay. And some throw synchronously, right out of\n * the call, rather than rejecting.\n *\n * An async function turns all four into the same thing. Whatever happens inside it, the caller gets\n * a promise back, so a synchronous throw arrives as a rejection and a missing or non-promise `play`\n * still produces a promise that resolves. That means one `catch` on the call site covers every\n * failure mode, and the caller never has to check whether it got a promise before attaching a\n * handler.\n *\n * Nothing here is actionable, because a refusal is the browser enforcing its own autoplay policy.\n * Restrictive in-app browsers and low power mode refuse even after a user gesture, and interrupted\n * or unsupported sources reject too. The video simply stays paused, so callers should keep a debug\n * breadcrumb and never warn.\n */\nexport async function play(video: HTMLVideoElement) {\n  return video.play();\n}\n","import './shoppable-video-player/index.js';\nimport { ready } from '../../lib/dom-ready.js';\n\nfunction updateVideoId() {\n  const player = document.querySelector('shoppable-video-player');\n\n  // The player element is rendered by the same template that loads this script, so it should always\n  // be present here. In practice we see rare nulls in the wild on iOS Safari, most likely a\n  // navigation or bfcache teardown race firing this deferred handler against a document whose\n  // section subtree is momentarily gone. Guard rather than crash.\n\n  if (!player) {\n    return;\n  }\n\n  const params = new URLSearchParams(location.search);\n  const videoId = params.get('video_id');\n  if (videoId) {\n    player.dataset.videoId = videoId;\n    player.hidden = false;\n  } else {\n    player.dataset.videoId = '';\n    player.hidden = true;\n  }\n}\n\nfunction onSlideClicked(event: GlobalEventHandlersEventMap['carousel-slide-clicked']) {\n  const button = event.detail?.slide.querySelector('button');\n  if (!button?.dataset.videoId) {\n    return;\n  }\n\n  const focusEvent = new Event('focus-stack-push-requested', {\n    bubbles: true,\n    composed: true\n  });\n  button.dispatchEvent(focusEvent);\n\n  const player = document.querySelector('shoppable-video-player');\n  if (player) {\n    player.dataset.videoId = button.dataset.videoId;\n    player.hidden = false;\n  }\n}\n\n/**\n * After the player is closed, moves the carousel back to the slide with the video that was playing.\n */\nfunction onPlayerClosed(event: GlobalEventHandlersEventMap['shoppable-video-player-closed']) {\n  const carousel = document.querySelector<HTMLElement>('#shoppable-videos-carousel');\n  if (!carousel) {\n    return;\n  }\n\n  const videoId = event.detail.video_id;\n  const slides = carousel.querySelectorAll('[data-carousel-slide]');\n  for (const [index, slide] of slides.entries()) {\n    if (slide.querySelector(`[data-video-id=\"${videoId}\"]`)) {\n      carousel.dataset.go = index.toString();\n      return;\n    }\n  }\n}\n\nfunction onReady() {\n  updateVideoId();\n\n  const carousel = document.querySelector<HTMLElement>('#shoppable-videos-carousel');\n  if (!carousel) {\n    return;\n  }\n\n  carousel.addEventListener('carousel-slide-clicked', onSlideClicked);\n  addEventListener('shoppable-video-player-closed', onPlayerClosed);\n}\n\nready(onReady);\n"],"names":["assert","expression","message","AssertionError","Error","constructor","super","this","name","ready","callback","type","document","readyState","timer","setTimeout","clearTimeout","addEventListener","removeEventListener","ShoppableVideoPlayer","HTMLElement","observedAttributes","muted","paused","videoPlayState","watchedAnalyticsCache","lastKnownScrollPosition","lastKnownTouchPosition","lastKnownProductScrollPosition","videoWidth","mouseDownOnProducts","onVideoEventBound","onVideoEvent","bind","onVideoClickBound","onVideoClick","onTimeUpdateBound","onTimeUpdate","onPlayClickBound","onPlayClick","onCaptionCueChangeBound","onCaptionCueChange","onCaptionsControlClickBound","onCaptionsControlClick","onCloseClickBound","onCloseClick","onMuteClickBound","onMuteClick","onPreviousClickBound","onPreviousClick","onNextClickBound","onNextClick","onWheelBound","onWheel","onTouchStartBound","onTouchStart","onTouchMoveBound","onTouchMove","onMouseDownBound","onMouseDown","onMouseMoveBound","onMouseMove","onProductMoveBound","onProductMove","onProductsWheelBound","onProductsWheel","onPopStateBound","onPopState","onReadyBound","onReady","onWindowResizeBound","onWindowResize","onScreenChangeBound","onScreenChange","onKeyboardEventBound","onKeyboardEvent","connectedCallback","initializeShadowRoot","releaseReady","init","disconnectedCallback","playEl","shadowRoot","getElementById","closeEl","muteEl","previousEl","nextEl","videosEl","querySelector","captionsControlEl","videoEl","removeVideoListeners","productsEl","querySelectorAll","productEl","attachShadow","mode","innerHTML","event","code","closePlayer","includes","navigateToVideo","showPlayer","currentSection","closest","carousel","inert","Event","bubbles","composed","dispatchEvent","focus","focusVisible","attributeChangedCallback","oldValue","newValue","isConnected","hidden","videos","dataset","videoId","length","index","findIndex","v","video_id","activatePlayerAtIndex","activateVideo","updateVideoContainerWidth","prevIndex","nextIndex","currentVideo","createVideoWrapperElement","appendChild","nextVideo","previousVideo","insertBefore","showLoader","loaderTimer","loader","classList","remove","hideLoader","add","id","activeEl","pause","textTracks","parentElement","currentTime","products","targetVideoDiv","updateProgress","targetProducts","video","addVideoListeners","updateUrlParamVideoId","playVideo","forward","active","targetIndex","parseInt","target","addIndex","toBeRemoved","firstElementChild","lastElementChild","toBeAdded","removeChild","contains","prepend","_event","_activeVideo$textTrac","_cue","_cue2","activeVideo","cue","_track$activeCues","track","activeCues","captions","textContent","text","captionsOffIcon","captionsOnIcon","writeCaptionsEnabled","setVideoStatus","passive","localStorage","getItem","error","readCaptionsEnabled","updateIconPositions","width","Math","floor","innerHeight","innerWidth","containerEl","style","minWidth","progressEl","maxWidth","captionsEl","box","getBoundingClientRect","left","menuEl","offset","right","URLSearchParams","location","search","get","bounds","clientY","y","height","clientX","x","pageX","offsetLeft","scrollLeft","buttons","scrollTimer","preventDefault","walk","moveTo","scrollTo","top","behavior","console","log","touches","isWheelEventInBounds","rect","stopPropagation","Element","scrollTop","deltaY","playIcon","playState","async","play","then","_","getVideoNumber","catch","ended","undefined","debug","statusEl","pauseVideo","HTMLVideoElement","percentDuration","duration","trackViewMilestones","milestones","key","reached","videoObject","find","milestone","viewEvent","CustomEvent","detail","affiliate_display_name","percent_viewed","mute","scriptTag","JSON","parse","closeEvent","videoWrapperEl","createElement","toString","createVideoElement","append","createProductsCarousel","captionsDiv","setAttribute","preview_image","controls","mp4Source","sources","source","mime_type","url","createTrackElement","label","kind","srclang","src","default","product","draggable","URL","handle","origin","primary_variant","product_id","searchParams","set","href","thumb","featured_image","image","productImage","titleEl","title","options","productTitle","productSubTitle","subtitle","enabled","setItem","data","delete","history","replaceState","onSlideClicked","_event$detail","button","slide","focusEvent","player","onPlayerClosed","slides","entries","go","customElements","define","updateVideoId"],"sourceRoot":""}