{"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 *\n * The player shows and hides itself off `data-modal-state`. For now the player and its section's\n * script set that attribute. Later the modal manager sets it instead.\n */\nclass ShoppableVideoPlayer extends HTMLElement implements CustomElement {\n  public static get observedAttributes() {\n    return [\n      'data-modal-state'\n    ];\n  }\n\n  declare readonly dataset: {\n    /**\n     * Whether the player is shown, as \"open\". Anything else, or no value at all, means closed.\n     *\n     * Set the video id first, since opening reads it to pick the video to play.\n     */\n    modalState: string;\n\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 onModalDismissRequestedBound = this.onModalDismissRequested.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    removeEventListener('modal-dismiss-requested', this.onModalDismissRequestedBound);\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 (['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  /**\n   * Closes the player when the modal manager asks the open modal to dismiss, which it does on an\n   * escape key press. The player covers the backdrop, so a backdrop click cannot reach it. This\n   * listener is only attached while the player is open.\n   */\n  private onModalDismissRequested(_event: WindowEventMap['modal-dismiss-requested']) {\n    this.closePlayer();\n  }\n\n  private showPlayer() {\n    this.hidden = false;\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 = 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    addEventListener('modal-dismiss-requested', this.onModalDismissRequestedBound);\n  }\n\n  public attributeChangedCallback(name: string, oldValue: string, newValue: string) {\n    this.initializeShadowRoot();\n\n    if (!this.isConnected || name !== 'data-modal-state' || oldValue === newValue) {\n      return;\n    }\n\n    if (newValue === 'open') {\n      this.showPlayer();\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    } else if (oldValue === 'open') {\n      this.hidePlayer();\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.dataset.modalState = 'open';\n    } else if (this.dataset.modalState === 'open') {\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    // iPhone Safari has sent a time update to a video with no parent after the player closed. Why\n    // the video lost its parent is not known.\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    this.dataset.modalState = 'closed';\n  }\n\n  private hidePlayer() {\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\n    // Emptying the list does not stop the videos or detach their listeners, so without this their\n    // events keep reaching the player after it closes.\n    for (const video of videosEl.querySelectorAll('video')) {\n      video.pause();\n      this.removeVideoListeners(video);\n    }\n\n    for (const track of videosEl.querySelectorAll('track')) {\n      track.removeEventListener('cuechange', this.onCaptionCueChangeBound);\n    }\n\n    for (const productsEl of videosEl.querySelectorAll<HTMLElement>('.products.scrollable')) {\n      productsEl.removeEventListener('wheel', this.onProductsWheelBound);\n    }\n\n    for (const productEl of videosEl.querySelectorAll<HTMLElement>('.product')) {\n      productEl.removeEventListener('mousemove', this.onProductMoveBound);\n    }\n\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    removeEventListener('modal-dismiss-requested', this.onModalDismissRequestedBound);\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.dataset.modalState = 'open';\n  } else {\n    player.dataset.videoId = '';\n    player.dataset.modalState = 'closed';\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.dataset.modalState = 'open';\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","onModalDismissRequestedBound","onModalDismissRequested","connectedCallback","initializeShadowRoot","releaseReady","init","disconnectedCallback","playEl","shadowRoot","getElementById","closeEl","muteEl","previousEl","nextEl","videosEl","querySelector","captionsControlEl","videoEl","removeVideoListeners","productsEl","querySelectorAll","productEl","attachShadow","mode","innerHTML","event","includes","code","navigateToVideo","_event","closePlayer","showPlayer","hidden","currentSection","closest","carousel","inert","Event","bubbles","composed","dispatchEvent","focus","focusVisible","attributeChangedCallback","oldValue","newValue","isConnected","videos","dataset","videoId","length","index","findIndex","v","video_id","activatePlayerAtIndex","activateVideo","updateVideoContainerWidth","hidePlayer","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","_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","modalState","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","_video$parentElement","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":""}