{"version":3,"file":"carousel-element-snippet.min.js","mappings":"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","sources":["webpack://lange/../node_modules/@integrabeauty/assert/src/index.ts","webpack://lange/./lib/perf.ts","webpack://lange/./snippets/carousel-element/index.ts","webpack://lange/./lib/dom-ready.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 * Returns a timestamp in milliseconds for measuring durations.\n *\n * This decorates performance.now().\n *\n * This tries to use the native high-resolution epoch, falling back to Date.now().\n *\n * If native throws, this still returns a value, but it logs a message as a side effect.\n *\n * This happens in a try/catch, so it is safe.\n *\n * @see https://developer.mozilla.org/en-US/docs/Web/API/Performance/now\n */\nexport function now() {\n  try {\n    if (typeof performance?.now === 'function') {\n      return performance.now();\n    }\n  } catch (error) {\n    console.debug(error);\n  }\n\n  return Date.now();\n}\n\n/**\n * Records a named point on the User Timing timeline in devtools.\n *\n * This decorates performance.mark within a try/catch that suppresses errors.\n *\n * @see https://developer.mozilla.org/en-US/docs/Web/API/Performance/mark\n */\nexport function mark(name: string) {\n  try {\n    if (typeof performance?.mark === 'function') {\n      performance.mark(name);\n    }\n  } catch (error) {\n    console.debug(error);\n  }\n}\n\n/**\n * Records a named span between two timestamps on the User Timing timeline in devtools.\n *\n * This decorates performance.measure within a try/catch that suppresses errors.\n *\n * The bounds are explicit timestamps rather than named marks, which avoids the error the marked\n * name form throws when a start mark was never recorded.\n *\n * The detail param is optional and must be structured-cloneable. It should be a plain object. If\n * the value cannot be cloned, then performance.measure throws, which is caught and logged by this\n * wrapper. If specified, the detail shows up in the tooltip in the devtools panel.\n *\n * @see https://developer.mozilla.org/en-US/docs/Web/API/Performance/measure\n */\nexport function measure(name: string, start: number, end: number, detail?: unknown) {\n  try {\n    if (typeof performance?.measure === 'function') {\n      performance.measure(name, { start, end, detail });\n    }\n  } catch (error) {\n    console.debug(error);\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 { now } from '../../lib/perf.js';\nimport styles from './shadow-stylesheet-inline.scss?source';\n\n/**\n * A carousel. Sections render this element instead of writing carousel markup and scripts\n * themselves, so how the carousel works stays private to this element and can change without\n * breaking the sections that use it.\n *\n * Adapted from Splide, which is MIT licensed.\n *\n * Callers mark the slides they hand over with `data-carousel-slide`. The element keeps its track\n * and list in a shadow root, along with their styles, and the slides stay where the caller put them\n * and show inside the list through a slot. Liquid renders the element's shadow root snippet inside\n * it, and a carousel a script inserts gets the same shadow root from the element. With the arrows\n * on, it draws them in a footer row under the track, with the drag bar on the left and the arrows\n * on the right, or above the track with `data-track-position=\"after-controls\"`. Everything the\n * element draws goes in the shadow root, out of reach of the page's styles, so the page adjusts it\n * only through the element's data attributes and CSS variables. Options come in as data attributes,\n * one per option, with `breakpoints` as JSON. Leaving an attribute off keeps the default for that\n * option. The element reads the options once when it mounts, so changing an attribute afterward\n * does nothing yet.\n *\n * A carousel that mounts while hidden can't measure its slides, so a caller sets `data-refresh`\n * once the carousel is showing, and the element lays the slides out again. Setting it again later\n * refreshes again, even when the value is the same. A caller moves the carousel to a slide by\n * setting `data-go` to that slide's index.\n *\n * Once mounted, the element keeps its current state in `data-index`, `data-current-per-page`, and\n * `data-slide-count`, so a script that loads after the mount can still read where the carousel is.\n * It fires `carousel-element-mounted` once the mount is done and that state is written. It fires\n * `carousel-slide-move-started` when a move starts, before the state is updated, and\n * `carousel-slide-move-completed` once the move ends. It fires `carousel-element-resized` whenever\n * the element lays out the slides again, including once during the mount. The state is already\n * updated when either of those last two fires. It also fires `carousel-element-overflow-changed`\n * whenever the slides start or stop overflowing the carousel, including once during the mount with\n * the starting value, and `carousel-slide-clicked` when a slide is clicked, but not when the click\n * ends a drag. It fires `carousel-slide-visible` and `carousel-slide-hidden` when a slide comes\n * into view or leaves it, including during the mount for the slides that start in view.\n *\n * Every event bubbles and is composed, so a carousel inside a shadow root is heard outside it too.\n *\n * The element marks its own state with data attributes rather than classes. On the root that's\n * `data-mounted` from the start of the mount until a destroy, `data-initialized` once the first\n * mount is done, `data-overflowing` while the slides don't all fit, and `data-arrows-beside` while\n * it has drawn its arrows beside the track. The slide you are on gets `data-active`, a clone of a\n * slide gets `data-clone`, and the autoplay toggle gets `data-playing` while autoplay runs. The\n * pagination dot for the slide you are on carries `aria-selected`.\n */\nclass CarouselElement extends HTMLElement implements CustomElement {\n  public declare readonly dataset: {\n    /**\n     * Where the slides sit when they all fit, either \"start\" or \"center\". Left unset, the `focus`\n     * option decides, which can leave a row that fits shifted off to one side.\n     */\n    align: 'center' | 'start';\n\n    /**\n     * What a click on an arrow does. Defaults to \"step\", which moves the slide you are on by one\n     * even when the slides stay put, as they do near either end of a carousel that trims the space\n     * past its first and last slides. With \"scroll\" a click always moves the slides, skipping over\n     * any slide that would leave them where they are, and an arrow with no more scrolling to do on\n     * its side is disabled. Use \"scroll\" where nothing on the page shows which slide you are on.\n     */\n    arrowBehavior: 'scroll' | 'step';\n\n    /**\n     * Whether the arrows the element draws carry the click tracking names \"Carousel Previous Arrow\"\n     * and \"Carousel Next Arrow\". Off by default, where a click on an arrow counts toward whatever\n     * name an ancestor carries.\n     */\n    arrowClickTrack: 'false' | 'true';\n\n    /**\n     * Which icon the arrows the element draws use. Defaults to \"arrow\", the line arrow. The three\n     * chevrons are separate drawings that differ a little in size and line weight, and the first\n     * two sit on a disc a page can fill with the icon background variable. Also works inside\n     * `data-breakpoints`, for a carousel that changes icon by width. Does nothing for arrows the\n     * caller hands over.\n     */\n    arrowIcon: 'arrow' | 'chevron' | 'chevron-bold' | 'chevron-thin';\n\n    /**\n     * Whether to show the previous and next arrows. On by default. When the caller hands over an\n     * arrows block, the element uses those buttons, and when this is off they stay in the page but\n     * are hidden.\n     */\n    arrows: 'false' | 'true';\n\n    /**\n     * Set by the element while it has drawn its arrows beside the track.\n     */\n    arrowsBeside: 'true';\n\n    /**\n     * Hides the arrows the element draws while set, without taking them out of the layout. Unlike\n     * `data-arrows`, a page can set and clear it at any time, such as to keep the arrows out of\n     * sight until the carousel has its final size.\n     */\n    arrowsHidden: 'true';\n\n    /**\n     * Where the arrows the element draws sit. Defaults to \"footer\", in the footer row it draws.\n     * With \"beside\" the footer moves to the right of the track and anything else the element draws,\n     * like the drag bar, goes under both. With \"sides\" the arrows sit across the middle of the\n     * carousel, one on each edge, and a page can push them past the edges with the side offset\n     * variable. With \"above\" the arrows sit above the carousel at its right end, as far up as the\n     * above offset variable says. With \"corner\" they sit inside the carousel's top right corner, in\n     * from the edges by the corner offset variable. Also works inside `data-breakpoints`. Does\n     * nothing for arrows the caller hands over.\n     */\n    arrowsPosition: 'above' | 'beside' | 'corner' | 'edges' | 'footer' | 'sides';\n\n    /**\n     * Whether each slide takes its own width from its content instead of the carousel splitting its\n     * width evenly by `data-per-page`. Off by default.\n     */\n    autoWidth: 'false' | 'true';\n\n    /**\n     * Whether the carousel moves on its own every `data-interval`. Off by default.\n     */\n    autoplay: 'false' | 'true';\n\n    /**\n     * Whether the element draws its own play and pause button for autoplay, first in the footer it\n     * draws. Off by default. Does nothing without autoplay.\n     */\n    autoplayToggle: 'false' | 'true';\n\n    /**\n     * A JSON object of options that change at certain screen widths, keyed by width. Each value can\n     * hold any of the options that make sense to change by width, written with the camelCase option\n     * names rather than these attribute names. Whether a key is a max or a min width depends on\n     * `data-media-query`.\n     *\n     * @example '{\"768\":{\"perPage\":3,\"gap\":16}}'\n     */\n    breakpoints: string;\n\n    /**\n     * Whether to hide everything the element draws besides the slides, like the footer, the drag\n     * bar and the dots. Unlike the other attributes, this one works when set after the mount, for a\n     * page that shows the slides on their own for a while, like a fullscreen view.\n     */\n    controlsHidden: 'true';\n\n    /**\n     * How the element lays out the footer it draws when the caller hands over no arrows. Defaults\n     * to \"footer\", with the drag bar on the left and the arrows on the right. With \"center\" the\n     * arrows sit in the middle with the pagination dots between them, and the drag bar goes below.\n     */\n    controlsPosition: 'center' | 'footer';\n\n    /**\n     * How many slides fit across the carousel right now, as a whole number. The element writes this\n     * once mounted and keeps it current as breakpoints change, and setting it does nothing.\n     */\n    currentPerPage: string;\n\n    /**\n     * How the slides sit while a `destroy` breakpoint has the carousel destroyed. Left unset, they\n     * sit the way the element's stylesheets leave them. With \"stack\" they stack in a column, with a\n     * gap from the `--carousel-destroyed-gap` variable.\n     */\n    destroyedLayout: 'stack';\n\n    /**\n     * Whether the slides can be dragged. On by default. With \"overflow\" the slides can only be\n     * dragged while they overflow the carousel, so a carousel where every slide already fits does\n     * not move around under a drag that has nowhere to go.\n     */\n    drag: 'false' | 'overflow' | 'true';\n\n    /**\n     * A fixed width for every slide, which overrides `data-per-page`. A bare number is pixels, and\n     * anything else is used as a CSS length, like \"10rem\".\n     */\n    fixedWidth: string;\n\n    /**\n     * The most a flick can throw the carousel, as a number of pages, where a page is the width of\n     * the carousel. Defaults to 1.\n     */\n    flickMaxPages: string;\n\n    /**\n     * How far a flick throws the carousel, as a number, where a flick is a quick swipe that keeps\n     * the carousel moving after the finger lifts. Higher throws further. Defaults to 600. A flick\n     * never moves more than one page however hard it is.\n     */\n    flickPower: string;\n\n    /**\n     * Which slide counts as the current one when several are showing, as a whole number, or\n     * \"center\" to center the current slide.\n     */\n    focus: string;\n\n    /**\n     * A CSS selector for the things inside a slide that the element takes out of the tab order\n     * while the slide is off screen. Defaults to \"a, button, textarea, input, select, iframe\".\n     * Setting it replaces that list rather than adding to it, so a caller that wants one more tag\n     * lists the defaults along with it.\n     */\n    focusableNodes: string;\n\n    /**\n     * Whether the footer the element draws hides while the slides all fit. Off by default. With\n     * \"true\" the footer and the space around it only show while there is something to scroll to.\n     */\n    footerOnlyWhenOverflowing: 'false' | 'true';\n\n    /**\n     * Whether the footer the element draws adds height under the track. On by default. With \"false\"\n     * the footer comes out of the flow and sits where it would have been, over whatever follows the\n     * carousel, so a carousel holding a fixed aspect ratio keeps it. A page can set the footer's\n     * height with the footer height variable.\n     */\n    footerTakesRoom: 'false' | 'true';\n\n    /**\n     * The space between slides. A bare number is pixels, and anything else is used as a CSS length,\n     * like \"1rem\".\n     */\n    gap: string;\n\n    /**\n     * Set to a slide index, starting at 0, to move the carousel to that slide, the same as a move\n     * by the arrows. Every set moves, even with the same value. Setting it before the mount does\n     * nothing, so use `data-start` for the first slide in view.\n     */\n    go: string;\n\n    /**\n     * The height of every slide. A bare number is pixels, and anything else is used as a CSS\n     * length, like \"10rem\".\n     */\n    height: string;\n\n    /**\n     * The index of the current slide, starting at 0. The element writes this once mounted and keeps\n     * it current as the carousel moves. Setting it does not move the carousel, `data-go` does.\n     */\n    index: string;\n\n    /**\n     * \"true\" once the first mount is done, and it stays after a destroy. The element writes this,\n     * and setting it does nothing.\n     */\n    initialized: 'true';\n\n    /**\n     * How long autoplay rests on each slide, in milliseconds. Defaults to 5000.\n     */\n    interval: string;\n\n    /**\n     * Whether the left and right arrow keys move the carousel. Off by default. When on, it listens\n     * on the carousel itself, so the keys move it while focus is inside it.\n     */\n    keyboard: 'false' | 'true';\n\n    /**\n     * Whether screen readers hear about each move through a live region. On by default. Turn it off\n     * for a carousel that only moves along with another one, so a single move is not announced\n     * twice.\n     */\n    live: 'false' | 'true';\n\n    /**\n     * Whether the `data-breakpoints` keys are max widths or min widths. Defaults to \"max\", where a\n     * key applies at that width and narrower. With \"min\" a key applies at that width and wider.\n     */\n    mediaQuery: 'max' | 'min';\n\n    /**\n     * \"true\" from the start of the mount until the carousel is destroyed, including a destroy from\n     * the `destroy` breakpoint option. It shows up before the slides are measured, which makes it\n     * the one to key a placeholder layout on. The element writes this, and setting it does nothing.\n     */\n    mounted: 'true';\n\n    /**\n     * Whether the carousel works out its last stop from where the slides actually sit, so the next\n     * arrow turns off once moving further would not shift anything. Off by default, where the last\n     * stop comes from the slide count and `data-per-page`. Mostly useful with `data-auto-width`,\n     * where the per page count does not say how many slides fit.\n     */\n    omitEnd: 'false' | 'true';\n\n    /**\n     * Space at the right end of the carousel that only shows while the slides overflow it, so a\n     * carousel where every slide already fits sits flush. A bare number is pixels, and anything\n     * else is used as a CSS length, like \"1rem\". This sets the padding option itself, so it is\n     * meant for a carousel without `data-padding`.\n     */\n    overflowPadding: string;\n\n    /**\n     * \"true\" while the slides don't all fit, so there is somewhere to move. The element writes this\n     * and checks it again on resize, and setting it does nothing.\n     */\n    overflowing: 'true';\n\n    /**\n     * Space inside the carousel at its left and right ends, which shows a peek of the neighboring\n     * slides. A bare number is pixels, and anything else is used as a CSS length, like \"1rem\". For\n     * different space at each end, this takes a JSON object with `left` and `right` instead.\n     *\n     * @example '{\"right\":\"15%\"}'\n     */\n    padding: string;\n\n    /**\n     * Whether to show the pagination dots. On by default.\n     */\n    pagination: 'false' | 'true';\n\n    /**\n     * How many slides one move goes by, as a whole number. Defaults to `data-per-page`.\n     */\n    perMove: string;\n\n    /**\n     * How many slides fit across the carousel at once, as a whole number. Defaults to 1. A fade\n     * carousel ignores it.\n     */\n    perPage: string;\n\n    /**\n     * Set to any value to make the carousel lay out its slides again, for when it was hidden or\n     * changed size in a way it could not see. Every set refreshes, even with the same value.\n     */\n    refresh: string;\n\n    /**\n     * Whether a \"slide\" carousel wraps from the last slide back to the first and the other way\n     * around, instead of stopping at the ends. A \"loop\" carousel wraps anyway.\n     */\n    rewind: 'false' | 'true';\n\n    /**\n     * Whether dragging past either end wraps around when `data-rewind` is on. Off by default.\n     */\n    rewindByDrag: 'false' | 'true';\n\n    /**\n     * The `role` attribute the element puts on itself. Defaults to \"region\".\n     */\n    role: string;\n\n    /**\n     * How many slides the carousel has, not counting the clones a loop carousel adds. The element\n     * writes this once mounted, and setting it does nothing.\n     */\n    slideCount: string;\n\n    /**\n     * Whether to show a drag bar under the slides while they overflow the carousel. Off by default.\n     */\n    slidebar: 'false' | 'true';\n\n    /**\n     * How long a move takes, in milliseconds. Defaults to 400.\n     */\n    speed: string;\n\n    /**\n     * The index of the slide to move to once mounted, starting at 0, so a slide other than the\n     * first starts in view. The carousel mounts on the first slide and then moves, the same as a\n     * move by the arrows.\n     */\n    start: string;\n\n    /**\n     * Where the track sits against the footer the element draws. Defaults to \"before-controls\",\n     * with the footer under the track. With \"after-controls\" the footer goes above it, for a\n     * carousel whose controls sit above the slides.\n     */\n    trackPosition: 'after-controls' | 'before-controls';\n\n    /**\n     * The kind of carousel. Defaults to \"slide\", which stops at each end. \"loop\" wraps around\n     * forever. \"fade\" shows one slide at a time and fades between them.\n     */\n    transition: 'fade' | 'loop' | 'slide';\n\n    /**\n     * Whether the slides update which one is active and which ones are visible as soon as a move\n     * starts, instead of once it ends. Off by default.\n     */\n    updateOnMove: 'false' | 'true';\n  };\n\n  public static observedAttributes = ['data-go', 'data-refresh'];\n\n  private releaseReady: ReleaseHandle;\n\n  /**\n   * Whether onReady() has mounted the carousel since the element last connected. Attribute requests\n   * like `data-go` only act while this is on. Unlike `isMounted`, a breakpoint destroy leaves it\n   * on, since the carousel can still mount again from there.\n   */\n  private hasMountedSinceConnect = false;\n\n  /**\n   * Whether the carousel is mounted. Set at the start of mount and cleared by destroy, so a move or\n   * resize on a destroyed carousel leaves its parts and the root alone.\n   */\n  public declare isMounted: boolean;\n\n  /**\n   * Set when a refresh is asked for while the carousel is still mounting. The refresh happens once\n   * the mount is done.\n   */\n  public declare isRefreshPending: boolean;\n\n  /**\n   * Set when the options change while the carousel is still mounting. The parts react to the change\n   * once the mount is done.\n   */\n  public declare isUpdatePending: boolean;\n\n  /**\n   * The track element, the root's `#track` child.\n   */\n  public declare track: HTMLElement;\n\n  /**\n   * The list element inside the track, which holds the slides.\n   */\n  public declare list: HTMLElement;\n\n  /**\n   * The `#arrows` element holding the arrow buttons, which the arrows code puts in the footer.\n   */\n  public declare arrowsWrapper: HTMLElement;\n\n  /**\n   * The `#footer` row the element draws under the track for the controls it draws itself, like the\n   * arrows, the autoplay toggle, and the drag bar. Unset until the element first draws one of them,\n   * and it stays in place after that, like the track does.\n   */\n  public declare footer: HTMLElement;\n\n  /**\n   * The arrow buttons. Null while the arrows are off.\n   */\n  public declare prevArrow: HTMLButtonElement;\n  public declare nextArrow: HTMLButtonElement;\n\n  /**\n   * The click listeners for the next and previous arrows, kept so they can be removed.\n   */\n  private onNextArrowClickBound = this.onNextArrowClick.bind(this);\n  private onPrevArrowClickBound = this.onPrevArrowClick.bind(this);\n\n  /**\n   * Advances the carousel on the `interval` option's timer while autoplay is playing.\n   */\n  public declare autoplayInterval: RequestIntervalInterface;\n\n  /**\n   * The `#toggle` play and pause button the element draws while `data-autoplay-toggle` is on.\n   */\n  public declare autoplayToggle: HTMLElement;\n\n  /**\n   * Whether the pointer is over the carousel, which pauses autoplay.\n   */\n  public declare isHovered: boolean;\n\n  /**\n   * Whether focus is inside the carousel, which pauses autoplay.\n   */\n  public declare isFocusWithin: boolean;\n\n  /**\n   * Whether autoplay is stopped. Once stopped, hover and focus changes no longer restart it, and\n   * only the toggle button does.\n   */\n  public declare isAutoplayStopped: boolean;\n\n  /**\n   * Whether the `autoplay` option was on when the carousel mounted, which is what decides whether\n   * moves and refreshes reset the autoplay wait.\n   */\n  public declare isAutoplayEnabled: boolean;\n\n  /**\n   * The root's mouseenter and mouseleave listener, which pauses autoplay while the pointer is over\n   * the carousel. Kept so it can be removed.\n   */\n  private onAutoplayHoverBound = this.onAutoplayHover.bind(this);\n\n  /**\n   * The root's focusin and focusout listener, which pauses autoplay while focus is inside the\n   * carousel. Kept so it can be removed.\n   */\n  private onAutoplayFocusBound = this.onAutoplayFocus.bind(this);\n\n  /**\n   * The toggle button's click listener, kept so it can be removed.\n   */\n  private onAutoplayToggleClickBound = this.onAutoplayToggleClick.bind(this);\n\n  /**\n   * The index of the slide the carousel is on, or moving to.\n   */\n  public declare currentIndex: number;\n\n  /**\n   * The index the carousel was on before the last move.\n   */\n  public declare prevIndex: number;\n\n  /**\n   * The last index the carousel can go to. See `getEndIndex()`.\n   */\n  public declare endIndex: number;\n\n  /**\n   * The number of slides, not counting clones, as of the last options update or refresh.\n   */\n  public declare slideCount: number;\n\n  /**\n   * The `perMove` option as of the last options update or refresh.\n   */\n  public declare perMove: number;\n\n  /**\n   * The `perPage` option as of the last options update or refresh.\n   */\n  public declare perPage: number;\n\n  /**\n   * Whether moves cross fade rather than slide, settled the first time the carousel mounts.\n   */\n  public declare isFadeTransition: boolean;\n\n  /**\n   * The callback for the move in progress, called once the list's slide transition ends.\n   */\n  public declare transitionEndCallback: () => void;\n\n  /**\n   * The list's transitionend listener for a slide transition, kept so it can be removed. A fade\n   * carousel never sets it.\n   */\n  private onListTransitionEndBound = this.onListTransitionEnd.bind(this);\n\n  /**\n   * The clone slides at both ends of a loop carousel.\n   */\n  public declare clones: HTMLElement[];\n\n  /**\n   * How many clones were made for each end. Zero when the carousel is not a loop.\n   */\n  public declare cloneCount: number;\n\n  /**\n   * The list position when the current drag started or was last sampled, which drag offsets are\n   * measured from.\n   */\n  public declare dragBasePosition: number;\n\n  /**\n   * The pointer event sampled at the start of the drag and then every 200ms, for working out drag\n   * distance and speed.\n   */\n  public declare dragBaseEvent: TouchEvent | MouseEvent;\n\n  /**\n   * The sample before `dragBaseEvent`.\n   */\n  public declare dragPrevBaseEvent: TouchEvent | MouseEvent;\n\n  /**\n   * Whether the current pointer press has turned into a drag of the carousel.\n   */\n  public declare isDragging: boolean;\n\n  /**\n   * Whether the list has been dragged past its first or last position. This must not be `undefined`\n   * for strict comparison.\n   */\n  public declare isDraggedPastEdge: boolean;\n\n  /**\n   * The pointer speed in pixels per millisecond at the moment a drag was let go, kept only while\n   * the move that release starts is being set up. Zero at any other time.\n   */\n  public declare releaseVelocity: number;\n\n  /**\n   * Turns on once the user drags, so the click that ends the drag doesn't activate a link inside a\n   * slide.\n   */\n  public declare shouldPreventClick: boolean;\n\n  /**\n   * Whether dragging is off, which follows the `drag` option.\n   */\n  public declare isDragDisabled: boolean;\n\n  /**\n   * Where the move and up listeners go during a drag, the track for touch and the window for a\n   * mouse.\n   */\n  public declare dragTarget: Window | HTMLElement;\n\n  /**\n   * The pointer move and up listeners, kept so they can be removed when a drag ends. They go on the\n   * track or the window, so they take a plain event and check its type.\n   */\n  private onDragPointerMoveBound = this.onDragPointerMove.bind(this);\n  private onDragPointerUpBound = this.onDragPointerUp.bind(this);\n\n  /**\n   * The track listeners drag adds at mount, kept so they can be removed.\n   */\n  private onDragPointerDownBound = this.onDragPointerDown.bind(this);\n  private onDragClickBound = this.onDragClick.bind(this);\n\n  /**\n   * A Slide object for every slide, clones included, sorted by index.\n   */\n  public declare slides: SlideComponent[];\n\n  /**\n   * The `#slider` bar, rendered the first time it is shown.\n   */\n  public declare slidebar: HTMLElement;\n\n  /**\n   * The `#slider-handle` the visitor drags along the slidebar.\n   */\n  public declare slidebarHandle: HTMLElement;\n\n  /**\n   * Whether a slidebar drawn on an earlier mount is still in the shadow root, so it gets shown\n   * again where it is rather than drawn and placed a second time.\n   */\n  public declare hasDrawnSlidebar: boolean;\n\n  /**\n   * Whether the slidebar is showing, which is when it follows the carousel's moves, resizes, and\n   * drags.\n   */\n  public declare isSlidebarEnabled: boolean;\n\n  /**\n   * The handle's current offset along the slidebar, in pixels.\n   */\n  public declare handlePosition: number;\n\n  /**\n   * The furthest the handle can sit along the slidebar, in pixels.\n   */\n  public declare maxHandlePosition: number;\n\n  /**\n   * The furthest the track can move, in pixels. Stored so it isn't recalculated on every drag\n   * frame.\n   */\n  public declare maxTrackPosition: number;\n\n  /**\n   * The previous touch's x coordinate, for working out how far a touch on the slidebar moved.\n   */\n  public declare previousTouchX: number;\n\n  /**\n   * Where a touch on the slidebar started, for working out which way the thumb is going.\n   */\n  private declare slidebarTouchStartX: number;\n  private declare slidebarTouchStartY: number;\n\n  /**\n   * Whether a touch on the slidebar started on the handle rather than on the bar around it.\n   */\n  private declare isSlidebarTouchOnHandle: boolean;\n\n  /**\n   * Which way the current touch on the slidebar is going. It stays \"pending\" until the thumb moves\n   * far enough to tell, then becomes \"x\" for a drag of the carousel or \"y\" for a scroll of the\n   * page, and goes back to \"none\" once the touch ends.\n   */\n  private declare slidebarTouchAxis: 'none' | 'pending' | 'x' | 'y';\n\n  /**\n   * The handle's and bar's listeners, added while the slidebar shows and kept so they can be\n   * removed.\n   */\n  private onSlidebarMouseDownBound = this.onSlidebarMouseDown.bind(this);\n  private onSlidebarTouchStartBound = this.onSlidebarTouchStart.bind(this);\n  private onSlidebarHandleTransitionEndBound = this.onSlidebarHandleTransitionEnd.bind(this);\n  private onSlidebarBackgroundMouseDownBound = this.onSlidebarBackgroundMouseDown.bind(this);\n  private onSlidebarTouchMoveBound = this.onSlidebarTouchMove.bind(this);\n  private onSlidebarTouchEndBound = this.onSlidebarTouchEnd.bind(this);\n  private onSlidebarTouchCancelBound = this.onSlidebarTouchCancel.bind(this);\n\n  /**\n   * The window listeners for a mouse press on the handle, added on mousedown and removed when the\n   * press ends.\n   */\n  private onSlidebarMouseMoveBound = this.onSlidebarMouseMove.bind(this);\n  private onSlidebarMouseUpBound = this.onSlidebarMouseUp.bind(this);\n\n  /**\n   * The window listeners for a held press on the bar outside the handle, and the animation frame\n   * loop that pushes the handle toward the pointer while it is held.\n   */\n  private onSlidebarBackgroundMouseUpBound = this.onSlidebarBackgroundMouseUp.bind(this);\n  private onSlidebarBackgroundMouseMoveBound = this.onSlidebarBackgroundMouseMove.bind(this);\n  private pushSlidebarHandleBound = this.pushSlidebarHandle.bind(this);\n  private declare slidebarPressFrame: number;\n\n  /**\n   * Where along the bar the held press is, in pixels.\n   */\n  private declare slidebarPressX: number;\n\n  /**\n   * Which way the held press is from the handle, -1 for before it and 1 for after it.\n   */\n  private declare slidebarPressDirection: number;\n\n  /**\n   * When the handle was last pushed toward the held press, for working out how far to push it next.\n   */\n  private declare slidebarPressTime: number;\n\n  /**\n   * When the held press started, for telling a click apart from a hold.\n   */\n  private declare slidebarPressStartTime: number;\n\n  /**\n   * Whether the handle has reached the held press, after which it follows the pointer directly.\n   */\n  private declare isSlidebarPressCaughtUp: boolean;\n\n  /**\n   * The slide elements in the list, not counting clones.\n   */\n  public declare slideElements: HTMLElement[];\n\n  /**\n   * The modifier classes last put on the track.\n   */\n  public declare trackModifierClasses: string[];\n\n  /**\n   * The root's size at the last resize, so a resize event that didn't change it can be skipped.\n   */\n  public declare lastRootRect: DOMRect;\n\n  /**\n   * Whether the slides were wider than the list at the last resize.\n   */\n  public declare wasOverflowing: boolean;\n\n  /**\n   * The window's resize and load listener, kept so it can be removed. It lays out the carousel at\n   * most once per animation frame.\n   */\n  private onWindowResizeBound = this.onWindowResize.bind(this);\n\n  /**\n   * Whether the resize listener already has a layout waiting on the next animation frame.\n   */\n  public declare isResizeScheduled: boolean;\n\n  /**\n   * The keydown listener for keyboard navigation, kept so it can be removed.\n   */\n  private onKeyDownBound = this.onKeyDown.bind(this);\n\n  /**\n   * Set for one tick after each move so a keydown does not move the carousel twice.\n   */\n  public declare isKeyboardDisabled: boolean;\n\n  /**\n   * The change listener on each breakpoint and reduced motion media query, kept so it can be\n   * removed. It stays on while the carousel is destroyed by a breakpoint, so it can mount again.\n   */\n  private onMediaChangeBound = this.onMediaChange.bind(this);\n\n  /**\n   * Each media query paired with the options it applies while it matches.\n   */\n  public declare mediaQueries: [ Options, MediaQueryList ][];\n\n  /**\n   * The `#pagination` list the pagination code created. Null while pagination is off.\n   */\n  public declare paginationList: HTMLUListElement;\n\n  /**\n   * One entry per page dot, in page order.\n   */\n  public declare paginationItems: PaginationItem[];\n\n  /**\n   * The click and keydown listeners every page dot shares, kept so they can be removed.\n   */\n  private onPaginationClickBound = this.onPaginationClick.bind(this);\n  private onPaginationKeyDownBound = this.onPaginationKeyDown.bind(this);\n\n  /**\n   * The screen reader only span the live region briefly appends to the track after each move.\n   */\n  public declare screenReaderText: HTMLSpanElement;\n\n  /**\n   * The timer that removes the live region's screen reader span shortly after it is appended.\n   */\n  public declare screenReaderTextTimeout: number;\n\n  /**\n   * Whether the `live` option was on when the carousel mounted, which is what decides whether\n   * autoplay and moves update the live region.\n   */\n  public declare isLiveEnabled: boolean;\n\n  /**\n   * Set when destroy() is called while the carousel is still mounting, which happens when a\n   * breakpoint matching at mount time sets `destroy`. Holds whether the destroy should be complete,\n   * and the destroy happens once the mount is done.\n   */\n  public declare destroyWhenReady: boolean;\n\n  /**\n   * Where the carousel is in its life, one of `MOUNTING`, `IDLE`, `MOVING`, `DRAGGING`, or\n   * `DESTROYED`.\n   */\n  public declare state: number;\n\n  /**\n   * The defaults merged with the option attributes, plus anything merged in through mergeOptions()\n   * since. The current options get rebuilt from these whenever the breakpoints change.\n   */\n  public declare baseOptions: Options;\n\n  /**\n   * The current options, which are the base options with the matching breakpoints and the reduced\n   * motion options on top.\n   */\n  public declare currentOptions: Options;\n\n  public attributeChangedCallback(name: string, _oldValue: string, newValue: string) {\n    // Outside of the time between a mount and the next disconnect, a set does nothing. Removing the\n    // attribute is not a request to refresh. Before the mount there is nothing to refresh, and the\n    // mount measures the slides anyway.\n    if (!this.hasMountedSinceConnect) {\n      return;\n    }\n\n    if (name === 'data-refresh' && newValue !== null) {\n      this.refreshParts();\n    }\n\n    if (name === 'data-go' && newValue !== null) {\n      const index = parseInt(newValue, 10);\n      if (index >= 0) {\n        this.goTo(index);\n      }\n    }\n  }\n\n  public connectedCallback() {\n    // When our script loads before the parser reaches the end of the element, the slides are not\n    // there yet, so we wait for the document to finish parsing before building.\n    this.releaseReady = ready(this.onReady.bind(this));\n  }\n\n  public disconnectedCallback() {\n    this.releaseReady();\n\n    if (this.hasMountedSinceConnect) {\n      this.destroy();\n      this.hasMountedSinceConnect = false;\n    }\n\n    // Nothing keeps the state current while unmounted, so it goes until the next mount writes it\n    delete this.dataset.index;\n    delete this.dataset.currentPerPage;\n    delete this.dataset.slideCount;\n  }\n\n  private onReady(_event?: Event) {\n    // Each carousel builds and mounts in a task of its own rather than every carousel on the page\n    // in the one DOMContentLoaded task, so a page with many carousels gets several short tasks in\n    // place of one long one, and the carousels higher up go live without waiting on the rest. A\n    // disconnect clears the timer through the same release handle.\n    const timer = setTimeout(() => this.buildAndMount());\n    this.releaseReady = () => clearTimeout(timer);\n  }\n\n  private buildAndMount() {\n    this.build();\n\n    // Each mount starts the carousel over from scratch. These are the fields mountParts() reads\n    // before it sets them, so a carousel that was moved in the page does not carry them over.\n    this.state = MOUNTING;\n    this.hasMountedSinceConnect = true;\n    this.isFadeTransition = undefined;\n    this.transitionEndCallback = undefined;\n    this.readOptions();\n    this.mountParts();\n\n    // The featured products section, where this came from, set its overflow padding again once\n    // mounted, since it found the overflow event alone sometimes left the wrong padding. Not\n    // confirmed against our fork.\n    if (this.dataset.overflowPadding) {\n      this.setOverflowPadding(this.isOverflowing());\n    }\n\n    if (this.dataset.start) {\n      this.goTo(parseInt(this.dataset.start, 10));\n    }\n\n    this.writeState();\n\n    const event = new Event('carousel-element-mounted', { bubbles: true, composed: true });\n    this.dispatchEvent(event);\n  }\n\n  /**\n   * The element runs this from inside go(), so a caller that sets `data-go` hears the event before\n   * setting the attribute returns.\n   */\n  private onMove(index: number, previousIndex: number) {\n    type Detail = CarouselSlideMoveStartedEvent['detail'];\n    const event = new CustomEvent<Detail>('carousel-slide-move-started', {\n      bubbles: true,\n      composed: true,\n      detail: { index, previousIndex }\n    });\n    this.dispatchEvent(event);\n  }\n\n  private onMoved(index: number, previousIndex: number) {\n    this.writeState();\n\n    type Detail = CarouselSlideMoveCompletedEvent['detail'];\n    const event = new CustomEvent<Detail>('carousel-slide-move-completed', {\n      bubbles: true,\n      composed: true,\n      detail: { index, previousIndex }\n    });\n    this.dispatchEvent(event);\n  }\n\n  private onResized() {\n    this.writeState();\n\n    const event = new Event('carousel-element-resized', { bubbles: true, composed: true });\n    this.dispatchEvent(event);\n  }\n\n  /**\n   * The drag handling stops the click that ends a drag before it reaches the slide, so this only\n   * runs for a real click.\n   */\n  private onClick(slide: SlideComponent) {\n    type Detail = CarouselSlideClickedEvent['detail'];\n    const event = new CustomEvent<Detail>('carousel-slide-clicked', {\n      bubbles: true,\n      composed: true,\n      detail: { index: slide.index, slide: slide.slide }\n    });\n    this.dispatchEvent(event);\n  }\n\n  private onVisible(slide: SlideComponent) {\n    type Detail = CarouselSlideVisibleEvent['detail'];\n    const event = new CustomEvent<Detail>('carousel-slide-visible', {\n      bubbles: true,\n      composed: true,\n      detail: { index: slide.index, slide: slide.slide }\n    });\n    this.dispatchEvent(event);\n  }\n\n  private onHidden(slide: SlideComponent) {\n    type Detail = CarouselSlideHiddenEvent['detail'];\n    const event = new CustomEvent<Detail>('carousel-slide-hidden', {\n      bubbles: true,\n      composed: true,\n      detail: { index: slide.index, slide: slide.slide }\n    });\n    this.dispatchEvent(event);\n  }\n\n  private onOverflow(isOverflow: boolean) {\n    if (this.dataset.drag === 'overflow') {\n      this.mergeOptions({ drag: isOverflow }, true, true);\n    }\n\n    if (this.dataset.overflowPadding) {\n      this.setOverflowPadding(isOverflow);\n    }\n\n    type Detail = CarouselElementOverflowChangedEvent['detail'];\n    const event = new CustomEvent<Detail>('carousel-element-overflow-changed',\n      { bubbles: true, composed: true, detail: { isOverflow } });\n    this.dispatchEvent(event);\n  }\n\n  private setOverflowPadding(isOverflow: boolean) {\n    const right = isOverflow ? parseLength(this.dataset.overflowPadding) : 0;\n    this.mergeOptions({ padding: { right } }, true, true);\n  }\n\n  private writeState() {\n    this.dataset.index = this.currentIndex.toString();\n    this.dataset.currentPerPage = this.currentOptions.perPage.toString();\n    this.dataset.slideCount = this.slideElements.length.toString();\n  }\n\n  /**\n   * Makes sure the shadow root holding the track and list is there, and marks the slides.\n   */\n  private build() {\n    // Liquid writes the shadow root into the page, but the browser only builds it while reading the\n    // page, so a carousel a script inserts arrives without one and we attach it here\n    if (!this.shadowRoot) {\n      this.attachShadow({ mode: 'open' });\n\n      // The same markup the shadow root snippet writes, so the two need to change together\n      this.shadowRoot.innerHTML = `<style>${styles}</style><slot name=\"header\"></slot>` +\n        '<div id=\"track\"><div id=\"list\"><slot></slot></div></div>';\n    }\n  }\n\n  /**\n   * Sets the base and current options from the defaults and the option attributes.\n   */\n  private readOptions() {\n    // Only options that have an attribute are set, so the defaults hold for the rest\n    const options: Options = merge({}, DEFAULTS);\n\n    if (this.dataset.transition) {\n      options.transition = this.dataset.transition;\n    }\n\n    if (this.dataset.role) {\n      options.role = this.dataset.role;\n    }\n\n    if (this.dataset.align) {\n      options.align = this.dataset.align;\n    }\n\n    if (this.dataset.arrowBehavior) {\n      options.arrowBehavior = this.dataset.arrowBehavior;\n    }\n\n    if (this.dataset.arrowIcon) {\n      options.arrowIcon = this.dataset.arrowIcon;\n    }\n\n    if (this.dataset.arrowsPosition) {\n      options.arrowsPosition = this.dataset.arrowsPosition;\n    }\n\n    if (this.dataset.arrows) {\n      options.arrows = this.dataset.arrows === 'true';\n    }\n\n    if (this.dataset.pagination) {\n      options.pagination = this.dataset.pagination === 'true';\n    }\n\n    if (this.dataset.rewind) {\n      options.rewind = this.dataset.rewind === 'true';\n    }\n\n    if (this.dataset.rewindByDrag) {\n      options.rewindByDrag = this.dataset.rewindByDrag === 'true';\n    }\n\n    if (this.dataset.speed) {\n      options.speed = parseInt(this.dataset.speed, 10);\n    }\n\n    if (this.dataset.keyboard) {\n      options.keyboard = this.dataset.keyboard === 'true';\n    }\n\n    if (this.dataset.live) {\n      options.live = this.dataset.live === 'true';\n    }\n\n    if (this.dataset.autoplay) {\n      options.autoplay = this.dataset.autoplay === 'true';\n    }\n\n    if (this.dataset.interval) {\n      options.interval = parseInt(this.dataset.interval, 10);\n    }\n\n    if (this.dataset.autoWidth) {\n      options.autoWidth = this.dataset.autoWidth === 'true';\n    }\n\n    // With \"overflow\" the drag option is left at its default here, and the overflow handler sets it\n    // during the mount once the element knows whether the slides overflow\n    if (this.dataset.drag === 'true' || this.dataset.drag === 'false') {\n      options.drag = this.dataset.drag === 'true';\n    }\n\n    if (this.dataset.updateOnMove) {\n      options.updateOnMove = this.dataset.updateOnMove === 'true';\n    }\n\n    if (this.dataset.flickPower) {\n      options.flickPower = parseFloat(this.dataset.flickPower);\n    }\n\n    if (this.dataset.flickMaxPages) {\n      options.flickMaxPages = parseFloat(this.dataset.flickMaxPages);\n    }\n\n    if (this.dataset.omitEnd) {\n      options.omitEnd = this.dataset.omitEnd === 'true';\n    }\n\n    if (this.dataset.slidebar) {\n      options.slidebar = this.dataset.slidebar === 'true';\n    }\n\n    if (this.dataset.perPage) {\n      options.perPage = parseInt(this.dataset.perPage, 10);\n    }\n\n    if (this.dataset.perMove) {\n      options.perMove = parseInt(this.dataset.perMove, 10);\n    }\n\n    if (this.dataset.fixedWidth) {\n      options.fixedWidth = parseLength(this.dataset.fixedWidth);\n    }\n\n    if (this.dataset.focus === 'center') {\n      options.focus = 'center';\n    } else if (this.dataset.focus) {\n      options.focus = parseInt(this.dataset.focus, 10);\n    }\n\n    if (this.dataset.focusableNodes) {\n      options.focusableNodes = this.dataset.focusableNodes;\n    }\n\n    if (this.dataset.gap) {\n      options.gap = parseLength(this.dataset.gap);\n    }\n\n    if (this.dataset.height) {\n      options.height = parseLength(this.dataset.height);\n    }\n\n    if (this.dataset.padding?.startsWith('{')) {\n      options.padding = <Options['padding']>JSON.parse(this.dataset.padding);\n    } else if (this.dataset.padding) {\n      options.padding = parseLength(this.dataset.padding);\n    }\n\n    if (this.dataset.mediaQuery) {\n      options.mediaQuery = this.dataset.mediaQuery;\n    }\n\n    if (this.dataset.breakpoints) {\n      options.breakpoints = <Options['breakpoints']>JSON.parse(this.dataset.breakpoints);\n    }\n\n    this.baseOptions = options;\n    this.currentOptions = merge({}, options);\n  }\n\n  /**\n   * Sets up the carousel parts, like the slides, the layout, and drag handling. onReady() calls\n   * this once per connect, and a breakpoint calls it again to bring the carousel back after a\n   * breakpoint destroyed it.\n   */\n  private mountParts() {\n    assert([MOUNTING, DESTROYED].includes(this.state), '[carousel-element] Already mounted!');\n\n    this.state = MOUNTING;\n    this.isMounted = true;\n    this.isRefreshPending = false;\n    this.isUpdatePending = false;\n\n    // The index starts at 0 before anything else, since the root's resize handler runs while the\n    // carousel is still mounting and reads `index`.\n    this.currentIndex = 0;\n    this.prevIndex = 0;\n\n    // The notify, update, and refresh methods call the parts in the order they are set up here, so\n    // moving a block here means moving its calls there too.\n\n    // Watch the breakpoint and reduced motion media queries, and update the options when they\n    // change. The query listeners only come off on a complete destroy, since a breakpoint can set\n    // `destroy`, and the media queries still have to be watched while the carousel is destroyed so\n    // it can mount again.\n    const breakpoints = this.currentOptions.breakpoints;\n    this.mediaQueries = [];\n\n    const isMin = this.currentOptions.mediaQuery === 'min';\n\n    const widths = breakpoints ? Object.keys(breakpoints) : [];\n    widths.sort((width1, width2) => isMin ?\n      parseFloat(width1) - parseFloat(width2) :\n      parseFloat(width2) - parseFloat(width1));\n\n    for (const width of widths) {\n      this.registerMediaQuery(breakpoints[width], `(${isMin ? 'min' : 'max'}-width:${width}px)`);\n    }\n\n    this.registerMediaQuery(REDUCED_MOTION, '(prefers-reduced-motion: reduce)');\n    this.updateMediaQueries();\n\n    // Collect the track, list, and slide elements, and set the track classes and aria attributes.\n    this.slideElements = [];\n    this.trackModifierClasses = [];\n    this.findTrack();\n    this.collectSlides();\n    this.setRoles();\n    this.updateModifierClasses();\n    this.dataset.mounted = 'true';\n\n    // Create a Slide object for every slide element. Clones get theirs from createClones() through\n    // registerSlide().\n    this.slides = [];\n    this.registerSlides();\n\n    // Size the root, track padding, and slides, and size them again on every resize.\n    this.lastRootRect = undefined;\n    this.wasOverflowing = undefined;\n    this.applySizeOptions();\n    this.isResizeScheduled = false;\n    addEventListener('resize', this.onWindowResizeBound);\n    addEventListener('load', this.onWindowResizeBound);\n\n    // Generate clones for a loop carousel.\n    this.clones = [];\n    this.createClones();\n\n    // Track the current index and work out where each move should go.\n    this.updateIndexBounds();\n\n    // Set up the transition that animates each move. A fade carousel cross fades the slides stacked\n    // on top of each other, and every other transition slides the list. Which one gets picked the\n    // first time the carousel mounts and stays the same after that.\n    if (this.isFadeTransition === undefined) {\n      this.isFadeTransition = this.currentOptions.transition === 'fade';\n    }\n\n    if (!this.isFadeTransition) {\n      this.list.addEventListener('transitionend', this.onListTransitionEndBound);\n    }\n\n    // A footer drawn on an earlier mount was hidden when the carousel was destroyed\n    if (this.footer) {\n      this.footer.hidden = false;\n    }\n\n    // Wire up the previous and next arrow buttons.\n    this.initArrows();\n\n    // Set up autoplay, with its toggle button.\n    const onInterval = () => this.goNext();\n    this.autoplayInterval = createInterval(this.currentOptions.interval, onInterval);\n    this.autoplayToggle = this.find('#toggle');\n    this.isHovered = undefined;\n    this.isFocusWithin = undefined;\n    this.isAutoplayStopped = this.currentOptions.autoplay === 'pause';\n\n    this.isAutoplayEnabled = !!this.currentOptions.autoplay;\n\n    // A toggle drawn on an earlier mount is still in the footer, so the find above already has it\n    if (this.isAutoplayEnabled && !this.autoplayToggle && this.dataset.autoplayToggle === 'true') {\n      this.autoplayToggle = createAutoplayToggle();\n      this.getFooter().prepend(this.autoplayToggle);\n    }\n\n    if (this.isAutoplayEnabled) {\n      this.addEventListener('mouseenter', this.onAutoplayHoverBound);\n      this.addEventListener('mouseleave', this.onAutoplayHoverBound);\n      this.addEventListener('focusin', this.onAutoplayFocusBound);\n      this.addEventListener('focusout', this.onAutoplayFocusBound);\n      this.autoplayToggle?.addEventListener('click', this.onAutoplayToggleClickBound);\n      this.autoplayToggle?.setAttribute('aria-controls', this.track.id);\n\n      if (!this.isAutoplayStopped) {\n        this.playAutoplay();\n      }\n\n      this.updateAutoplay();\n    }\n\n    // Let the visitor drag the list with a mouse or a touch.\n    this.isDraggedPastEdge = false;\n    this.releaseVelocity = 0;\n    this.dragBaseEvent = undefined;\n    this.dragPrevBaseEvent = undefined;\n    this.isDragging = undefined;\n    this.shouldPreventClick = undefined;\n    this.dragTarget = undefined;\n\n    // The up events include click, because the browser sometimes dispatches drag events instead of\n    // mouse ones.\n    const dragOptions: AddEventListenerOptions = { passive: false, capture: true };\n    this.track.addEventListener('touchmove', onTrackNoop, dragOptions);\n    this.track.addEventListener('mousemove', onTrackNoop, dragOptions);\n    this.track.addEventListener('touchend', onTrackNoop, dragOptions);\n    this.track.addEventListener('touchcancel', onTrackNoop, dragOptions);\n    this.track.addEventListener('mouseup', onTrackNoop, dragOptions);\n    this.track.addEventListener('click', onTrackNoop, dragOptions);\n    this.track.addEventListener('touchstart', this.onDragPointerDownBound, dragOptions);\n    this.track.addEventListener('mousedown', this.onDragPointerDownBound, dragOptions);\n    this.track.addEventListener('click', this.onDragClickBound, { capture: true });\n    this.track.addEventListener('dragstart', onTrackDragStart);\n\n    // Add a drag bar for showing and controlling the slide position while the `slidebar` option is\n    // on. The slidebar is created the first time it is shown, so a carousel that never shows one\n    // never gets the markup. One drawn on an earlier mount stays in the shadow root, hidden.\n    this.slidebar = this.find('#slider');\n    this.slidebarHandle = this.find('#slider-handle');\n    this.hasDrawnSlidebar = !!this.slidebar;\n    this.isSlidebarEnabled = false;\n    this.handlePosition = 0;\n    this.previousTouchX = 0;\n    this.slidebarTouchAxis = 'none';\n\n    // Move between slides with the arrow keys.\n    this.addKeyListener();\n\n    // Set up the pagination UI (a slide picker).\n    //\n    // See https://www.w3.org/TR/2021/NOTE-wai-aria-practices-1.2-20211129/#grouped-carousel-elements\n    this.paginationItems = [];\n    this.paginationList = null;\n\n    this.initPagination();\n\n    // Set up the live region on the track, which announces slide changes to screen readers. JAWS\n    // needs `aria-atomic` to make the `aria-busy` work.\n    //\n    // See https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/ARIA_Live_Regions\n    this.screenReaderText = document.createElement('span');\n    this.screenReaderText.id = 'sr';\n\n    this.screenReaderTextTimeout = 0;\n\n    this.isLiveEnabled = !!this.currentOptions.live;\n\n    if (this.isLiveEnabled) {\n      this.setAriaLive(this.autoplayInterval.isPaused() ? 'polite' : 'off');\n      this.track.setAttribute('aria-atomic', 'true');\n      this.screenReaderText.textContent = '…';\n    }\n\n    // Every part is set up by now, so each one does its first pass\n    this.reposition();\n\n    if (this.isFadeTransition) {\n      this.initFadeTransition();\n    }\n\n    if (this.currentOptions.arrows) {\n      this.updateArrows();\n    }\n\n    this.isDragDisabled = !this.currentOptions.drag;\n\n    this.dataset.initialized = 'true';\n\n    this.state = IDLE;\n\n    if (typeof this.destroyWhenReady === 'boolean') {\n      const completely = this.destroyWhenReady;\n      this.destroyWhenReady = undefined;\n      this.destroy(completely);\n    } else {\n      this.toggleSlidebar();\n\n      // A refresh or an options change asked for while mounting waited until every part was set up\n      if (this.isRefreshPending) {\n        this.refreshParts();\n      }\n\n      if (this.isUpdatePending) {\n        this.updateParts();\n      }\n    }\n  }\n\n  /**\n   * Has every part react to an options change, in the order they were set up in mount. While the\n   * carousel is still mounting, this waits until the mount is done.\n   */\n  private updateParts() {\n    if (!this.isMounted) {\n      return;\n    }\n\n    if (this.state === MOUNTING) {\n      this.isUpdatePending = true;\n      return;\n    }\n\n    this.updateModifierClasses();\n    this.applySizeOptions();\n    this.checkCloneCount();\n    this.reposition();\n    this.updateIndexBounds();\n    this.destroyArrows();\n    this.initArrows();\n    this.isDragDisabled = !this.currentOptions.drag;\n    this.toggleSlidebar();\n    this.removeKeyListener();\n    this.addKeyListener();\n    this.destroyPagination();\n    this.initPagination();\n  }\n\n  /**\n   * Rebuilds every part that depends on the slides, in the order they were set up in mount. While\n   * the carousel is still mounting, this waits until the mount is done.\n   */\n  private refreshParts() {\n    if (!this.isMounted) {\n      return;\n    }\n\n    if (this.state === MOUNTING) {\n      this.isRefreshPending = true;\n      return;\n    }\n\n    this.removeClassesAndAttributes();\n    this.findTrack();\n    this.collectSlides();\n    this.setRoles();\n    this.updateModifierClasses();\n    this.destroySlides();\n    this.registerSlides();\n    this.applySizeOptions();\n    this.removeClones();\n    this.createClones();\n    this.reposition();\n    this.updateIndexBounds();\n\n    if (this.isFadeTransition) {\n      this.initFadeTransition();\n    }\n\n    if (this.currentOptions.arrows) {\n      this.updateArrows();\n    }\n\n    if (this.isAutoplayEnabled) {\n      this.autoplayInterval.rewind();\n    }\n\n    this.destroyPagination();\n    this.initPagination();\n  }\n\n  private createClones() {\n    this.cloneCount = this.computeCloneCount();\n\n    if (this.cloneCount === 0) {\n      return;\n    }\n\n    // Generate the clones for each side.\n    const count = this.cloneCount;\n    const slides = this.slides.slice();\n    const length = slides.length;\n\n    if (length > 0) {\n      while (slides.length < count) {\n        slides.push(...slides);\n      }\n\n      // The clones at the end go after the last slide rather than at the end of the list, since the\n      // slides of a carousel with a shadow root sit under the element instead of in the list\n      let tail = slides[length - 1].slide;\n\n      slides.slice(-count).concat(slides.slice(0, count)).forEach((slide, index) => {\n        const isHead = index < count;\n\n        const clone = <HTMLElement>slide.slide.cloneNode(true);\n        clone.dataset.clone = 'true';\n\n        if (isHead) {\n          slides[0].slide.before(clone);\n        } else {\n          tail.after(clone);\n          tail = clone;\n        }\n\n        this.clones.push(clone);\n        this.registerSlide(clone, index - count + (isHead ? 0 : length), slide.index);\n      });\n    }\n\n    this.resizeSlides(true);\n  }\n\n  /**\n   * Registers a slide element and creates a Slide object. Needs to sort every time when a new slide\n   * is registered especially for clones.\n   *\n   * @param slide A slide element to register\n   * @param index A slide index\n   * @param slideIndex A slide index for clones. This must be `-1` for regular slides\n   */\n  private registerSlide(slide: HTMLElement, index: number, slideIndex: number) {\n    const object = this.createSlide(index, slideIndex, slide);\n    object.mount();\n    this.slides.push(object);\n    this.slides.sort((slide1, slide2) => slide1.index - slide2.index);\n  }\n\n  /**\n   * The subcomponent for managing each slide.\n   *\n   * @param index A slide index\n   * @param slideIndex A slide index for clones. This must be `-1` if the slide is not a clone\n   * @param slide A slide element\n   */\n  private createSlide(index: number, slideIndex: number, slide: HTMLElement) {\n    // The nested functions below build the slide object, and some take it as their own `this`, so\n    // they reach the carousel through this name.\n    const carousel = this;\n\n    const styles = slide.getAttribute('style');\n    const label = slide.getAttribute('aria-label');\n    const isClone = slideIndex > -1;\n    const container = slide.querySelector<HTMLElement>(':scope > .carousel-slide-container');\n    const updateOnMove = carousel.currentOptions.updateOnMove;\n    let destroyed: boolean;\n\n    // Whether the slide was in view at the last update, so the visible and hidden events only fire\n    // on a change.\n    let wasVisible = false;\n\n    function onClick() {\n      carousel.onClick(self);\n    }\n\n    function mount(this: SlideComponent) {\n      if (!isClone) {\n        slide.setAttribute('role', carousel.currentOptions.pagination ? 'tabpanel' : 'group');\n        slide.setAttribute('aria-roledescription', 'slide');\n        slide.setAttribute('aria-label',\n          label || `${index + 1} of ${carousel.slideElements.length}`);\n      }\n\n      listen();\n    }\n\n    /**\n     * Listens to some events.\n     */\n    function listen() {\n      slide.addEventListener('click', onClick);\n    }\n\n    function destroy() {\n      destroyed = true;\n      slide.removeEventListener('click', onClick);\n      delete slide.dataset.active;\n      for (const attribute of ALL_ATTRIBUTES) {\n        slide.removeAttribute(attribute);\n      }\n\n      if (styles) {\n        slide.setAttribute('style', styles);\n      } else {\n        slide.removeAttribute('style');\n      }\n\n      if (label) {\n        slide.setAttribute('aria-label', label);\n      } else {\n        slide.removeAttribute('aria-label');\n      }\n    }\n\n    function onMove() {\n      if (updateOnMove) {\n        update();\n      }\n    }\n\n    /**\n     * Updates the attributes of the slide.\n     */\n    function update() {\n      if (!destroyed) {\n        updateActivity();\n        updateVisibility();\n      }\n    }\n\n    /**\n     * Marks the slide when it is the one the carousel is on.\n     */\n    function updateActivity() {\n      if (isActive()) {\n        slide.dataset.active = 'true';\n      } else {\n        delete slide.dataset.active;\n      }\n    }\n\n    /**\n     * Updates the attributes related with visibility.\n     * - Do not update aria-hidden on shifting to avoid Window Narrator from start reading contents.\n     * - If the slide or something inside it has focus and the slide gets hidden, drops the focus.\n     */\n    function updateVisibility() {\n      const visible = isVisible();\n      const hidden = !visible && !isPeeking() && (!isActive() || isClone);\n\n      // A slide can hold focus after a click on a card inside it, and dragging the carousel can\n      // then push it off screen. Putting aria-hidden on it while it still holds focus hides the\n      // focus from assistive tech, and Chrome warns about that. So the focus has to leave first.\n      // Focus inside a shadow root shows up as its host here, which still sits inside the slide.\n      if (!visible && slide.contains(document.activeElement) &&\n        document.activeElement instanceof HTMLElement) {\n        document.activeElement.blur();\n      }\n\n      if (carousel.state !== MOVING) {\n        if (hidden) {\n          slide.setAttribute('aria-hidden', 'true');\n        } else {\n          slide.removeAttribute('aria-hidden');\n        }\n      }\n\n      if (carousel.currentOptions.focusableNodes) {\n        const focusableNodes = slide.querySelectorAll(carousel.currentOptions.focusableNodes);\n        for (const focusable of Array.from(focusableNodes)) {\n          if (hidden) {\n            focusable.setAttribute('tabindex', '-1');\n          } else {\n            focusable.removeAttribute('tabindex');\n          }\n        }\n      }\n\n      // The focusableNodes sweep above runs through querySelectorAll, which cannot reach into a\n      // shadow root, and a lot of our slides are custom elements keeping their link or button in\n      // one. So the sweep misses the control and leaves it focusable inside a slide that is aria-\n      // hidden. Setting inert on the slide covers it, since inert reaches into shadow roots where\n      // tabindex on the host does not. inert needs Safari 15.5, so an older iOS leaves hidden\n      // slides focusable.\n      slide.inert = hidden;\n\n      if (visible !== wasVisible) {\n        wasVisible = visible;\n\n        if (visible) {\n          carousel.onVisible(self);\n        } else {\n          carousel.onHidden(self);\n        }\n      }\n    }\n\n    /**\n     * Adds a CSS rule to the carousel or the container.\n     *\n     * @param property A property name\n     * @param value A CSS value to add\n     * @param useContainer Determines whether to apply the rule to the container or not\n     */\n    function style(property: StyleProperty, value: string | number, useContainer?: boolean) {\n      if (value !== null) {\n        let target = slide;\n        if (useContainer && container) {\n          target = container;\n        }\n\n        target.style[property] = `${value}`;\n      }\n    }\n\n    function isActive() {\n      // A clone of the active slide is active too, so more than one element can carry `data-active`\n      // .\n      return carousel.currentIndex === index || carousel.currentIndex === slideIndex;\n    }\n\n    function isVisible() {\n      if (carousel.currentOptions.transition === 'fade') {\n        return isActive();\n      }\n\n      const trackRect = carousel.track.getBoundingClientRect();\n      const slideRect = slide.getBoundingClientRect();\n      return Math.floor(trackRect.left) <= Math.ceil(slideRect.left) &&\n        Math.floor(slideRect.right) <= Math.ceil(trackRect.right);\n    }\n\n    /**\n     * Whether enough of a slide that is cut off by the edge of the track shows to count as on\n     * screen. Some carousels pad their track on purpose so the next card hangs off the edge, and\n     * the shopper can see that card and expects to tap it, even though {@link isVisible} says it is\n     * hidden.\n     *\n     * The track clips with overflow, so what counts is the slide's overlap with the track rather\n     * than with the viewport. The 24px floor stops a sliver from counting, since a carousel can\n     * carry a few pixels of track padding for something unrelated, like keeping a focus outline\n     * from getting clipped. The floor is a guess rather than a measured number.\n     */\n    function isPeeking() {\n      // Fade slides sit stacked on top of each other, so every one of them overlaps the track\n      if (carousel.currentOptions.transition === 'fade') {\n        return false;\n      }\n\n      const trackRect = carousel.track.getBoundingClientRect();\n      const slideRect = slide.getBoundingClientRect();\n      const overlap = Math.min(slideRect.right, trackRect.right) -\n        Math.max(slideRect.left, trackRect.left);\n      return overlap >= 24;\n    }\n\n    const self: SlideComponent = {\n      index,\n      slideIndex,\n      slide,\n      container,\n      isClone,\n      mount,\n      destroy,\n      update,\n      onMove,\n      style\n    };\n\n    return self;\n  }\n\n  /**\n   * Returns the number of elements to generate. This always returns 0 if the carousel transition is\n   * not `'loop'`.\n   *\n   * @returns The number of clones.\n   */\n  private computeCloneCount() {\n    if (this.currentOptions.transition !== 'loop') {\n      return 0;\n    }\n\n    // With a fixed slide width, enough clones to fill the track\n    if (this.currentOptions.fixedWidth) {\n      const fixedSize = this.getSlideSize(0);\n      if (fixedSize > 0) {\n        const fixedCount = Math.ceil(this.track.getBoundingClientRect().width / fixedSize);\n        if (fixedCount > 0) {\n          return fixedCount;\n        }\n      }\n    }\n\n    // With slides sized to their content, one clone per slide\n    if (this.currentOptions.autoWidth && this.slideElements.length > 0) {\n      return this.slideElements.length;\n    }\n\n    return this.currentOptions.perPage * 2;\n  }\n\n  private removeClones() {\n    for (const clone of this.clones) {\n      clone.remove();\n    }\n\n    this.clones = [];\n  }\n\n  private registerSlides() {\n    for (const [index, slide] of this.slideElements.entries()) {\n      this.registerSlide(slide, index, -1);\n    }\n  }\n\n  private destroySlides() {\n    for (const slide of this.slides) {\n      slide.destroy();\n    }\n\n    this.slides = [];\n  }\n\n  private removeClassesAndAttributes(completely?: boolean) {\n    const attributes = ALL_ATTRIBUTES.concat('style');\n\n    this.slideElements = [];\n    this.track.classList.remove(...this.trackModifierClasses);\n    for (const attribute of attributes) {\n      this.track.removeAttribute(attribute);\n      this.list.removeAttribute(attribute);\n    }\n\n    const rootAttributes = completely ? attributes : ['style', 'aria-roledescription'];\n    for (const attribute of rootAttributes) {\n      this.removeAttribute(attribute);\n    }\n  }\n\n  private updateModifierClasses() {\n    this.track.classList.remove(...this.trackModifierClasses);\n\n    // These class names are built from the `transition` option, so a search for a full name like\n    // `track-fade` won't find them here.\n    const transition = this.currentOptions.transition;\n    this.trackModifierClasses = [`track-${transition}`];\n\n    if (this.currentOptions.drag) {\n      this.trackModifierClasses.push('track-draggable');\n    }\n\n    this.track.classList.add(...this.trackModifierClasses);\n  }\n\n  private findTrack() {\n    this.track = this.find('#track');\n    this.list = this.find('#list');\n\n    assert(this.track && this.list, '[carousel-element] A track/list element is missing.');\n  }\n\n  private collectSlides() {\n    // Slides shown through the shadow root's slot are still children of the element itself\n    const children = this.querySelectorAll<HTMLElement>(\n      ':scope > [data-carousel-slide]:not([data-clone=\"true\"])');\n    this.slideElements.push(...children);\n  }\n\n  /**\n   * Sets the roles on the root and the list. Don't change the role of the root element, which\n   * removes the region from the accessibility tree.\n   */\n  private setRoles() {\n    if (!this.getAttribute('role') && this.tagName !== 'SECTION' &&\n      this.currentOptions.role) {\n      this.setAttribute('role', this.currentOptions.role);\n    }\n\n    this.setAttribute('aria-roledescription', 'carousel');\n\n    this.list.setAttribute('role', 'presentation');\n  }\n\n  /**\n   * Finishes a slide transition once the list's own transition ends.\n   */\n  private onListTransitionEnd(event: TransitionEvent) {\n    if (event.target === this.list && this.transitionEndCallback) {\n      this.cancelTransition();\n      this.transitionEndCallback();\n    }\n  }\n\n  /**\n   * Offsets all slides for stacking them onto the head of the list.\n   */\n  private initFadeTransition() {\n    for (const slide of this.slides) {\n      slide.style('transform', `translateX(-${100 * slide.index}%)`);\n    }\n  }\n\n  /**\n   * Handles the window's resize and load events by laying out the carousel again, at most once per\n   * animation frame.\n   */\n  private onWindowResize(_event: Event) {\n    if (!this.isResizeScheduled) {\n      this.isResizeScheduled = true;\n      requestAnimationFrame(() => {\n        this.isResizeScheduled = false;\n        this.onResize();\n      });\n    }\n  }\n\n  /**\n   * Initializes the layout on mount, on an options change, or on a refresh. Uses `max-width` for\n   * the root to prevent the carousel from exceeding the parent element.\n   */\n  private applySizeOptions() {\n    this.style.maxWidth = unit(this.currentOptions.width);\n    this.track.style.paddingLeft = this.getPaddingCss(false);\n    this.track.style.paddingRight = this.getPaddingCss(true);\n\n    this.resizeSlides(true);\n  }\n\n  /**\n   * Updates dimensions of some elements when the carousel is resized. Also checks the total size of\n   * the slides and tells the root and the slidebar when it starts or stops exceeding the list\n   * width.\n   *\n   * @param force Skips checking the root dimension change and always performs the resizing process\n   */\n  private resizeSlides(force?: boolean) {\n    const newRect = this.getBoundingClientRect();\n\n    if (force || this.lastRootRect.width !== newRect.width ||\n      this.lastRootRect.height !== newRect.height) {\n      this.styleSlides('marginRight', unit(this.currentOptions.gap));\n      const fixedWidth = unit(this.currentOptions.fixedWidth);\n      const width = this.currentOptions.autoWidth ? null : fixedWidth || this.getSlideSizeCss();\n      this.styleSlides('width', width);\n      this.styleSlides('height', unit(this.currentOptions.height), true);\n\n      this.lastRootRect = newRect;\n      this.notifyResized();\n\n      const prevOverflow = this.wasOverflowing;\n      this.wasOverflowing = this.isOverflowing();\n\n      if (this.wasOverflowing !== prevOverflow) {\n        if (this.wasOverflowing) {\n          this.dataset.overflowing = 'true';\n        } else {\n          delete this.dataset.overflowing;\n        }\n\n        this.notifyOverflowChanged();\n      }\n    }\n  }\n\n  /**\n   * Returns whether the slides are wider than the list. This is always `true` for a fade carousel.\n   */\n  private isOverflowing() {\n    // When the slide count matches perPage, the slides fill the list exactly, but adding up their\n    // fractional widths can land a hair over the list width. Firefox does this on some layouts.\n    // Counting that as overflow makes the overflow padding flip on and off forever, since the\n    // padding itself changes the rounding. So we only count overflow past a pixel of slack.\n    return this.currentOptions.transition === 'fade' ||\n      this.getSlidesSize(true) > this.getListSize() + 1;\n  }\n\n  /**\n   * Returns the CSS width for each slide, which splits the list across `perPage` slides with the\n   * gaps taken out.\n   */\n  private getSlideSizeCss() {\n    const gap = unit(this.currentOptions.gap);\n    const perPage = this.currentOptions.perPage ? this.currentOptions.perPage : 1;\n    const plusGap = gap ? ` + ${gap}` : '';\n    const minusGap = gap ? ` - ${gap}` : '';\n    return `calc((100%${plusGap})/${perPage}${minusGap})`;\n  }\n\n  /**\n   * Returns the list width in pixels.\n   */\n  private getListSize() {\n    return this.list.getBoundingClientRect().width;\n  }\n\n  /**\n   * Returns the total size of the slides, without the clones before the first slide. Do not use the\n   * clone's size because it's unstable while initializing and refreshing process.\n   *\n   * @param withoutGap Determines whether to exclude the last gap or not\n   *\n   * @returns The total width of the slides without clones.\n   */\n  private getSlidesSize(withoutGap?: boolean) {\n    return this.getTotalSizeThrough(this.slideElements.length - 1) -\n      this.getTotalSizeThrough(0) +\n      this.getSlideSize(0, withoutGap);\n  }\n\n  /**\n   * Returns the slide width.\n   *\n   * @param index A slide index\n   * @param withoutGap Determines whether to exclude the gap amount or not\n   *\n   * @returns The size of the specified slide element in pixel.\n   */\n  private getSlideSize(index?: number, withoutGap?: boolean) {\n    const slide = this.getSlideAt(index || 0);\n    if (!slide) {\n      return 0;\n    }\n\n    const width = slide.slide.getBoundingClientRect().width;\n    if (withoutGap) {\n      return width;\n    }\n\n    return width + this.getGap();\n  }\n\n  /**\n   * Returns the gap value in pixel by using the computed style of the first slide.\n   *\n   * @returns The gap value in pixel.\n   */\n  private getGap() {\n    const slide = this.getSlideAt(0);\n    if (!slide) {\n      return 0;\n    }\n\n    const gap = parseFloat(getComputedStyle(slide.slide).marginRight);\n    return Number.isNaN(gap) ? 0 : gap;\n  }\n\n  /**\n   * Returns the total width of slides from the start of the list to the specified index. This\n   * includes sizes of clones before the first slide.\n   *\n   * @param index A slide index. If omitted, uses the last index\n   * @param withoutGap Determines whether to exclude the last gap or not\n   *\n   * @returns The total width of slides.\n   */\n  private getTotalSizeThrough(index: number, withoutGap?: boolean) {\n    const slide = this.getSlideAt(index);\n\n    if (slide) {\n      const right = slide.slide.getBoundingClientRect().right;\n      const left = this.list.getBoundingClientRect().left;\n      return Math.abs(right - left) + (withoutGap ? 0 : this.getGap());\n    }\n\n    return 0;\n  }\n\n  /**\n   * Tells the root and every part that reacts to the slides being sized again that it happened, in\n   * the order they were set up in mount. The slides get sized while the carousel is still mounting,\n   * before any of the parts are set up, and then only the root hears about it.\n   */\n  private notifyResized() {\n    if (!this.isMounted) {\n      return;\n    }\n\n    this.onResized();\n\n    if (this.state === MOUNTING) {\n      return;\n    }\n\n    this.reposition();\n\n    // The end index can change with `autoWidth` or `fixedWidth` on, so the controller, arrows, and\n    // pagination get set up again when it does.\n    if (this.endIndex !== this.getEndIndex()) {\n      this.updateIndexBounds();\n\n      if (this.currentOptions.arrows) {\n        this.updateArrows();\n      }\n\n      this.destroyPagination();\n      this.initPagination();\n    }\n\n    if (this.isSlidebarEnabled) {\n      this.updateSlidebarSize();\n    }\n  }\n\n  /**\n   * Tells the root and every part that reacts to a move that one is starting, in the order they\n   * were set up in mount.\n   *\n   * @param index The index the carousel is moving to\n   * @param previousIndex The index the carousel is moving from\n   */\n  private notifyMove(index: number, previousIndex: number) {\n    if (!this.isMounted) {\n      return;\n    }\n\n    this.onMove(index, previousIndex);\n\n    for (const slide of this.slides) {\n      slide.onMove();\n    }\n\n    if (this.isAutoplayEnabled) {\n      this.autoplayInterval.rewind();\n      // Reset the wait to the current `interval` option, so a breakpoint that changes `interval`\n      // takes effect from the next slide on.\n      this.autoplayInterval.set(this.currentOptions.interval);\n    }\n\n    // Ignore the keyboard until the next tick, so the carousel doesn't move twice.\n    const wasKeyboardDisabled = this.isKeyboardDisabled;\n    this.isKeyboardDisabled = true;\n    setTimeout(() => {\n      this.isKeyboardDisabled = wasKeyboardDisabled;\n    });\n\n    if (this.currentOptions.pagination) {\n      this.updatePagination();\n    }\n\n    if (this.isSlidebarEnabled) {\n      this.moveSlidebarHandle(index);\n    }\n  }\n\n  /**\n   * Toggles the SR field and `aria-busy`.\n   *\n   * @param active Determines whether to activate the field or not\n   */\n  private toggleScreenReaderText(active: boolean) {\n    this.track.setAttribute('aria-busy', `${active}`);\n\n    if (active) {\n      this.track.append(this.screenReaderText);\n\n      // Windows Narrator goes silent when the SR text is removed right away, so we wait 90ms first.\n      clearTimeout(this.screenReaderTextTimeout);\n      this.screenReaderTextTimeout = setTimeout(() => this.toggleScreenReaderText(false), 90);\n    } else {\n      this.screenReaderText.remove();\n      clearTimeout(this.screenReaderTextTimeout);\n    }\n  }\n\n  /**\n   * Tells the root and every part that reacts to a finished move that it is done, in the order they\n   * were set up in mount.\n   *\n   * @param index The index the carousel moved to\n   * @param previousIndex The index the carousel moved from\n   */\n  private notifyMoved(index: number, previousIndex: number) {\n    if (!this.isMounted) {\n      return;\n    }\n\n    this.onMoved(index, previousIndex);\n\n    for (const slide of this.slides) {\n      slide.update();\n    }\n\n    if (this.currentOptions.arrows) {\n      this.updateArrows();\n    }\n\n    if (this.isLiveEnabled) {\n      this.toggleScreenReaderText(true);\n    }\n  }\n\n  /**\n   * Sets the handle position based on the active slide's position.\n   *\n   * @param index Active Slide index.\n   */\n  private moveSlidebarHandle(index: number) {\n    let newSlidebarPosition;\n    if (this.currentOptions.transition === 'fade') {\n      // TODO: this fade-mode index-to-position math is hard to follow and possibly inconsistent\n      // with the reverse conversion. The two position-to-index conversions elsewhere in this file\n      // divide the handle travel into one segment per slide, but this placement instead divides by\n      // the gaps between slides and folds in the slides-per-page count, so the forward and reverse\n      // mappings do not round-trip. It is unclear whether that mismatch is deliberate, since those\n      // read paths round to the nearest slide and so tolerate slop this placement cannot, or\n      // whether it is a latent off-by-one. Someone who knows the fade layout should confirm and\n      // reconcile.\n      const gapsBetweenSlides = this.slides.length - 1;\n      const share = this.currentOptions.perPage / gapsBetweenSlides;\n      const step = share * this.maxHandlePosition;\n      newSlidebarPosition = step * index;\n    } else {\n      const newTrackPosition = this.getPositionOf(index);\n      newSlidebarPosition = this.getSlidebarPositionForTrack(newTrackPosition);\n    }\n\n    this.handlePosition = this.clampSlidebarHandlePosition(newSlidebarPosition);\n    this.slidebarHandle.style.transform = `translateX(${this.handlePosition}px)`;\n    this.slidebarHandle.style.transition = 'transform 400ms cubic-bezier(0.25, 1, 0.5, 1)';\n  }\n\n  /**\n   * Repositions the carousel.\n   *\n   * - Do not call `cancelMove()` here because iOS Safari emits window resize event while the user\n   *   swipes the carousel because of the bottom bar.\n   */\n  private reposition() {\n    this.translateTo(this.getPositionOf(this.currentIndex, true));\n\n    for (const slide of this.slides) {\n      slide.update();\n    }\n  }\n\n  /**\n   * Tells the root and the slidebar that the slides started or stopped overflowing the carousel.\n   * Like notifyResized(), only the root hears about it while the carousel is still mounting.\n   */\n  private notifyOverflowChanged() {\n    if (!this.isMounted) {\n      return;\n    }\n\n    this.onOverflow(this.wasOverflowing);\n\n    // Every carousel mounts the slidebar and overflowing alone does not mean the slidebar option is\n    // on, so this goes through the same check as updated and the end of mount\n    if (this.state !== MOUNTING) {\n      this.toggleSlidebar();\n    }\n  }\n\n  /**\n   * Parses the padding option and returns the value for one side.\n   *\n   * @param right Determines whether to get the right padding or the left\n   *\n   * @returns The padding value as a CSS string.\n   */\n  private getPaddingCss(right: boolean) {\n    const padding = this.currentOptions.padding;\n    if (!padding) {\n      return '0px';\n    }\n\n    if (typeof padding === 'object') {\n      const sideValue = right ? padding.right : padding.left;\n      return sideValue ? unit(sideValue) : '0px';\n    }\n\n    return unit(padding);\n  }\n\n  /**\n   * Observes the required clone count and refreshes the carousel if necessary.\n   */\n  private checkCloneCount() {\n    const count = this.computeCloneCount();\n\n    if (this.cloneCount !== count) {\n      if (this.cloneCount < count || !count) {\n        this.refreshParts();\n      }\n    }\n  }\n\n  private onNextArrowClick(_event: MouseEvent) {\n    this.goNext(true);\n  }\n\n  private onPrevArrowClick(_event: MouseEvent) {\n    this.goPrev(true);\n  }\n\n  /**\n   * Returns the footer the element draws for its own controls, drawing it the first time. It goes\n   * right after the track, or right before it for a carousel whose controls sit above the slides.\n   */\n  private getFooter() {\n    if (!this.footer) {\n      this.footer = document.createElement('div');\n      this.footer.id = 'footer';\n      if (this.dataset.trackPosition === 'after-controls') {\n        this.track.before(this.footer);\n      } else {\n        this.track.after(this.footer);\n      }\n    }\n\n    return this.footer;\n  }\n\n  private initArrows() {\n    if (!this.currentOptions.arrows) {\n      return;\n    }\n\n    // The arrows go in a footer row under the track, which the drag bar joins when it shows.\n    this.arrowsWrapper = document.createElement('div');\n    this.arrowsWrapper.id = 'arrows';\n\n    // The stylesheet lays out the arrows above, beside, on the sides, or at the edges of the track\n    // from this\n    const position = this.currentOptions.arrowsPosition;\n    if (position && position !== 'footer') {\n      this.arrowsWrapper.dataset.arrowsPosition = position;\n    }\n\n    // Arrows beside the track turn the whole element into a grid, which a rule in a shadow root can\n    // only do from an attribute on the element itself\n    if (position === 'beside') {\n      this.dataset.arrowsBeside = 'true';\n    }\n\n    this.prevArrow = createArrow(true, this.currentOptions.arrowIcon);\n    this.nextArrow = createArrow(false, this.currentOptions.arrowIcon);\n\n    if (this.dataset.arrowClickTrack === 'true') {\n      this.prevArrow.dataset.clickTrack = 'Carousel Previous Arrow';\n      this.nextArrow.dataset.clickTrack = 'Carousel Next Arrow';\n    }\n\n    this.arrowsWrapper.append(this.prevArrow, this.nextArrow);\n    this.getFooter().append(this.arrowsWrapper);\n\n    this.nextArrow.addEventListener('click', this.onNextArrowClickBound);\n    this.prevArrow.addEventListener('click', this.onPrevArrowClickBound);\n    this.updateArrows();\n    this.prevArrow.setAttribute('aria-controls', this.track.id);\n    this.nextArrow.setAttribute('aria-controls', this.track.id);\n  }\n\n  private destroyArrows() {\n    if (this.prevArrow && this.nextArrow) {\n      this.nextArrow.removeEventListener('click', this.onNextArrowClickBound);\n      this.prevArrow.removeEventListener('click', this.onPrevArrowClickBound);\n      this.arrowsWrapper.remove();\n      delete this.dataset.arrowsBeside;\n      this.prevArrow = null;\n      this.nextArrow = null;\n    }\n  }\n\n  /**\n   * Updates status of arrows, such as `disabled` and `aria-label`.\n   */\n  private updateArrows() {\n    const prev = this.prevArrow;\n    const next = this.nextArrow;\n    if (prev && next) {\n      const prevIndex = this.getPrevIndex();\n      const nextIndex = this.getNextIndex();\n      // When the previous arrow would wrap to a later slide, or the next arrow to an earlier one,\n      // the label says where it goes\n      let prevLabel = 'Previous slide';\n      if (prevIndex > -1 && this.currentIndex < prevIndex) {\n        prevLabel = 'Go to last slide';\n      }\n\n      let nextLabel = 'Next slide';\n      if (nextIndex > -1 && this.currentIndex > nextIndex) {\n        nextLabel = 'Go to first slide';\n      }\n\n      prev.disabled = prevIndex < 0;\n      next.disabled = nextIndex < 0;\n\n      prev.setAttribute('aria-label', prevLabel);\n      next.setAttribute('aria-label', nextLabel);\n    }\n  }\n\n  /**\n   * Initializes some parameters. Needs to check the number of slides since the current index may be\n   * out of the range after refresh. The process order must be Elements -> Controller -> Move.\n   */\n  private updateIndexBounds() {\n    this.slideCount = this.slideElements.length;\n    this.perMove = this.currentOptions.perMove;\n    this.perPage = this.currentOptions.perPage;\n    this.endIndex = this.getEndIndex();\n\n    // With `omitEnd` the carousel can't go past the end index, otherwise it can reach the last\n    // slide\n    let maxIndex = this.slideCount - 1;\n    if (this.currentOptions.omitEnd) {\n      maxIndex = this.endIndex;\n    }\n\n    const index = clamp(this.currentIndex, 0, maxIndex);\n\n    if (index !== this.currentIndex) {\n      this.currentIndex = index;\n      this.reposition();\n    }\n  }\n\n  private initPagination() {\n    if (this.currentOptions.pagination) {\n      this.createPagination();\n      this.updatePagination();\n    }\n  }\n\n  /**\n   * Creates the pagination element and appends it to the carousel.\n   */\n  private createPagination() {\n    // With `focus` set, every slide up to the end index gets its own dot. Otherwise the slides are\n    // grouped into pages of `perPage`.\n    let pageCount;\n    if (this.currentOptions.focus === undefined) {\n      const slideCount = this.slideElements.length;\n      pageCount = Math.ceil(slideCount / this.currentOptions.perPage);\n    } else {\n      pageCount = this.getEndIndex() + 1;\n    }\n\n    // In a centered footer the dots go between the arrows the element drew, or at the end of the\n    // footer when it holds no arrows\n    this.paginationList = document.createElement('ul');\n    this.paginationList.id = 'pagination';\n    if (this.footer && this.dataset.controlsPosition === 'center' && this.prevArrow) {\n      this.prevArrow.after(this.paginationList);\n    } else if (this.footer && this.dataset.controlsPosition === 'center') {\n      this.footer.append(this.paginationList);\n    } else {\n      this.track.parentNode.append(this.paginationList);\n    }\n\n    const list = this.paginationList;\n    list.setAttribute('role', 'tablist');\n    list.setAttribute('aria-label', 'Select a slide to show');\n\n    for (let page = 0; page < pageCount; page++) {\n      const listItem = document.createElement('li');\n      list.append(listItem);\n\n      const button = document.createElement('button');\n      button.classList.add('pagination-page');\n      button.setAttribute('type', 'button');\n      listItem.append(button);\n      // An id in our shadow root can't point at a slide outside it, so the dot points at the track\n      // the way the arrows do\n\n      let label = `Go to slide ${page + 1}`;\n      if (this.currentOptions.focus === undefined && this.currentOptions.perPage > 1) {\n        label = `Go to page ${page + 1}`;\n      }\n\n      button.addEventListener('click', this.onPaginationClickBound);\n      button.addEventListener('keydown', this.onPaginationKeyDownBound);\n\n      listItem.setAttribute('role', 'presentation');\n      button.setAttribute('role', 'tab');\n      button.setAttribute('aria-controls', this.track.id);\n      button.setAttribute('aria-label', label);\n      button.setAttribute('tabindex', '-1');\n\n      this.paginationItems.push({ listItem, button, page });\n    }\n  }\n\n  private updatePagination() {\n    const prev = this.getPaginationItemAt(this.getIndex(true));\n    const curr = this.getPaginationItemAt(this.getIndex());\n\n    if (prev) {\n      const button = prev.button;\n      button.removeAttribute('aria-selected');\n      button.setAttribute('tabindex', '-1');\n    }\n\n    if (curr) {\n      const button = curr.button;\n      button.setAttribute('aria-selected', 'true');\n      button.removeAttribute('tabindex');\n    }\n  }\n\n  /**\n   * Returns a Slide object at the specified index.\n   *\n   * @param index A slide index\n   *\n   * @returns A Slide object if available, or otherwise `undefined`.\n   */\n  private getSlideAt(index: number) {\n    return this.slides.find(slide => slide.index === index);\n  }\n\n  /**\n   * Checks if the number of slides is over than the `perPage` option, including clones.\n   *\n   * @returns `true` if there are enough slides, or otherwise `false`.\n   */\n  private hasEnoughSlides() {\n    return this.slides.length > this.currentOptions.perPage;\n  }\n\n  private getPaginationItemAt(index: number) {\n    return this.paginationItems[this.getPageOfIndex(index)];\n  }\n\n  /**\n   * Moves to the page of the pagination dot that was clicked.\n   *\n   * @see https://www.w3.org/WAI/tutorials/carousels/functionality/\n   */\n  private onPaginationClick(event: MouseEvent) {\n    const item = this.paginationItems.find(entry => entry.button === event.currentTarget);\n    this.goToPage(item.page, true);\n  }\n\n  /**\n   * Moves focus and the carousel between pages with the arrow, Home, and End keys while a\n   * pagination dot has focus.\n   *\n   * @see https://www.w3.org/TR/2021/NOTE-wai-aria-practices-1.2-20211129/#keyboard-interaction-21\n   */\n  private onPaginationKeyDown(event: KeyboardEvent) {\n    const page = this.paginationItems.find(entry => entry.button === event.currentTarget).page;\n    const length = this.paginationItems.length;\n    const key = normalizeKey(event);\n\n    let nextPage = -1;\n\n    if (key === 'ArrowRight') {\n      nextPage = (page + 1) % length;\n    } else if (key === 'ArrowLeft') {\n      nextPage = (page - 1 + length) % length;\n    } else if (key === 'Home') {\n      nextPage = 0;\n    } else if (key === 'End') {\n      nextPage = length - 1;\n    }\n\n    const item = this.paginationItems[nextPage];\n\n    if (item) {\n      item.button.focus({ preventScroll: true });\n      this.goToPage(nextPage);\n      event.preventDefault();\n      event.stopPropagation();\n      event.stopImmediatePropagation();\n    }\n  }\n\n  private destroyPagination() {\n    if (this.paginationList) {\n      for (const item of this.paginationItems) {\n        item.button.removeEventListener('click', this.onPaginationClickBound);\n        item.button.removeEventListener('keydown', this.onPaginationKeyDownBound);\n      }\n\n      this.paginationList.remove();\n\n      this.paginationItems = [];\n      this.paginationList = null;\n    }\n  }\n\n  /**\n   * Tells every part that reacts to the window resizing, or to slide images loading, that it\n   * happened, in the order they were set up in mount.\n   */\n  private onResize() {\n    if (this.isMounted) {\n      this.resizeSlides();\n      this.checkCloneCount();\n    }\n  }\n\n  /**\n   * Finds an element only in this carousel, ignoring elements in a nested carousel.\n   *\n   * @returns A found element or undefined.\n   */\n  private find<E extends HTMLElement = HTMLElement>(selector: string) {\n    // A nested carousel would sit in one of the slides, which are outside our shadow root, so\n    // everything in there is ours\n    return this.shadowRoot.querySelector<E>(selector);\n  }\n\n  /**\n   * Sets the track's `aria-live` value. Does nothing when the `live` option is off.\n   */\n  private setAriaLive(value: 'off' | 'polite') {\n    if (this.currentOptions.live) {\n      this.track.setAttribute('aria-live', value);\n    }\n  }\n\n  /**\n   * Registers entries as [ Options, media query string ].\n   *\n   * @param options Options merged to current options when the document matches the query\n   * @param query A query string\n   */\n  private registerMediaQuery(options: Options, query: string) {\n    const queryList = matchMedia(query);\n    queryList.addEventListener('change', this.onMediaChangeBound);\n    this.mediaQueries.push([options, queryList]);\n  }\n\n  private onMediaChange(_event: MediaQueryListEvent) {\n    this.updateMediaQueries();\n  }\n\n  /**\n   * Checks all media queries in entries and updates options.\n   */\n  private updateMediaQueries() {\n    const destroyed = this.state === DESTROYED;\n    const merged = this.mediaQueries.reduce<Options>((merged, entry) => {\n      return merge(merged, entry[1].matches ? entry[0] : {});\n    }, {});\n\n    for (const key of Object.keys(this.currentOptions)) {\n      delete this.currentOptions[<keyof Options>key];\n    }\n\n    this.mergeOptions(merge({}, this.baseOptions, merged));\n\n    if (this.currentOptions.destroy) {\n      this.destroy(false);\n    } else if (destroyed) {\n      this.destroyMediaQueries(true);\n      this.mountParts();\n    }\n  }\n\n  private destroyMediaQueries(completely: boolean) {\n    if (completely) {\n      for (const [, queryList] of this.mediaQueries) {\n        queryList.removeEventListener('change', this.onMediaChangeBound);\n      }\n    }\n  }\n\n  /**\n   * Disables or enables the reduced motion options. Disabling puts those options back to their base\n   * values, even where a breakpoint had set them. This method does nothing when the document does\n   * not match the query.\n   *\n   * @param enable Determines whether to apply the reduced motion options or not\n   */\n  private applyReducedMotion(enable: boolean) {\n    if (matchMedia('(prefers-reduced-motion: reduce)').matches) {\n      if (enable) {\n        Object.assign(this.currentOptions, REDUCED_MOTION);\n      } else {\n        this.currentOptions.speed = this.baseOptions.speed;\n        this.currentOptions.autoplay = this.baseOptions.autoplay;\n      }\n    }\n  }\n\n  /**\n   * Merges options into the current options, and optionally the base options too, then has the\n   * parts react to the change.\n   *\n   * @param newOptions New options\n   * @param base Determines whether to also update base options or not\n   * @param notify If `true`, the parts always react to the change\n   */\n  private mergeOptions(newOptions: Options, base?: boolean, notify?: boolean) {\n    merge(this.currentOptions, newOptions);\n    if (base) {\n      merge(this.baseOptions, newOptions);\n    }\n\n    if (notify || this.state !== MOUNTING) {\n      this.updateParts();\n    }\n  }\n\n  /**\n   * Called when the user clicks or touches the carousel.\n   *\n   * - Needs to prevent the default behaviour when the carousel is busy to deny any action, such as\n   *   dragging images\n   * - IE does not support MouseEvent and TouchEvent constructors\n   * - The `dragging` state always becomes `true` when the user starts dragging while the carousel\n   *   is moving\n   */\n  private onDragPointerDown(event: TouchEvent | MouseEvent) {\n    // Firefox, mostly on Android, sometimes sends a touch event with an empty list of changed\n    // touches. We think a touchstart like that is what gets saved as the base event and makes a\n    // later move throw when it measures against it, though that is unconfirmed. We skip it, so this\n    // touch does not start a drag.\n    if (isTouchEvent(event) && event.changedTouches.length === 0) {\n      console.debug('Ignoring touchstart with no changed touches', event);\n      return;\n    }\n\n    this.shouldPreventClick = false;\n\n    if (!this.isDragDisabled) {\n      const isTouch = isTouchEvent(event);\n\n      // A press on an arrow or a pagination dot is a click on that control, not a drag.\n      const isOnControl = event.target instanceof HTMLElement &&\n        event.target.matches('.pagination-page, .arrow');\n\n      if (!isOnControl && (isTouch || !event.button)) {\n        this.dragTarget = isTouch ? this.track : window;\n        this.isDragging = this.state === MOVING;\n        this.dragPrevBaseEvent = null;\n\n        const target = this.dragTarget;\n        const options: AddEventListenerOptions = { passive: false, capture: true };\n        target.addEventListener('touchmove', this.onDragPointerMoveBound, options);\n        target.addEventListener('mousemove', this.onDragPointerMoveBound, options);\n        target.addEventListener('touchend', this.onDragPointerUpBound, options);\n        target.addEventListener('touchcancel', this.onDragPointerUpBound, options);\n        target.addEventListener('mouseup', this.onDragPointerUpBound, options);\n        target.addEventListener('click', this.onDragPointerUpBound, options);\n        this.cancelMove();\n        this.saveDragBase(event);\n      }\n    }\n  }\n\n  private onDragPointerMove(event: Event) {\n    if (!isPointerEvent(event)) {\n      return;\n    }\n\n    // Firefox, mostly on Android, sometimes sends a touchmove with an empty list of changed\n    // touches. There is no touch to read a coordinate from, so the drag math further down would\n    // throw. We skip that event, which costs one frame of drag movement. Skipping here also keeps\n    // the event from being saved as the base event that later moves measure against.\n    if (isTouchEvent(event) && event.changedTouches.length === 0) {\n      console.debug('Ignoring touchmove with no changed touches', event);\n      return;\n    }\n\n    if (this.state !== DRAGGING) {\n      this.state = DRAGGING;\n    }\n\n    if (event.cancelable) {\n      if (this.isDragging) {\n        // Past the first or last slide of a slide carousel, the list moves only a fifth as far as\n        // the pointer, so it drags with some resistance.\n        let friction = 1;\n        if (this.isDraggedPastEdge && this.currentOptions.transition === 'slide') {\n          friction = 5;\n        }\n\n        this.translateTo(this.dragBasePosition + this.getDragDistance(event) / friction);\n\n        // While the pointer stays down, we save a fresh base coord and time every 200ms.\n        const expired = this.getDragDuration(event) > 200;\n        const wasExceeded = this.isDraggedPastEdge;\n        this.isDraggedPastEdge = this.isPositionExceedingLimit();\n        const hasExceeded = this.isDraggedPastEdge !== wasExceeded;\n\n        if (expired || hasExceeded) {\n          this.saveDragBase(event);\n        }\n\n        this.shouldPreventClick = true;\n\n        if (this.isSlidebarEnabled && this.currentOptions.transition !== 'fade') {\n          const newPosition = this.getSlidebarPositionForTrack();\n          this.handlePosition = this.clampSlidebarHandlePosition(newPosition);\n          this.slidebarHandle.style.transform = `translateX(${this.handlePosition}px)`;\n        }\n\n        event.preventDefault();\n      } else if (Math.abs(this.getDragDistance(event)) >\n        Math.abs(this.getDragDistance(event, true))) {\n        // The pointer moved more sideways than up or down, so this is a drag along the carousel\n        // rather than a page scroll. A touch has to move 10px before it counts as a drag rather\n        // than a tap. A mouse counts at once.\n        const threshold = isTouchEvent(event) ? 10 : 0;\n        this.isDragging = Math.abs(this.getDragDistance(event)) > threshold;\n        event.preventDefault();\n      }\n    }\n  }\n\n  /**\n   * Called when the user releases pointing devices. Needs to move the carousel when:\n   *\n   * - The user drags the carousel and the distance exceeds the threshold\n   * - The user aborted the carousel moving by pointerdown and just released it without dragging the\n   *   carousel\n   *\n   * @param event The event, which only gets handled when it is a TouchEvent or MouseEvent\n   */\n  private onDragPointerUp(event: Event) {\n    if (!isPointerEvent(event)) {\n      return;\n    }\n\n    if (this.state === DRAGGING) {\n      this.state = IDLE;\n    }\n\n    if (this.isDragging) {\n      this.moveAfterDrag(event);\n      event.preventDefault();\n    }\n\n    this.removeDragPointerListeners();\n    this.isDragging = false;\n  }\n\n  /**\n   * Saves data at the specific moment.\n   */\n  private saveDragBase(event: TouchEvent | MouseEvent) {\n    this.dragPrevBaseEvent = this.dragBaseEvent;\n    this.dragBaseEvent = event;\n    this.dragBasePosition = this.getPosition();\n  }\n\n  /**\n   * Calculates the destination by the drag velocity and moves the carousel. If motion is reduced,\n   * restores transition speed to the initial value because it's \"essential\" motion for the user to\n   * recognize what happens on the carousel.\n   */\n  private moveAfterDrag(event: TouchEvent | MouseEvent) {\n    // The drag speed in pixels per millisecond since the last sample. It stays zero when that\n    // sample is 200ms old or more, or when the list was dragged past an end of a carousel that\n    // doesn't loop.\n    let velocity = 0;\n\n    // Firefox sometimes sends a touchmove with no changed touches, so we check the touchend for the\n    // same thing. A touchend like that has no coordinate to measure speed from. We leave the speed\n    // at zero, so the list just settles on the nearest slide. Nobody has seen this happen on a\n    // touchend, so this check may be defensive paranoia.\n    const hasPoint = !isTouchEvent(event) || event.changedTouches.length > 0;\n\n    if (hasPoint && (this.currentOptions.transition === 'loop' || !this.isDraggedPastEdge)) {\n      const time = this.getDragDuration(event);\n\n      if (time && time < 200) {\n        velocity = this.getDragDistance(event) / time;\n      }\n    }\n\n    // A flick carries the list on from where it is, farther the faster it was, up to\n    // `flickMaxPages` list widths.\n    const flickPower = this.currentOptions.flickPower || 600;\n    const flickMaxPages = this.currentOptions.flickMaxPages || 1;\n    const throwDistance = Math.abs(velocity) * flickPower;\n    const maxDistance = this.getListSize() * flickMaxPages;\n    const distance = Math.min(throwDistance, maxDistance);\n    const destination = this.getPosition() + sign(velocity) * distance;\n\n    const rewind = this.currentOptions.rewind && this.currentOptions.rewindByDrag;\n\n    this.applyReducedMotion(false);\n\n    if (this.currentOptions.transition === 'fade') {\n      if (velocity > 0) {\n        if (rewind) {\n          this.goPrev();\n        } else {\n          this.goBy(-1);\n        }\n      } else if (rewind) {\n        this.goNext();\n      } else {\n        this.goBy(1);\n      }\n    } else if (this.currentOptions.transition === 'slide' && this.isDraggedPastEdge && rewind) {\n      if (this.isPositionExceedingLimit(true)) {\n        this.goNext();\n      } else {\n        this.goPrev();\n      }\n    } else {\n      // The transition reads the release speed so the snap can start out at about the speed the\n      // pointer was moving. The move sets up the transition right away, so we can clear it again\n      // straight after.\n      this.releaseVelocity = velocity;\n      const closest = this.getIndexAt(destination);\n      const index = this.currentOptions.transition === 'slide' ?\n        clamp(closest, 0, this.endIndex) :\n        closest;\n      this.goTo(index, true);\n      this.releaseVelocity = 0;\n    }\n\n    this.applyReducedMotion(true);\n  }\n\n  /**\n   * Returns the coord difference between the provided and base events.\n   *\n   * @param event The pointer event to measure from the base event\n   * @param orthogonal If `true`, returns the coord of the orthogonal axis against the drag one\n   *\n   * @returns The difference of the coord.\n   */\n  private getDragDistance(event: TouchEvent | MouseEvent, orthogonal?: boolean) {\n    return getCoord(event, orthogonal) - getCoord(this.getDragBaseEvent(event), orthogonal);\n  }\n\n  /**\n   * Returns the elapsed time from the base event to `event`.\n   *\n   * @returns The elapsed time in milliseconds.\n   */\n  private getDragDuration(event: TouchEvent | MouseEvent) {\n    return event.timeStamp - this.getDragBaseEvent(event).timeStamp;\n  }\n\n  /**\n   * Returns the base event. If the base event is same with `event`, returns previous one.\n   *\n   * @returns A base event.\n   */\n  private getDragBaseEvent(event: TouchEvent | MouseEvent) {\n    if (this.dragBaseEvent === event && this.dragPrevBaseEvent) {\n      return this.dragPrevBaseEvent;\n    }\n\n    return this.dragBaseEvent;\n  }\n\n  /**\n   * Checks if the provided position exceeds the minimum or maximum limit or not.\n   *\n   * @param max `true` for testing max, `false` for min, and `undefined` for both\n   * @param position A position to test. If omitted, tests the current position\n   *\n   * @returns `true` if the position exceeds the limit, or otherwise `false`.\n   */\n  private isPositionExceedingLimit(max?: boolean | undefined, position?: number) {\n    const tested = position === undefined ? this.getPosition() : position;\n    const exceededMin = max !== true && tested > this.getPositionLimit(false);\n    const exceededMax = max !== false && tested < this.getPositionLimit(true);\n    return exceededMin || exceededMax;\n  }\n\n  /**\n   * Removes the move and up listeners a press added to the drag target.\n   */\n  private removeDragPointerListeners() {\n    const target = this.dragTarget;\n    if (target) {\n      target.removeEventListener('touchmove', this.onDragPointerMoveBound, { capture: true });\n      target.removeEventListener('mousemove', this.onDragPointerMoveBound, { capture: true });\n      target.removeEventListener('touchend', this.onDragPointerUpBound, { capture: true });\n      target.removeEventListener('touchcancel', this.onDragPointerUpBound, { capture: true });\n      target.removeEventListener('mouseup', this.onDragPointerUpBound, { capture: true });\n      target.removeEventListener('click', this.onDragPointerUpBound, { capture: true });\n    }\n  }\n\n  /**\n   * Called when the track element is clicked. Disables click any elements inside it while dragging.\n   */\n  private onDragClick(event: MouseEvent) {\n    if (!this.isDragDisabled && this.shouldPreventClick) {\n      event.preventDefault();\n      event.stopPropagation();\n      event.stopImmediatePropagation();\n    }\n  }\n\n  /**\n   * Clears the inline transition the handle gets for an animated move, once that move ends.\n   */\n  private onSlidebarHandleTransitionEnd(_event: TransitionEvent) {\n    this.slidebarHandle.style.transition = '';\n  }\n\n  private onSlidebarMouseDown(_event: MouseEvent) {\n    // Adding the same function twice does nothing, so a second press can't stack listeners.\n    addEventListener('mousemove', this.onSlidebarMouseMoveBound);\n    addEventListener('mouseup', this.onSlidebarMouseUpBound);\n  }\n\n  private onSlidebarMouseMove(event: MouseEvent) {\n    this.dragSlidebarHandle(this.handlePosition + event.movementX);\n  }\n\n  private onSlidebarMouseUp(_event: MouseEvent) {\n    this.alignTrackToSlidebar();\n    removeEventListener('mousemove', this.onSlidebarMouseMoveBound);\n    removeEventListener('mouseup', this.onSlidebarMouseUpBound);\n  }\n\n  /**\n   * Called when a touch starts on the bar or the handle. Nothing moves yet, because we wait to see\n   * which way the thumb goes. A sideways drag moves the carousel, and an up or down one is left to\n   * scroll the page.\n   */\n  private onSlidebarTouchStart(event: TouchEvent) {\n    const touch = event.touches[0];\n    this.slidebarTouchStartX = touch.clientX;\n    this.slidebarTouchStartY = touch.clientY;\n    this.previousTouchX = touch.clientX;\n    this.isSlidebarTouchOnHandle = event.target === this.slidebarHandle;\n    this.slidebarTouchAxis = 'pending';\n  }\n\n  private onSlidebarTouchMove(event: TouchEvent) {\n    if (this.slidebarTouchAxis !== 'pending' && this.slidebarTouchAxis !== 'x') {\n      return;\n    }\n\n    const touch = event.touches[0];\n\n    if (this.slidebarTouchAxis === 'pending') {\n      const distanceX = Math.abs(touch.clientX - this.slidebarTouchStartX);\n      const distanceY = Math.abs(touch.clientY - this.slidebarTouchStartY);\n      if (Math.max(distanceX, distanceY) < SLIDEBAR_TOUCH_SLOP) {\n        return;\n      }\n\n      if (distanceY > distanceX) {\n        this.slidebarTouchAxis = 'y';\n        return;\n      }\n\n      this.slidebarTouchAxis = 'x';\n\n      // A drag that starts on the bar outside the handle jumps the handle under the thumb first, so\n      // the thumb does not have to land on the handle to drag it.\n      if (!this.isSlidebarTouchOnHandle) {\n        this.dragSlidebarHandle(this.getSlidebarTouchX(touch) -\n          this.slidebarHandle.offsetWidth / 2);\n        this.previousTouchX = touch.clientX;\n      }\n    }\n\n    // Keeps the page from scrolling while the thumb drags the carousel\n    if (event.cancelable) {\n      event.preventDefault();\n    }\n\n    const movementX = touch.clientX - this.previousTouchX;\n    this.previousTouchX = touch.clientX;\n    this.dragSlidebarHandle(this.handlePosition + movementX);\n  }\n\n  private onSlidebarTouchEnd(event: TouchEvent) {\n    const axis = this.slidebarTouchAxis;\n    this.slidebarTouchAxis = 'none';\n\n    if (axis === 'x') {\n      this.alignTrackToSlidebar();\n    } else if (axis === 'pending' && !this.isSlidebarTouchOnHandle &&\n      event.changedTouches.length > 0) {\n      // A tap on the bar acts like a click on it. Firefox sometimes sends a touch event with no\n      // changed touches, and then there is no point to read, so the tap does nothing.\n      const pressX = this.getSlidebarTouchX(event.changedTouches[0]);\n      this.goToSlidebarPress(pressX, pressX < this.handlePosition ? -1 : 1);\n    }\n\n    // Without this, a tap also sends the mouse events a browser fakes after a touch, and the\n    // mousedown listener on the bar would move the carousel a second time.\n    if (axis !== 'y' && event.cancelable) {\n      event.preventDefault();\n    }\n  }\n\n  /**\n   * The browser can cancel a touch instead of ending it, for example when the thumb slides off the\n   * page into the browser's own bars.\n   */\n  private onSlidebarTouchCancel(_event: TouchEvent) {\n    if (this.slidebarTouchAxis === 'x') {\n      this.alignTrackToSlidebar();\n    }\n\n    this.slidebarTouchAxis = 'none';\n  }\n\n  /**\n   * Where a touch sits along the bar, in pixels from its left edge.\n   */\n  private getSlidebarTouchX(touch: Touch) {\n    return touch.clientX - this.slidebar.getBoundingClientRect().left;\n  }\n\n  /**\n   * Called when the visitor presses on the bar outside the handle.\n   */\n  private onSlidebarBackgroundMouseDown(event: MouseEvent) {\n    if (event.button !== 0 || event.target !== event.currentTarget) {\n      return;\n    }\n\n    // A click only arrives when the release lands on the bar too, so a press that wobbled off the\n    // bar before letting go would do nothing. Like a native scrollbar's gutter, we act on the press\n    // instead. While the press is held we push the handle toward the pointer at a steady speed, the\n    // same way a drag of the handle moves it. Once it catches up it follows the pointer like a\n    // drag, and once the press lets go we snap to a slide like the end of a drag does.\n    this.slidebarPressX = event.offsetX;\n    this.slidebarPressDirection = event.offsetX < this.handlePosition ? -1 : 1;\n    this.slidebarPressTime = now();\n    this.slidebarPressStartTime = this.slidebarPressTime;\n    this.isSlidebarPressCaughtUp = false;\n    addEventListener('mousemove', this.onSlidebarBackgroundMouseMoveBound);\n    addEventListener('mouseup', this.onSlidebarBackgroundMouseUpBound);\n    this.slidebarPressFrame = requestAnimationFrame(this.pushSlidebarHandleBound);\n  }\n\n  private onSlidebarBackgroundMouseMove(event: MouseEvent) {\n    this.slidebarPressX = event.clientX - this.slidebar.getBoundingClientRect().left;\n  }\n\n  private onSlidebarBackgroundMouseUp(_event: MouseEvent) {\n    this.stopSlidebarPress();\n\n    // A held press that caught up is a drag, so it lands wherever the pointer took it, and one let\n    // go partway stops where the handle got to.\n    if (now() - this.slidebarPressStartTime >= SLIDEBAR_CLICK_DURATION) {\n      this.alignTrackToSlidebar();\n      return;\n    }\n\n    this.goToSlidebarPress(this.slidebarPressX, this.slidebarPressDirection);\n  }\n\n  /**\n   * Goes to the slide under a click or a tap on the bar. When that is the slide we are already on,\n   * we still move one slide toward the press, so a click on the bar always does something.\n   *\n   * @param pressX Where the press landed, in pixels from the bar's left edge.\n   * @param direction Which side of the handle the press started on, -1 for left and 1 for right.\n   */\n  private goToSlidebarPress(pressX: number, direction: number) {\n    const handlePosition = pressX - this.slidebarHandle.offsetWidth / 2;\n    let index: number;\n    if (this.currentOptions.transition === 'fade') {\n      // The handle's travel is split into one segment per slide\n      const segmentWidth = this.maxHandlePosition / this.slides.length;\n      index = Math.round(handlePosition / segmentWidth);\n    } else {\n      index = this.getIndexAt(this.getTrackPositionForSlidebar(handlePosition));\n    }\n\n    if (index !== this.currentIndex) {\n      this.goTo(index, true);\n    } else if (direction < 0) {\n      this.goPrev(true);\n    } else {\n      this.goNext(true);\n    }\n  }\n\n  private stopSlidebarPress() {\n    cancelAnimationFrame(this.slidebarPressFrame);\n    removeEventListener('mousemove', this.onSlidebarBackgroundMouseMoveBound);\n    removeEventListener('mouseup', this.onSlidebarBackgroundMouseUpBound);\n  }\n\n  /**\n   * Moves the handle one frame's worth toward the held press. Runs every frame until the press lets\n   * go.\n   */\n  private pushSlidebarHandle(time: number) {\n    const elapsed = Math.max(0, time - this.slidebarPressTime);\n    this.slidebarPressTime = time;\n\n    const target = this.clampSlidebarHandlePosition(this.slidebarPressX -\n      this.slidebarHandle.offsetWidth / 2);\n    const distance = target - this.handlePosition;\n\n    if (Math.abs(distance) < 1) {\n      this.isSlidebarPressCaughtUp = true;\n    }\n\n    if (this.isSlidebarPressCaughtUp) {\n      this.dragSlidebarHandle(target);\n    } else {\n      const step = Math.min(Math.abs(distance), SLIDEBAR_PRESS_SPEED * elapsed);\n      this.dragSlidebarHandle(this.handlePosition + Math.sign(distance) * step);\n    }\n\n    this.slidebarPressFrame = requestAnimationFrame(this.pushSlidebarHandleBound);\n  }\n\n  private removeSlidebarWindowListeners() {\n    this.stopSlidebarPress();\n    removeEventListener('mousemove', this.onSlidebarMouseMoveBound);\n    removeEventListener('mouseup', this.onSlidebarMouseUpBound);\n  }\n\n  private toggleSlidebar() {\n    // We need to both check hasEnoughSlides() and isOverflowing(). Depending on the options, or due\n    // to some bugs, solely relying on one of these methods has led to issues.\n    if (this.currentOptions.slidebar && this.hasEnoughSlides() &&\n      this.isOverflowing()) {\n      this.enableSlidebar();\n    } else {\n      this.disableSlidebar();\n    }\n  }\n\n  /**\n   * Enables the slidebar functionality, adding the necessary event listeners.\n   */\n  private enableSlidebar() {\n    if (!this.hasDrawnSlidebar) {\n      // Render the slidebar and size its handle the first time it is shown.\n      if (!this.slidebar) {\n        this.slidebar = document.createElement('div');\n        this.slidebar.id = 'slider';\n\n        this.slidebarHandle = document.createElement('div');\n        this.slidebarHandle.id = 'slider-handle';\n\n        this.slidebarHandle.style.width = this.calculateSlidebarHandleWidth();\n\n        this.slidebar.appendChild(this.slidebarHandle);\n      }\n\n      // The drag bar goes first in the footer the element drew for its own arrows, or at the end of\n      // the carousel when there is no such footer, the footer is centered, or the footer sits\n      // beside the track\n      let inFooter = !!this.footer;\n      if (this.dataset.controlsPosition === 'center') {\n        inFooter = false;\n      } else if (this.currentOptions.arrowsPosition === 'beside') {\n        inFooter = false;\n      }\n\n      if (inFooter) {\n        this.footer.prepend(this.slidebar);\n      } else {\n        this.shadowRoot.append(this.slidebar);\n      }\n    }\n\n    this.slidebar.hidden = false;\n\n    // Without this delay, the first page of the carousel is not clickable. There’s an issue with\n    // calling the goTo() method immediately when the slidebar is mounted.\n    setTimeout(() => this.updateSlidebarSize());\n\n    this.isSlidebarEnabled = true;\n\n    this.slidebarHandle.addEventListener('mousedown', this.onSlidebarMouseDownBound);\n    this.slidebarHandle.addEventListener('transitionend', this.onSlidebarHandleTransitionEndBound);\n    this.slidebar.addEventListener('mousedown', this.onSlidebarBackgroundMouseDownBound);\n    this.slidebar.addEventListener('touchstart', this.onSlidebarTouchStartBound, { passive: true });\n    this.slidebar.addEventListener('touchmove', this.onSlidebarTouchMoveBound, { passive: false });\n    this.slidebar.addEventListener('touchend', this.onSlidebarTouchEndBound, { passive: false });\n    this.slidebar.addEventListener('touchcancel', this.onSlidebarTouchCancelBound);\n  }\n\n  /**\n   * Disables the slidebar functionality, removing the event listeners and hiding the slidebar.\n   */\n  private disableSlidebar() {\n    // Only a slidebar that has been shown has anything to undo\n    if (this.slidebar) {\n      this.slidebar.hidden = true;\n      this.isSlidebarEnabled = false;\n      this.removeSlidebarElementListeners();\n    }\n  }\n\n  private removeSlidebarElementListeners() {\n    this.slidebarHandle.removeEventListener('mousedown', this.onSlidebarMouseDownBound);\n    this.slidebarHandle.removeEventListener('transitionend',\n      this.onSlidebarHandleTransitionEndBound);\n    this.slidebar.removeEventListener('mousedown', this.onSlidebarBackgroundMouseDownBound);\n    this.slidebar.removeEventListener('touchstart', this.onSlidebarTouchStartBound);\n    this.slidebar.removeEventListener('touchmove', this.onSlidebarTouchMoveBound);\n    this.slidebar.removeEventListener('touchend', this.onSlidebarTouchEndBound);\n    this.slidebar.removeEventListener('touchcancel', this.onSlidebarTouchCancelBound);\n  }\n\n  private updateSlidebarSize() {\n    this.slidebarHandle.style.width = this.calculateSlidebarHandleWidth();\n\n    // Work out the furthest the handle and the track can go, so the two stay in sync.\n    this.maxHandlePosition = this.slidebar.offsetWidth - this.slidebarHandle.offsetWidth;\n    this.maxTrackPosition = this.getSlidesSize() - this.getListSize();\n\n    this.goTo(this.currentIndex, true);\n  }\n\n  /**\n   * Calculates the width of the handle.\n   *\n   * The function works depending upon the 'mode' the carousel is in. If it's in 'fade' mode, the\n   * width is calculated based on the proportion of 'perPage' option to the total number of slides,\n   * scaled to fit a percentage scale (0-100).\n   *\n   * For other modes, the handle width is determined by the ratio of list size to the total size of\n   * the slides, also expressed as a percentage.\n   *\n   * @returns The calculated width of the handle.\n   */\n  private calculateSlidebarHandleWidth() {\n    let handleWidth;\n    if (this.currentOptions.transition === 'fade') {\n      handleWidth = (this.currentOptions.perPage / this.slides.length) * 100;\n    } else {\n      handleWidth = (this.getListSize() / this.getSlidesSize()) * 100;\n    }\n\n    return `${handleWidth}%`;\n  }\n\n  /**\n   * Adjusts and returns the intended position of the handle within the boundaries of a carousel.\n   * Checks whether the new position is within the range [0, maxPosition]. If the intended position\n   * is less than 0, it will be set to 0. If it's larger than maxPosition, it will be set to\n   * maxPosition. If it's the same as the current position, it will return this value without\n   * changes.\n   *\n   * @param toPosition The intended new position\n   *\n   * @returns The position kept within the range [0, maxPosition].\n   */\n  private clampSlidebarHandlePosition(toPosition: number) {\n    let newPosition = toPosition;\n    if (newPosition <= 0) {\n      newPosition = 0;\n    } else if (newPosition >= this.maxHandlePosition) {\n      newPosition = this.maxHandlePosition;\n    }\n\n    return newPosition;\n  }\n\n  /**\n   * Calculates the handle's position based on the current track position.\n   *\n   * @param trackPosition Optional track position for calculation. If not provided the value from\n   *   `getPosition()` is taken. We don't need to pass a new track position if this function used to\n   *   get the slidebar position when the carousel is dragged, but it's necessary if used when the\n   *   carousel is moved to a certain slide because the position at the end of moving should be\n   *   taken instead of the carousel's current track position.\n   */\n  private getSlidebarPositionForTrack(trackPosition?: number) {\n    const currentTrackPosition = -1 * (trackPosition ?? this.getPosition());\n    const ratio = currentTrackPosition / this.maxTrackPosition;\n    const newSlideBarPosition = ratio * this.maxHandlePosition;\n    return newSlideBarPosition;\n  }\n\n  /**\n   * Processes and restricts handle movement within the slidebar bounds.\n   *\n   * @param toPosition Desired new position of the handle.\n   */\n  private dragSlidebarHandle(toPosition: number) {\n    const newPosition = this.clampSlidebarHandlePosition(toPosition);\n\n    // avoid position update if handle position hasn't changed.\n    if (this.handlePosition === newPosition) {\n      return;\n    }\n\n    this.handlePosition = newPosition;\n\n    // A move animation leaves its transition on the handle until the animation ends, and one that\n    // had nowhere to go, like the move when the carousel first sets up, never ends. A drag has to\n    // follow the pointer without easing, so we clear it.\n    this.slidebarHandle.style.transition = '';\n\n    if (this.currentOptions.transition !== 'fade') {\n      const newTrackPosition = this.getTrackPositionForSlidebar(this.handlePosition);\n      this.translateTo(newTrackPosition);\n    }\n\n    // it ensures the DOM updates are synchronized with the browser's refresh rate, avoiding\n    // unnecessary reflows and keeping animations smooth\n    requestAnimationFrame(() => {\n      this.slidebarHandle.style.transform = `translateX(${this.handlePosition}px)`;\n    });\n  }\n\n  /**\n   * Aligns the track position based on the current position of the handle.\n   */\n  private alignTrackToSlidebar() {\n    let index: number;\n\n    if (this.currentOptions.transition === 'fade') {\n      // The handle's travel is split into one segment per slide\n      const segmentWidth = this.maxHandlePosition / this.slides.length;\n      index = Math.round(this.handlePosition / segmentWidth);\n    } else {\n      const currentTrackPosition = this.getPosition();\n      index = this.getIndexAt(currentTrackPosition);\n    }\n\n    this.goTo(index, true);\n  }\n\n  /**\n   * Calculates the track's position based on the handle's position.\n   *\n   * @param handlePosition Position of the slidebar handle.\n   */\n  private getTrackPositionForSlidebar(handlePosition: number) {\n    const ratio = handlePosition / this.maxHandlePosition;\n    const newTrackPosition = -1 * ratio * this.maxTrackPosition;\n    return newTrackPosition;\n  }\n\n  private onKeyDown(event: KeyboardEvent) {\n    if (!this.isKeyboardDisabled) {\n      const key = normalizeKey(event);\n\n      if (key === 'ArrowLeft') {\n        this.goPrev();\n      } else if (key === 'ArrowRight') {\n        this.goNext();\n      }\n    }\n  }\n\n  private addKeyListener() {\n    if (this.currentOptions.keyboard) {\n      this.addEventListener('keydown', this.onKeyDownBound);\n    }\n  }\n\n  private removeKeyListener() {\n    this.removeEventListener('keydown', this.onKeyDownBound);\n  }\n\n  /**\n   * Pauses autoplay while the pointer is over the carousel.\n   */\n  private onAutoplayHover(event: MouseEvent) {\n    this.isHovered = event.type === 'mouseenter';\n    this.syncAutoplay();\n  }\n\n  /**\n   * Pauses autoplay while focus is inside the carousel.\n   */\n  private onAutoplayFocus(event: FocusEvent) {\n    this.isFocusWithin = event.type === 'focusin';\n    this.syncAutoplay();\n  }\n\n  private onAutoplayToggleClick(_event: MouseEvent) {\n    if (this.isAutoplayStopped) {\n      this.playAutoplay();\n    } else {\n      this.pauseAutoplay(true);\n    }\n  }\n\n  /**\n   * Toggles play/pause according to current flags. If autoplay is manually paused, this will do\n   * nothing.\n   */\n  private syncAutoplay() {\n    if (!this.isAutoplayStopped) {\n      if (this.isHovered || this.isFocusWithin) {\n        this.pauseAutoplay(false);\n      } else {\n        this.playAutoplay();\n      }\n    }\n  }\n\n  /**\n   * Starts autoplay and clears all flags.\n   */\n  private playAutoplay() {\n    if (this.autoplayInterval.isPaused() && this.hasEnoughSlides()) {\n      this.autoplayInterval.start();\n      this.isFocusWithin = false;\n      this.isHovered = false;\n      this.isAutoplayStopped = false;\n      this.updateAutoplay();\n\n      if (this.isLiveEnabled) {\n        this.setAriaLive('off');\n      }\n    }\n  }\n\n  /**\n   * Pauses autoplay.\n   *\n   * @param stop If `true`, autoplay keeps paused until `playAutoplay()` is explicitly called\n   */\n  private pauseAutoplay(stop = true) {\n    this.isAutoplayStopped = !!stop;\n    this.updateAutoplay();\n\n    if (!this.autoplayInterval.isPaused()) {\n      this.autoplayInterval.pause();\n\n      if (this.isLiveEnabled) {\n        this.setAriaLive('polite');\n      }\n    }\n  }\n\n  /**\n   * Updates the toggle button status.\n   */\n  private updateAutoplay() {\n    if (this.autoplayToggle) {\n      if (this.isAutoplayStopped) {\n        delete this.autoplayToggle.dataset.playing;\n      } else {\n        this.autoplayToggle.dataset.playing = 'true';\n      }\n\n      const label = this.isAutoplayStopped ? 'Start autoplay' : 'Pause autoplay';\n      this.autoplayToggle.setAttribute('aria-label', label);\n    }\n  }\n\n  /**\n   * Moves the carousel to a slide index. For the next or previous page, use `goNext()` or\n   * `goPrev()`, which respect `perPage` and `perMove`.\n   *\n   * @param index A slide index\n   * @param allowSameIndex Determines whether to allow going to the current index or not\n   * @param callback A callback function invoked after transition ends\n   */\n  private goTo(index: number, allowSameIndex?: boolean, callback?: AnyFunction) {\n    this.moveTo(this.currentOptions.transition === 'loop' ? index : clamp(index, 0, this.endIndex),\n      allowSameIndex, callback);\n  }\n\n  /**\n   * Moves the carousel to a page index.\n   *\n   * @param page A page index\n   * @param allowSameIndex Determines whether to allow going to the current index or not\n   */\n  private goToPage(page: number, allowSameIndex?: boolean) {\n    this.moveTo(this.getIndexOfPage(page), allowSameIndex);\n  }\n\n  private getNextIndex(destination?: boolean) {\n    return this.getAdjacentIndex(false, destination);\n  }\n\n  private getPrevIndex(destination?: boolean) {\n    return this.getAdjacentIndex(true, destination);\n  }\n\n  /**\n   * Returns the current/previous index.\n   *\n   * @param prev Whether to return previous index or not\n   */\n  private getIndex(prev?: boolean) {\n    return prev ? this.prevIndex : this.currentIndex;\n  }\n\n  /**\n   * Returns an adjacent destination index.\n   *\n   * @param prev Determines whether to return a previous or next index\n   * @param destination Determines whether to get a destination index or a slide one\n   *\n   * @returns An adjacent index if available, or otherwise `-1`.\n   */\n  private getAdjacentIndex(prev: boolean, destination?: boolean) {\n    const step = this.perMove || (this.currentOptions.focus !== undefined ? 1 : this.perPage);\n    const snapPage = !(this.perMove || this.currentOptions.focus !== undefined);\n    let destinationIndex = this.computeDestIndex(this.currentIndex + step * (prev ? -1 : 1),\n      this.currentIndex, snapPage);\n\n    // Near either end of a slide carousel, several slides can share the same trimmed position, so\n    // stepping between them moves nothing on screen. When nothing shows which slide you are on, a\n    // click like that looks broken. So in scroll mode we keep stepping until the slides would move,\n    // and end up at -1 when no slide in that direction would move them. The step count is capped so\n    // a carousel that rewinds can't keep wrapping around forever.\n    if (this.currentOptions.arrowBehavior === 'scroll' &&\n      this.currentOptions.transition === 'slide') {\n      const position = this.getPositionOf(this.currentIndex, true);\n      let steps = 0;\n      while (destinationIndex > -1 && steps < this.slideCount &&\n        approximatelyEqual(this.getPositionOf(destinationIndex, true), position, 1)) {\n        destinationIndex = this.computeDestIndex(destinationIndex + step * (prev ? -1 : 1),\n          destinationIndex, snapPage);\n        steps++;\n      }\n    }\n\n    if (destinationIndex === -1 && this.currentOptions.transition === 'slide') {\n      if (!approximatelyEqual(this.getPosition(), this.getPositionLimit(!prev), 1)) {\n        return prev ? 0 : this.endIndex;\n      }\n    }\n\n    return destination ? destinationIndex : this.loopIndex(destinationIndex);\n  }\n\n  /**\n   * Returns the end index where the carousel can go. For example, if the carousel has 10 slides and\n   * the `perPage` option is 3, the carousel can go to the slide 8 (the index is 7). If the\n   * `omitEnd` option is available, computes the index from the slide position.\n   *\n   * @returns An end index.\n   */\n  private getEndIndex() {\n    let end = this.slideCount - (this.currentOptions.focus !== undefined ||\n      (this.currentOptions.transition === 'loop' && this.perMove) ?\n      1 :\n      this.perPage);\n\n    if (this.currentOptions.omitEnd) {\n      while (end > 0) {\n        end--;\n\n        if (this.getPositionOf(this.slideCount - 1, true) !==\n          this.getPositionOf(end, true)) {\n          end++;\n\n          break;\n        }\n      }\n    }\n\n    return clamp(end, 0, this.slideCount - 1);\n  }\n\n  /**\n   * Converts the page index to the slide index.\n   *\n   * @param page A page index to convert\n   *\n   * @returns A slide index.\n   */\n  private getIndexOfPage(page: number) {\n    return clamp(this.currentOptions.focus !== undefined ? page : this.perPage * page, 0,\n      this.endIndex);\n  }\n\n  /**\n   * Converts the slide index to the page index.\n   *\n   * @param index An index to convert\n   *\n   * @returns A page index.\n   */\n  private getPageOfIndex(index: number) {\n    return this.currentOptions.focus !== undefined ?\n      Math.min(index, this.endIndex) :\n      Math.floor((index >= this.endIndex ? this.slideCount - 1 : index) /\n        this.perPage);\n  }\n\n  /**\n   * Converts the desired destination index to one the carousel can actually go to.\n   *\n   * @param desired The desired destination index\n   * @param from The index the move starts from\n   * @param snapPage Whether to land on the start of a page\n   *\n   * @returns A destination index, which can be a clone index on a loop carousel, or `-1` when there\n   * is nowhere to go.\n   */\n  private computeDestIndex(desired: number, from: number, snapPage?: boolean) {\n    // Without enough slides to fill the carousel there is nothing to move, unless `focus` lets the\n    // active slide change anyway.\n    if (!this.hasEnoughSlides() && this.currentOptions.focus === undefined) {\n      return -1;\n    }\n\n    if (desired >= 0 && desired <= this.endIndex) {\n      if (snapPage && desired !== from) {\n        return this.getIndexOfPage(this.getPageOfIndex(from) + (desired < from ? -1 : 1));\n      }\n\n      return desired;\n    }\n\n    // A move that starts inside the range and would cross an end lands on that end instead.\n    if (!this.perMove &&\n      (between(0, desired, from, true) || between(this.endIndex, from, desired, true))) {\n      return this.getIndexOfPage(this.getPageOfIndex(desired));\n    }\n\n    if (this.currentOptions.transition === 'loop') {\n      if (snapPage) {\n        // Going back from the first page lands on the last page, which can hold fewer slides\n        const remainder = this.slideCount % this.perPage;\n        const lastPageSize = remainder > 0 ? remainder : this.perPage;\n        return desired < 0 ? -lastPageSize : this.slideCount;\n      }\n\n      return desired;\n    }\n\n    if (this.currentOptions.rewind) {\n      return desired < 0 ? this.endIndex : 0;\n    }\n\n    return -1;\n  }\n\n  /**\n   * Loops the provided index only in the loop mode.\n   *\n   * @param index An index to loop\n   *\n   * @returns A looped index.\n   */\n  private loopIndex(index: number) {\n    if (this.currentOptions.transition !== 'loop') {\n      return index;\n    }\n\n    const looped = (index + this.slideCount) % this.slideCount;\n    return looped || 0;\n  }\n\n  /**\n   * Moves the carousel to a destination index, which can be a clone index on a loop carousel. Does\n   * nothing for `-1`, which means there is nowhere to go.\n   *\n   * @param destinationIndex A destination index, including clones\n   * @param allowSameIndex Determines whether to allow going to the current index or not\n   * @param callback A callback function invoked after transition ends\n   */\n  private moveTo(destinationIndex: number, allowSameIndex?: boolean, callback?: AnyFunction) {\n    const index = this.loopIndex(destinationIndex);\n\n    if (index > -1 && (allowSameIndex || index !== this.currentIndex)) {\n      // A move to the index it is already on, which `allowSameIndex` permits, leaves the previous\n      // index alone.\n      if (index !== this.currentIndex) {\n        this.prevIndex = this.currentIndex;\n        this.currentIndex = index;\n      }\n\n      const prev = this.prevIndex;\n\n      // A clone destination, which only happens on a loop carousel, first jumps the list one full\n      // loop in the direction of travel, so the transition to the real slide looks continuous.\n      if (destinationIndex !== index && this.canShift(destinationIndex > prev)) {\n        this.cancelMove();\n        this.translateTo(this.shiftPosition(this.getPosition(), destinationIndex > prev), true);\n      }\n\n      this.state = MOVING;\n      this.notifyMove(index, prev);\n\n      this.startTransition(index, () => {\n        this.state = IDLE;\n        this.notifyMoved(index, prev);\n        if (callback) {\n          callback();\n        }\n      });\n    }\n  }\n\n  /**\n   * Adds a CSS rule to all slides or containers.\n   *\n   * @param property A property name\n   * @param value A CSS value to add\n   * @param useContainer Determines whether to apply the rule to the container or not\n   */\n  private styleSlides(property: StyleProperty, value: string | number, useContainer?: boolean) {\n    for (const slide of this.slides) {\n      slide.style(property, value, useContainer);\n    }\n  }\n\n  /**\n   * Moves the carousel to the provided position.\n   *\n   * @param position The position to move to\n   * @param preventLoop If `true`, sets the provided position as is\n   */\n  private translateTo(position: number, preventLoop?: boolean) {\n    if (this.currentOptions.transition !== 'fade') {\n      let destination = preventLoop ? position : this.loopPosition(position);\n\n      // With every slide fitting there is nowhere to move, so an aligned carousel ignores the\n      // position it was asked for and holds the row where the align option puts it. The slides size\n      // leaves out the gap after the last slide, so a centered row comes out even.\n      if (this.currentOptions.align && !this.isOverflowing()) {\n        if (this.currentOptions.align === 'center') {\n          destination = (this.getListSize() - this.getSlidesSize(true)) / 2;\n        } else {\n          destination = 0;\n        }\n      }\n\n      this.list.style.transform = `translateX(${destination}px)`;\n      if (position !== destination) {\n        for (const slide of this.slides) {\n          slide.update();\n        }\n      }\n    }\n  }\n\n  /**\n   * Loops the provided position if it exceeds bounds (limit indices).\n   *\n   * @param position A position to loop\n   */\n  private loopPosition(position: number) {\n    if (this.currentOptions.transition === 'loop') {\n      const index = this.getIndexAt(position);\n      const exceededMax = index > this.getEndIndex();\n      const exceededMin = index < 0;\n\n      if (exceededMin || exceededMax) {\n        return this.shiftPosition(position, exceededMax);\n      }\n    }\n\n    return position;\n  }\n\n  /**\n   * Returns the current position.\n   *\n   * @returns The position of the list element.\n   */\n  private getPosition() {\n    const paddingLeft = parseFloat(getComputedStyle(this.track).paddingLeft);\n    const padding = paddingLeft || 0;\n    const listLeft = this.list.getBoundingClientRect().left;\n    const trackLeft = this.track.getBoundingClientRect().left;\n    return listLeft - trackLeft - padding;\n  }\n\n  /**\n   * Returns the limit number that the carousel can move to.\n   *\n   * @param max Determines whether to return the maximum or minimum limit\n   *\n   * @returns The border number.\n   */\n  private getPositionLimit(max: boolean) {\n    return this.getPositionOf(max ? this.getEndIndex() : 0, true);\n  }\n\n  /**\n   * Adds or subtracts the total width of the slides to the provided position.\n   *\n   * @param position A position to shift\n   * @param backwards Determines whether to shift the carousel backwards or forwards\n   *\n   * @returns The shifted position.\n   */\n  private shiftPosition(position: number, backwards: boolean) {\n    const excess = position - this.getPositionLimit(backwards);\n    const size = this.getSlidesSize();\n    const neededShifts = Math.ceil(Math.abs(excess) / size);\n    const shifts = neededShifts > 0 ? neededShifts : 1;\n    return position + size * shifts * (backwards ? 1 : -1);\n  }\n\n  /**\n   * Returns the closest index to the position.\n   *\n   * @param position A position to convert\n   *\n   * @returns The closest index to the position.\n   */\n  private getIndexAt(position: number) {\n    let index = 0;\n    let minDistance = Infinity;\n\n    for (const slide of this.slides) {\n      const slideIndex = slide.index;\n      const distance = Math.abs(this.getPositionOf(slideIndex, true) - position);\n\n      if (distance <= minDistance) {\n        minDistance = distance;\n        index = slideIndex;\n      } else {\n        break;\n      }\n    }\n\n    return index;\n  }\n\n  /**\n   * Converts the slide index to the position.\n   *\n   * @param index An index to convert\n   * @param trimming Whether to trim edge spaces or not\n   *\n   * @returns The position corresponding with the index.\n   */\n  private getPositionOf(index: number, trimming?: boolean) {\n    // The `focus` option offsets the slide from the start of the list.\n    let offset;\n    if (this.currentOptions.focus === 'center') {\n      offset = (this.getListSize() - this.getSlideSize(index, true)) / 2;\n    } else {\n      const focusOffset = this.currentOptions.focus * this.getSlideSize(index);\n      offset = focusOffset || 0;\n    }\n\n    const position = offset - this.getTotalSizeThrough(index - 1);\n\n    // A slide carousel trims the empty space past its first and last slides.\n    if (trimming && this.currentOptions.transition === 'slide') {\n      return clamp(position, 0, this.getListSize() - this.getSlidesSize(true));\n    }\n\n    return position;\n  }\n\n  private cancelTransition() {\n    if (!this.isFadeTransition) {\n      this.list.style.transition = '';\n    }\n  }\n\n  private cancelMove() {\n    this.translateTo(this.getPosition(), true);\n    this.cancelTransition();\n  }\n\n  /**\n   * Checks if there is enough width to shift the carousel.\n   *\n   * @param backwards `true` for checking backwards, or `false` for doing forwards\n   *\n   * @returns `true` if the carousel can be shifted for the specified direction, or otherwise\n   * `false`.\n   */\n  private canShift(backwards: boolean) {\n    const shifted = -this.shiftPosition(this.getPosition(), backwards);\n    return backwards ?\n      shifted >= 0 :\n      shifted <= this.list.scrollWidth -\n      this.track.getBoundingClientRect().width;\n  }\n\n  /**\n   * Starts the transition. The move helpers call this just before the carousel moves.\n   *\n   * @param index A destination index\n   * @param done The callback function that must be called after the transition ends\n   */\n  private startTransition(index: number, done: () => void) {\n    if (this.isFadeTransition) {\n      this.styleSlides('transition', `opacity ${this.currentOptions.speed}ms ${EASING}`);\n      setTimeout(done);\n      return;\n    }\n\n    const destination = this.getPositionOf(index, true);\n    const position = this.getPosition();\n\n    const distance = destination - position;\n\n    if (Math.abs(distance) >= 1 && this.currentOptions.speed >= 1) {\n      // A fixed duration makes the snap after a drag release move at whatever speed the leftover\n      // distance works out to, which can be much faster or slower than the finger was moving. So\n      // when the list is carrying on in the direction it was dragged, we size the duration to the\n      // release speed instead. The easing curve starts out at four times its average speed, so four\n      // times the distance over the release speed makes the snap start at about the release speed.\n      // We clamp it so a tiny distance doesn't snap instantly and a slow release doesn't crawl.\n      let duration = this.currentOptions.speed;\n      const velocity = this.releaseVelocity;\n      if (velocity !== 0 && sign(velocity) === sign(distance)) {\n        duration = clamp(4 * Math.abs(distance) / Math.abs(velocity), 200, 1200);\n      }\n\n      this.list.style.transition = `transform ${duration}ms ${EASING}`;\n      this.translateTo(destination, true);\n      this.transitionEndCallback = done;\n    } else {\n      this.translateTo(this.getPositionOf(index, true));\n      done();\n    }\n  }\n\n  /**\n   * Moves the carousel by a number of slides from the current index, ignoring `perMove` and\n   * `perPage` .\n   *\n   * @param offset How many slides to move, negative for backwards\n   */\n  private goBy(offset: number) {\n    this.moveTo(this.computeDestIndex(this.currentIndex + offset, this.currentIndex));\n  }\n\n  /**\n   * Moves the carousel to the next page, respecting `perMove` and `perPage`.\n   *\n   * @param allowSameIndex Determines whether to allow going to the current index or not\n   */\n  private goNext(allowSameIndex?: boolean) {\n    this.moveTo(this.getNextIndex(true), allowSameIndex);\n  }\n\n  /**\n   * Moves the carousel to the previous page, respecting `perMove` and `perPage`.\n   *\n   * @param allowSameIndex Determines whether to allow going to the current index or not\n   */\n  private goPrev(allowSameIndex?: boolean) {\n    this.moveTo(this.getPrevIndex(true), allowSameIndex);\n  }\n\n  /**\n   * Destroys the carousel.\n   *\n   * @param completely If `true`, breakpoints will not remount the carousel\n   */\n  private destroy(completely = true) {\n    if (this.state === MOUNTING) {\n      this.destroyWhenReady = completely;\n    } else {\n      this.track.removeAttribute('aria-live');\n      this.track.removeAttribute('aria-atomic');\n      this.track.removeAttribute('aria-busy');\n      this.screenReaderText.remove();\n\n      this.destroyPagination();\n      this.removeKeyListener();\n\n      // Remove every native listener the slidebar added, including those of a handle press still\n      // underway.\n      if (this.slidebar) {\n        this.removeSlidebarElementListeners();\n      }\n\n      this.removeSlidebarWindowListeners();\n\n      // Remove the track listeners drag added at mount, and the listeners of any drag still\n      // underway.\n      this.removeDragPointerListeners();\n      const track = this.track;\n      track.removeEventListener('touchmove', onTrackNoop, { capture: true });\n      track.removeEventListener('mousemove', onTrackNoop, { capture: true });\n      track.removeEventListener('touchend', onTrackNoop, { capture: true });\n      track.removeEventListener('touchcancel', onTrackNoop, { capture: true });\n      track.removeEventListener('mouseup', onTrackNoop, { capture: true });\n      track.removeEventListener('click', onTrackNoop, { capture: true });\n      track.removeEventListener('touchstart', this.onDragPointerDownBound, { capture: true });\n      track.removeEventListener('mousedown', this.onDragPointerDownBound, { capture: true });\n      track.removeEventListener('click', this.onDragClickBound, { capture: true });\n      track.removeEventListener('dragstart', onTrackDragStart);\n\n      this.autoplayInterval.cancel();\n      this.removeEventListener('mouseenter', this.onAutoplayHoverBound);\n      this.removeEventListener('mouseleave', this.onAutoplayHoverBound);\n      this.removeEventListener('focusin', this.onAutoplayFocusBound);\n      this.removeEventListener('focusout', this.onAutoplayFocusBound);\n      this.autoplayToggle?.removeEventListener('click', this.onAutoplayToggleClickBound);\n\n      this.destroyArrows();\n\n      // The drawn footer stays in place like the track, and the drag bar inside it is left showing,\n      // so the whole row is hidden until the next mount\n      if (this.footer) {\n        this.footer.hidden = true;\n      }\n\n      this.list.removeEventListener('transitionend', this.onListTransitionEndBound);\n\n      this.removeClones();\n      removeEventListener('resize', this.onWindowResizeBound);\n      removeEventListener('load', this.onWindowResizeBound);\n      this.destroySlides();\n      delete this.dataset.mounted;\n      this.removeClassesAndAttributes(completely);\n      this.destroyMediaQueries(completely);\n\n      this.isMounted = false;\n      this.state = DESTROYED;\n    }\n  }\n}\n\n/**\n * Turns a bare number into a number of pixels, and leaves a CSS length like \"1rem\" as a string.\n */\nfunction parseLength(value: string) {\n  if (/^-?\\d+(\\.\\d+)?$/.test(value)) {\n    return parseFloat(value);\n  }\n\n  return value;\n}\n\n/**\n * Fired from a carousel-element when its slides start or stop overflowing it.\n */\ntype CarouselElementOverflowChangedEvent = CustomEvent<{\n  /**\n   * Whether the slides are now wider than the carousel.\n   */\n  isOverflow: boolean;\n}>;\n\n/**\n * Fired from a carousel-element when a slide is clicked, but not when the click ends a drag.\n */\ntype CarouselSlideClickedEvent = CustomEvent<{\n  /**\n   * The index of the clicked slide.\n   */\n  index: number;\n\n  /**\n   * The clicked slide.\n   */\n  slide: HTMLElement;\n}>;\n\n/**\n * Fired from a carousel-element when a slide leaves view.\n */\ntype CarouselSlideHiddenEvent = CustomEvent<{\n  /**\n   * The index of the slide that left view.\n   */\n  index: number;\n\n  /**\n   * The slide that left view.\n   */\n  slide: HTMLElement;\n}>;\n\n/**\n * Fired from a carousel-element once a move to another slide ends, by any means.\n */\ntype CarouselSlideMoveCompletedEvent = CustomEvent<{\n  /**\n   * The index of the slide the carousel moved to.\n   */\n  index: number;\n\n  /**\n   * The index of the slide the carousel moved from.\n   */\n  previousIndex: number;\n}>;\n\n/**\n * Fired from a carousel-element when a move to another slide starts, by any means.\n */\ntype CarouselSlideMoveStartedEvent = CustomEvent<{\n  /**\n   * The index of the slide the carousel is moving to.\n   */\n  index: number;\n\n  /**\n   * The index of the slide the carousel is moving from.\n   */\n  previousIndex: number;\n}>;\n\n/**\n * Fired from a carousel-element when a slide comes into view. A carousel that mounts while hidden\n * can't measure its slides, so it counts every one of them as in view.\n */\ntype CarouselSlideVisibleEvent = CustomEvent<{\n  /**\n   * The index of the slide that came into view.\n   */\n  index: number;\n\n  /**\n   * The slide that came into view.\n   */\n  slide: HTMLElement;\n}>;\n\ndeclare global {\n  interface HTMLElementTagNameMap {\n    'carousel-element': CarouselElement;\n  }\n\n  interface GlobalEventHandlersEventMap {\n    'carousel-element-mounted': Event;\n    'carousel-element-overflow-changed': CarouselElementOverflowChangedEvent;\n    'carousel-element-resized': Event;\n    'carousel-slide-clicked': CarouselSlideClickedEvent;\n    'carousel-slide-hidden': CarouselSlideHiddenEvent;\n    'carousel-slide-move-completed': CarouselSlideMoveCompletedEvent;\n    'carousel-slide-move-started': CarouselSlideMoveStartedEvent;\n    'carousel-slide-visible': CarouselSlideVisibleEvent;\n  }\n}\n\n/**\n * The CSS timing function for the move between slides, a gentle ease out. The fade transition uses\n * it too.\n */\nconst EASING = 'cubic-bezier(0.25, 1, 0.5, 1)';\n\n/**\n * How fast the handle moves toward a held press on the slide bar, in pixels per millisecond.\n */\nconst SLIDEBAR_PRESS_SPEED = 0.8;\n\n/**\n * How long a press on the slide bar can last and still count as a click, in milliseconds.\n */\nconst SLIDEBAR_CLICK_DURATION = 250;\n\n/**\n * How far a touch on the slide bar has to move, in pixels, before we decide whether it is a\n * sideways drag of the carousel or a scroll of the page.\n */\nconst SLIDEBAR_TOUCH_SLOP = 10;\n\n/**\n * The options applied on top of the rest when the visitor's system asks for reduced motion through\n * `prefers-reduced-motion`. These turn off the transition speeds and hold autoplay in its paused\n * state.\n */\nconst REDUCED_MOTION: Options = {\n  speed: 0,\n  autoplay: 'pause'\n};\n\n/**\n * The collection of default options. Note that this collection does not contain all options.\n */\nconst DEFAULTS: Options = {\n  transition: 'slide',\n  role: 'region',\n  speed: 400,\n  perPage: 1,\n  arrows: true,\n  pagination: true,\n  interval: 5000,\n  drag: true,\n  focusableNodes: 'a, button, textarea, input, select, iframe',\n  live: true\n};\n\ninterface Options extends ResponsiveOptions {\n  /**\n   * Lets each slide be as wide as its own content instead of dividing the carousel by `perPage`.\n   * Pair it with `perPage` and `perMove` of `1`, since slides of different widths do not line up\n   * into pages. On a loop carousel it also changes how many clones get made, one per slide.\n   */\n  autoWidth?: boolean;\n\n  /**\n   * Turns on autoplay. With `true` it starts playing as soon as the carousel mounts. With `'pause'`\n   * it gets set up but stays stopped until a visitor presses the play button the element draws for\n   * `data-autoplay-toggle`. Autoplay only runs when there are more slides than `perPage`, and it\n   * pauses while the pointer is over the carousel or focus is inside it. Each play starts the\n   * current slide's wait over from zero.\n   */\n  autoplay?: boolean | 'pause';\n\n  /**\n   * Options that change at given viewport widths. Each key is a width in pixels, and its options\n   * apply while the viewport matches it. By default the keys are max widths, so a key of `600`\n   * applies at 600px and narrower, and when several match the narrowest one wins. With\n   * `mediaQuery: 'min'` they are min widths instead, and the widest matching one wins. Setting\n   * `destroy` inside a breakpoint turns the carousel off at that width.\n   *\n   * @example\n   * ```ts\n   * breakpoints: {\n   *   1000: { perPage: 3, gap: 20 },\n   *   600: { perPage: 1, gap: 5 }\n   * }\n   * ```\n   */\n  breakpoints?: Record<string | number, ResponsiveOptions>;\n\n  /**\n   * A selector for the focusable elements inside a slide. Matches inside a slide that is hidden get\n   * `tabindex=\"-1\"`, so keyboard users cannot tab into slides they cannot see. Defaults to links,\n   * buttons, form fields, and iframes. Extend it when slides hold other focusable things, like\n   * `video`. Set it to an empty string to turn this off.\n   */\n  focusableNodes?: string;\n\n  /**\n   * How long autoplay rests on each slide before moving on, in milliseconds. Defaults to `5000`.\n   */\n  interval?: number;\n\n  /**\n   * Lets the left and right arrow keys move the carousel while focus is inside the carousel root.\n   * Note that the element does not add a `tabindex` to the root, so a root that cannot take focus\n   * on its own only responds once focus is on something inside it. Off by default.\n   */\n  keyboard?: boolean;\n\n  /**\n   * Announces the active slide to screen readers when the carousel moves, through an `aria-live`\n   * region on the track. On by default. It goes quiet while autoplay is playing so it does not talk\n   * over itself.\n   */\n  live?: boolean;\n\n  /**\n   * Whether the `breakpoints` keys are max widths or min widths. Defaults to `'max'`, where a key\n   * applies at that width and narrower, and the narrowest matching key wins. `'min'` flips it, so a\n   * key applies at that width and wider, and the widest matching key wins.\n   */\n  mediaQuery?: 'max' | 'min';\n\n  /**\n   * With `focus` set, stops the carousel at the last position it can actually move to, rather than\n   * letting the active slide keep walking to the last slide while the slides sit still. That\n   * disables the next arrow there and drops the pagination dots that would only change the active\n   * slide without moving anything.\n   */\n  omitEnd?: boolean;\n\n  /**\n   * The `role` attribute for the carousel root. Defaults to `'region'`. It is skipped when the root\n   * already has a `role` of its own or is a `<section>` element, which counts as a region already.\n   */\n  role?: string;\n\n  /**\n   * The kind of carousel. `'slide'` is the default and stops at each end, or wraps back with\n   * `rewind`. `'loop'` wraps around forever by cloning slides at both ends. `'fade'` stacks the\n   * slides in one spot and fades between them, so it shows one slide at a time and `perPage` does\n   * not apply.\n   */\n  transition?: string;\n\n  /**\n   * Moves `data-active` to the new slide as soon as the carousel starts moving, instead of after it\n   * arrives. Useful when an animation tied to `data-active` should run alongside the move.\n   */\n  updateOnMove?: boolean;\n\n}\n\n/**\n * The interface for options that can correspond with breakpoints.\n */\ninterface ResponsiveOptions {\n  /**\n   * Where the slides sit when they all fit and there is nowhere to move. `'start'` puts them at the\n   * start edge and `'center'` centers the row. Left unset, the `focus` option positions them the\n   * same as when they overflow.\n   */\n  align?: 'center' | 'start';\n\n  /**\n   * What a click on an arrow does. Defaults to `'step'`, which moves the slide you are on by one.\n   * `'scroll'` always moves the slides.\n   */\n  arrowBehavior?: 'scroll' | 'step';\n\n  /**\n   * Which icon the arrows the element draws use. Defaults to the line arrow.\n   */\n  arrowIcon?: 'arrow' | 'chevron' | 'chevron-bold' | 'chevron-thin';\n\n  /**\n   * Shows the previous and next arrows. On by default.\n   */\n  arrows?: boolean;\n\n  /**\n   * Where the arrows the element draws sit. Defaults to the footer row it draws.\n   */\n  arrowsPosition?: 'above' | 'beside' | 'corner' | 'edges' | 'footer' | 'sides';\n\n  /**\n   * Turns the carousel off, which is mostly useful inside `breakpoints` to drop the carousel at\n   * some widths. The carousel comes back once a breakpoint without it applies again.\n   */\n  destroy?: boolean;\n\n  /**\n   * Lets the visitor drag or swipe the carousel. On by default.\n   */\n  drag?: boolean;\n\n  /**\n   * Sets every slide to this width, as pixels for a number or any CSS length for a string. Wins\n   * over `perPage`, so the carousel shows however many slides fit. On a loop carousel it also\n   * changes how many clones get made.\n   */\n  fixedWidth?: number | string;\n\n  /**\n   * With `drag` on, the most pages a quick flick can move the carousel. Defaults to `1`.\n   */\n  flickMaxPages?: number;\n\n  /**\n   * With `drag` on, how far a quick flick throws the carousel. A bigger number throws it farther.\n   * Defaults to `600`.\n   */\n  flickPower?: number;\n\n  /**\n   * Which position in the visible slides counts as active when several show at once. A number\n   * counts slides in from the start edge, so `0` is the first visible slide. `'center'` uses the\n   * middle. Setting it also makes the arrows move one slide at a time and lets the carousel move to\n   * every slide, rather than a page at a time. The carousel never moves past its first and last\n   * positions to leave empty space at the ends, so near an end a move can change the active slide\n   * without shifting the slides. See `omitEnd` for more on the ends.\n   */\n  focus?: number | 'center';\n\n  /**\n   * The space between slides, as pixels for a number or any CSS length for a string, like `'1rem'`.\n   * The element accounts for it when dividing the carousel into `perPage` slides.\n   */\n  gap?: number | string;\n\n  /**\n   * Sets the height of the slides, and with them the carousel, as pixels for a number or any CSS\n   * length for a string.\n   */\n  height?: number | string;\n\n  /**\n   * Space inside the carousel at its two ends, which shows a peek of the neighboring slides. A\n   * number or a string sets both ends the same, as pixels for a number or any CSS length for a\n   * string. An object sets the ends separately with `left` and `right`.\n   *\n   * @example\n   * ```ts\n   * padding: 10\n   * padding: '1rem'\n   * padding: { left: 10, right: 20 }\n   * ```\n   */\n  padding?: number | string | { left?: number | string; right?: number | string; };\n\n  /**\n   * Shows the pagination dots. On by default.\n   */\n  pagination?: boolean;\n\n  /**\n   * How many slides one move goes by, for the arrows, the keyboard, and autoplay. Defaults to a\n   * whole page, meaning `perPage` slides, or one slide when `focus` is set.\n   */\n  perMove?: number;\n\n  /**\n   * How many slides fit across the carousel at once. Defaults to `1`. Ignored when `fixedWidth` or\n   * `autoWidth` decides the slide width, and by a fade carousel.\n   */\n  perPage?: number;\n\n  /**\n   * On a `'slide'` carousel, wraps from the last slide back to the first and the other way around,\n   * instead of stopping at the ends. Ignored for `transition: 'loop'`, which wraps on its own.\n   */\n  rewind?: boolean;\n\n  /**\n   * With `rewind` on, also lets a drag past the last slide wrap to the first, and past the first\n   * wrap to the last. Off by default, so only the arrows, the keyboard, and autoplay rewind.\n   */\n  rewindByDrag?: boolean;\n\n  /**\n   * Whether to show a drag bar that tracks and controls the slide position. Off by default. It only\n   * shows while the slides overflow the track.\n   */\n  slidebar?: boolean;\n\n  /**\n   * How long a move between slides takes, in milliseconds. Defaults to `400`. Set it to `0` to jump\n   * with no animation.\n   */\n  speed?: number;\n\n  /**\n   * The most the carousel can grow to, set as its `max-width`, as pixels for a number or any CSS\n   * length for a string. Leave it unset to fill the container.\n   */\n  width?: number | string;\n}\n\n/**\n * The array with all attributes to remove later. Need to manually remove attributes that are not in\n * this. Note that removing `aria-live` disables the live region until the page reload.\n */\nconst ALL_ATTRIBUTES = [\n  'role',\n  'tabindex',\n  'disabled',\n  'aria-controls',\n  'aria-current',\n  'aria-label',\n  'aria-labelledby',\n  'aria-hidden',\n  'aria-roledescription',\n  'inert'\n];\n\n/**\n * The carousel is mounting, so its parts are not all set up yet. A refresh, an options change, or a\n * destroy that comes in meanwhile is held until the mount finishes. A resize or an overflow change\n * only reaches the root.\n */\nconst MOUNTING = 1;\n\n/**\n * The carousel is mounted and sitting still, with no move or drag going on.\n */\nconst IDLE = 2;\n\n/**\n * The carousel is animating to another slide.\n */\nconst MOVING = 3;\n\n/**\n * The shopper is dragging the carousel with a finger or the mouse.\n */\nconst DRAGGING = 4;\n\n/**\n * The carousel was torn down. It can be mounted again from here.\n */\nconst DESTROYED = 5;\n\n/**\n * A `CSSStyleDeclaration` property name that holds a string, such as `marginRight`.\n */\ntype StyleProperty = {\n  [ K in keyof CSSStyleDeclaration ]: CSSStyleDeclaration[K] extends string ? K : never;\n}[keyof CSSStyleDeclaration] & string;\n\ntype AnyFunction = (...args: any[]) => any;\n\n/**\n * Merges the sources into the object one after another and returns the object. A plain object value\n * is merged into a fresh copy rather than replacing what is there, and an array is copied with\n * `slice()` rather than merged.\n *\n * @param object An object to merge properties into\n * @param sources Objects to merge properties from, in order\n *\n * @returns The object it was given.\n */\nfunction merge<T extends Record<string, any>>(object: T, ...sources: Record<string, any>[]) {\n  const target: Record<string, unknown> = object;\n\n  for (const source of sources) {\n    for (const [key, value] of <[string, unknown][]>Object.entries(source)) {\n      if (Array.isArray(value)) {\n        target[key] = value.slice();\n      } else if (value !== null && typeof value === 'object') {\n        let current = target[key];\n        if (current === null || typeof current !== 'object') {\n          current = {};\n        }\n\n        target[key] = merge({}, current, value);\n      } else {\n        target[key] = value;\n      }\n    }\n  }\n\n  return object;\n}\n\ninterface RequestIntervalInterface {\n  cancel(): void;\n  isPaused(): boolean;\n  pause(): void;\n  rewind(): void;\n  set(interval: number): void;\n  start(): void;\n}\n\n/**\n * Requests interval like the native `setInterval()` with using `requestAnimationFrame`.\n *\n * @param initialInterval The interval duration in milliseconds\n * @param onInterval The callback fired on every interval\n */\nfunction createInterval(initialInterval: number, onInterval: () => void) {\n  const now = Date.now;\n\n  /**\n   * The interval duration in milliseconds, which `set` can change.\n   */\n  let interval = initialInterval;\n  let startTime: number;\n\n  /**\n   * The animation frame ID.\n   */\n  let id: number;\n  let paused = true;\n\n  /**\n   * The update function called on every animation frame.\n   */\n  function update() {\n    if (!paused) {\n      const rate = interval ? Math.min((now() - startTime) / interval, 1) : 1;\n      if (rate >= 1) {\n        onInterval();\n        startTime = now();\n      }\n\n      id = requestAnimationFrame(update);\n    }\n  }\n\n  /**\n   * Starts the interval over from zero.\n   */\n  function start() {\n    cancel();\n    startTime = now();\n    paused = false;\n    id = requestAnimationFrame(update);\n  }\n\n  function pause() {\n    paused = true;\n  }\n\n  /**\n   * Rewinds the current progress.\n   */\n  function rewind() {\n    startTime = now();\n  }\n\n  function cancel() {\n    if (id) {\n      cancelAnimationFrame(id);\n    }\n\n    id = 0;\n    paused = true;\n  }\n\n  /**\n   * Sets new interval duration.\n   *\n   * @param time The interval duration in milliseconds\n   */\n  function set(time: number) {\n    interval = time;\n  }\n\n  function isPaused() {\n    return paused;\n  }\n\n  const output: RequestIntervalInterface = {\n    start,\n    rewind,\n    pause,\n    cancel,\n    set,\n    isPaused\n  };\n\n  return output;\n}\n\n/**\n * The interface for the Slide sub component.\n */\ninterface SlideComponent {\n  container: HTMLElement;\n  destroy(): void;\n  index: number;\n  isClone: boolean;\n  mount(): void;\n\n  /**\n   * Called when the carousel starts moving. Updates the slide when the `updateOnMove` option was on\n   * when the slide was created.\n   */\n  onMove(): void;\n  slide: HTMLElement;\n  slideIndex: number;\n  style(property: StyleProperty, value: string | number, useContainer?: boolean): void;\n  update(): void;\n}\n\n/**\n * Returns the `pageX` and `pageY` coordinates provided by the event. Be aware that IE does not\n * support both TouchEvent and MouseEvent constructors.\n *\n * @param event The pointer event to read the coordinate from\n * @param orthogonal If `true`, returns the coord of the orthogonal axis against the drag one\n *\n * @returns A pageX or pageY coordinate.\n */\nfunction getCoord(event: TouchEvent | MouseEvent, orthogonal?: boolean) {\n  const point = isTouchEvent(event) ? event.changedTouches[0] : event;\n  return orthogonal ? point.pageY : point.pageX;\n}\n\n/**\n * Does nothing. Drag adds it to the track's move and up events at mount, which came from upstream\n * with no reason given.\n */\nfunction onTrackNoop(_event: Event) {\n  // Intentionally empty\n}\n\n/**\n * Stops the browser's native drag of images and links inside the track.\n */\nfunction onTrackDragStart(event: DragEvent) {\n  event.preventDefault();\n}\n\nfunction isTouchEvent(event: TouchEvent | MouseEvent): event is TouchEvent {\n  return typeof TouchEvent !== 'undefined' && event instanceof TouchEvent;\n}\n\nfunction isPointerEvent(event: Event): event is TouchEvent | MouseEvent {\n  return event instanceof MouseEvent ||\n    (typeof TouchEvent !== 'undefined' && event instanceof TouchEvent);\n}\n\n/**\n * Creates an arrow button. In IE, A SVG element is focusable.\n *\n * @param prev Determines whether to create a previous or next arrow\n *\n * @returns A created button element.\n */\n/**\n * Creates an arrow button holding one of the arrow icons, the line arrow when the icon is unknown.\n * Both buttons point right, and the stylesheet flips the previous one.\n */\nfunction createArrow(prev: boolean, icon: Options['arrowIcon']) {\n  const modifier = prev ? 'arrow-prev' : 'arrow-next';\n  const start = '<svg class=\"arrow-icon\" role=\"presentation\" ' +\n    'xmlns=\"http://www.w3.org/2000/svg\" fill=\"none\" focusable=\"false\" ';\n\n  let svg;\n  if (icon === 'chevron') {\n    svg = start + 'width=\"32\" height=\"32\" viewBox=\"0 0 32 33\">' +\n      '<circle class=\"arrow-disc\" cx=\"16\" cy=\"16.4727\" r=\"16\"/>' +\n      '<path d=\"M13 9.47266L20 16.4727L13 23.4727\" stroke=\"currentColor\" stroke-width=\"1.5\" ' +\n      'stroke-linecap=\"round\"/>' +\n      '</svg>';\n  } else if (icon === 'chevron-bold') {\n    svg = start + 'width=\"30\" height=\"30\" viewBox=\"0 0 30 30\">' +\n      '<circle class=\"arrow-disc\" cx=\"15\" cy=\"15\" r=\"15\"/>' +\n      '<path d=\"M10.9615 23.077L18.4615 15.0001L10.9615 6.92318\" stroke=\"currentColor\" ' +\n      'stroke-width=\"2\" stroke-linejoin=\"round\"/>' +\n      '</svg>';\n  } else if (icon === 'chevron-thin') {\n    svg = start + 'width=\"36\" height=\"36\" viewBox=\"0 0 24 24\">' +\n      '<path d=\"M9 18L15 12L9 6\" stroke=\"currentColor\" stroke-linecap=\"round\" ' +\n      'stroke-linejoin=\"round\"/>' +\n      '</svg>';\n  } else {\n    svg = start + 'width=\"19\" height=\"18\" viewBox=\"0 0 19 18\">' +\n      '<path d=\"M4.25 9H14.75\" stroke=\"currentColor\" stroke-linecap=\"round\" ' +\n      'stroke-linejoin=\"round\"/>' +\n      '<path d=\"M9.5 14.25L14.75 9L9.5 3.75\" stroke=\"currentColor\" stroke-linecap=\"round\" ' +\n      'stroke-linejoin=\"round\"/>' +\n      '</svg>';\n  }\n\n  const arrow = `<button class=\"arrow ${modifier}\" type=\"button\" ` +\n    `data-arrow-icon=\"${icon || 'arrow'}\">${svg}</button>`;\n\n  const parser = new DOMParser();\n  const parsedDocument = parser.parseFromString(arrow, 'text/html');\n  return <HTMLButtonElement>parsedDocument.body.firstElementChild;\n}\n\n/**\n * Creates the autoplay play and pause button. The stylesheet shows one icon or the other from the\n * button's playing state.\n */\nfunction createAutoplayToggle() {\n  const toggle = '<button id=\"toggle\" type=\"button\">' +\n    '<svg role=\"presentation\" id=\"toggle-play\" viewBox=\"0 0 24 24\" ' +\n    'xmlns=\"http://www.w3.org/2000/svg\" focusable=\"false\"><path d=\"m22 12-20 11v-22l10 5.5z\"/></svg>' +\n    '<svg role=\"presentation\" id=\"toggle-pause\" viewBox=\"0 0 24 24\" ' +\n    'xmlns=\"http://www.w3.org/2000/svg\" focusable=\"false\"><path d=\"m2 1v22h7v-22zm13 0v22h7v-22z\"/></svg>' +\n    '</button>';\n\n  const parser = new DOMParser();\n  const parsedDocument = parser.parseFromString(toggle, 'text/html');\n  return <HTMLButtonElement>parsedDocument.body.firstElementChild;\n}\n\n/**\n * The interface for each pagination item.\n */\ninterface PaginationItem {\n  button: HTMLButtonElement;\n\n  listItem: HTMLLIElement;\n  page: number;\n}\n\nfunction normalizeKey(key: string | KeyboardEvent) {\n  // Older browsers report some keys by nonstandard names, so we map those to the standard ones.\n  const standardNames: Record<string, string> = {\n    Spacebar: ' ',\n    Right: 'ArrowRight',\n    Left: 'ArrowLeft',\n    Up: 'ArrowUp',\n    Down: 'ArrowDown'\n  };\n\n  const name = typeof key === 'string' ? key : key.key;\n  const standardName = standardNames[name];\n  return standardName ? standardName : name;\n}\n\n/**\n * Checks if the provided 2 numbers are approximately equal or not.\n *\n * @param x A number\n * @param y Another number to compare\n * @param epsilon An accuracy that defines the approximation\n *\n * @returns `true` if 2 numbers are considered to be equal, or otherwise `false`.\n */\nfunction approximatelyEqual(x: number, y: number, epsilon: number) {\n  return Math.abs(x - y) < epsilon;\n}\n\n/**\n * Checks if the subject number is between `x` and `y`.\n *\n * @param number A subject number to check\n * @param x A min or max number\n * @param y A max or min number\n * @param exclusive Whether to exclude `x` or `y`\n */\nfunction between(number: number, x: number, y: number, exclusive?: boolean) {\n  const minimum = Math.min(x, y);\n  const maximum = Math.max(x, y);\n  return exclusive ?\n    minimum < number && number < maximum :\n    minimum <= number && number <= maximum;\n}\n\n/**\n * Clamps a number.\n *\n * @param number A subject number to check\n * @param x A min or max number\n * @param y A min or max number\n *\n * @returns A clamped number.\n */\nfunction clamp(number: number, x: number, y: number) {\n  const minimum = Math.min(x, y);\n  const maximum = Math.max(x, y);\n  return Math.min(Math.max(minimum, number), maximum);\n}\n\nfunction sign(x: number) {\n  if (x > 0) {\n    return 1;\n  }\n\n  if (x < 0) {\n    return -1;\n  }\n\n  return 0;\n}\n\n/**\n * Appends `px` to the provided number. If the value is already string, just returns it.\n *\n * @param value A value to append `px` to\n *\n * @returns A string with the CSS unit.\n */\nfunction unit(value: number | string) {\n  if (typeof value === 'string') {\n    return value;\n  }\n\n  return value ? `${value}px` : '';\n}\n\nif (!customElements.get('carousel-element')) {\n  customElements.define('carousel-element', CarouselElement);\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"],"names":["assert","expression","message","AssertionError","Error","constructor","super","this","name","now","_performance","performance","error","console","debug","Date","CarouselElement","HTMLElement","static","releaseReady","hasMountedSinceConnect","onNextArrowClickBound","onNextArrowClick","bind","onPrevArrowClickBound","onPrevArrowClick","onAutoplayHoverBound","onAutoplayHover","onAutoplayFocusBound","onAutoplayFocus","onAutoplayToggleClickBound","onAutoplayToggleClick","onListTransitionEndBound","onListTransitionEnd","onDragPointerMoveBound","onDragPointerMove","onDragPointerUpBound","onDragPointerUp","onDragPointerDownBound","onDragPointerDown","onDragClickBound","onDragClick","onSlidebarMouseDownBound","onSlidebarMouseDown","onSlidebarTouchStartBound","onSlidebarTouchStart","onSlidebarHandleTransitionEndBound","onSlidebarHandleTransitionEnd","onSlidebarBackgroundMouseDownBound","onSlidebarBackgroundMouseDown","onSlidebarTouchMoveBound","onSlidebarTouchMove","onSlidebarTouchEndBound","onSlidebarTouchEnd","onSlidebarTouchCancelBound","onSlidebarTouchCancel","onSlidebarMouseMoveBound","onSlidebarMouseMove","onSlidebarMouseUpBound","onSlidebarMouseUp","onSlidebarBackgroundMouseUpBound","onSlidebarBackgroundMouseUp","onSlidebarBackgroundMouseMoveBound","onSlidebarBackgroundMouseMove","pushSlidebarHandleBound","pushSlidebarHandle","onWindowResizeBound","onWindowResize","onKeyDownBound","onKeyDown","onMediaChangeBound","onMediaChange","onPaginationClickBound","onPaginationClick","onPaginationKeyDownBound","onPaginationKeyDown","attributeChangedCallback","_oldValue","newValue","refreshParts","index","parseInt","goTo","connectedCallback","callback","type","document","readyState","timer","setTimeout","clearTimeout","addEventListener","removeEventListener","ready","onReady","disconnectedCallback","destroy","dataset","currentPerPage","slideCount","_event","buildAndMount","build","state","MOUNTING","isFadeTransition","undefined","transitionEndCallback","readOptions","mountParts","overflowPadding","setOverflowPadding","isOverflowing","start","writeState","event","Event","bubbles","composed","dispatchEvent","onMove","previousIndex","CustomEvent","detail","onMoved","onResized","onClick","slide","onVisible","onHidden","onOverflow","isOverflow","drag","mergeOptions","right","parseLength","padding","currentIndex","toString","currentOptions","perPage","slideElements","length","shadowRoot","attachShadow","mode","innerHTML","_this$dataset$padding","options","merge","DEFAULTS","transition","role","align","arrowBehavior","arrowIcon","arrowsPosition","arrows","pagination","rewind","rewindByDrag","speed","keyboard","live","autoplay","interval","autoWidth","updateOnMove","flickPower","parseFloat","flickMaxPages","omitEnd","slidebar","perMove","fixedWidth","focus","focusableNodes","gap","height","startsWith","JSON","parse","mediaQuery","breakpoints","baseOptions","DESTROYED","includes","isMounted","isRefreshPending","isUpdatePending","prevIndex","mediaQueries","isMin","widths","Object","keys","sort","width1","width2","width","registerMediaQuery","REDUCED_MOTION","updateMediaQueries","trackModifierClasses","findTrack","collectSlides","setRoles","updateModifierClasses","mounted","slides","registerSlides","lastRootRect","wasOverflowing","applySizeOptions","isResizeScheduled","clones","createClones","updateIndexBounds","list","footer","hidden","initArrows","_this$autoplayToggle","_this$autoplayToggle2","autoplayInterval","initialInterval","onInterval","startTime","id","paused","update","Math","min","requestAnimationFrame","cancel","pause","cancelAnimationFrame","set","time","isPaused","createInterval","goNext","autoplayToggle","find","isHovered","isFocusWithin","isAutoplayStopped","isAutoplayEnabled","toggle","parser","DOMParser","parseFromString","body","firstElementChild","createAutoplayToggle","getFooter","prepend","setAttribute","track","playAutoplay","updateAutoplay","isDraggedPastEdge","releaseVelocity","dragBaseEvent","dragPrevBaseEvent","isDragging","shouldPreventClick","dragTarget","dragOptions","passive","capture","onTrackNoop","onTrackDragStart","slidebarHandle","hasDrawnSlidebar","isSlidebarEnabled","handlePosition","previousTouchX","slidebarTouchAxis","addKeyListener","paginationItems","paginationList","initPagination","screenReaderText","createElement","screenReaderTextTimeout","isLiveEnabled","setAriaLive","textContent","reposition","initFadeTransition","updateArrows","isDragDisabled","initialized","IDLE","destroyWhenReady","completely","toggleSlidebar","updateParts","checkCloneCount","destroyArrows","removeKeyListener","destroyPagination","removeClassesAndAttributes","destroySlides","removeClones","cloneCount","computeCloneCount","count","slice","push","tail","concat","forEach","isHead","clone","cloneNode","before","after","registerSlide","resizeSlides","slideIndex","object","createSlide","mount","slide1","slide2","carousel","styles","getAttribute","label","isClone","container","querySelector","destroyed","wasVisible","self","isActive","active","visible","trackRect","getBoundingClientRect","slideRect","floor","left","ceil","isVisible","max","isPeeking","contains","activeElement","blur","MOVING","removeAttribute","querySelectorAll","focusable","Array","from","inert","updateVisibility","attribute","ALL_ATTRIBUTES","style","property","value","useContainer","target","fixedSize","getSlideSize","fixedCount","remove","entries","attributes","classList","rootAttributes","add","children","tagName","cancelTransition","onResize","maxWidth","unit","paddingLeft","getPaddingCss","paddingRight","force","newRect","styleSlides","getSlideSizeCss","notifyResized","prevOverflow","overflowing","notifyOverflowChanged","getSlidesSize","getListSize","withoutGap","getTotalSizeThrough","getSlideAt","getGap","getComputedStyle","marginRight","Number","isNaN","abs","endIndex","getEndIndex","updateSlidebarSize","notifyMove","wasKeyboardDisabled","isKeyboardDisabled","updatePagination","moveSlidebarHandle","toggleScreenReaderText","append","notifyMoved","newSlidebarPosition","gapsBetweenSlides","maxHandlePosition","newTrackPosition","getPositionOf","getSlidebarPositionForTrack","clampSlidebarHandlePosition","transform","translateTo","sideValue","goPrev","trackPosition","arrowsWrapper","position","arrowsBeside","prevArrow","createArrow","nextArrow","arrowClickTrack","clickTrack","prev","next","getPrevIndex","nextIndex","getNextIndex","prevLabel","nextLabel","disabled","maxIndex","clamp","createPagination","pageCount","controlsPosition","parentNode","page","listItem","button","getPaginationItemAt","getIndex","curr","hasEnoughSlides","getPageOfIndex","item","entry","currentTarget","goToPage","key","normalizeKey","nextPage","preventScroll","preventDefault","stopPropagation","stopImmediatePropagation","selector","query","queryList","matchMedia","merged","reduce","matches","destroyMediaQueries","applyReducedMotion","enable","assign","newOptions","base","notify","isTouchEvent","changedTouches","isTouch","window","cancelMove","saveDragBase","isPointerEvent","DRAGGING","cancelable","friction","dragBasePosition","getDragDistance","expired","getDragDuration","wasExceeded","isPositionExceedingLimit","hasExceeded","newPosition","threshold","moveAfterDrag","removeDragPointerListeners","getPosition","velocity","throwDistance","maxDistance","distance","destination","sign","goBy","closest","getIndexAt","orthogonal","getCoord","getDragBaseEvent","timeStamp","tested","exceededMin","getPositionLimit","exceededMax","dragSlidebarHandle","movementX","alignTrackToSlidebar","touch","touches","slidebarTouchStartX","clientX","slidebarTouchStartY","clientY","isSlidebarTouchOnHandle","distanceX","distanceY","SLIDEBAR_TOUCH_SLOP","getSlidebarTouchX","offsetWidth","axis","pressX","goToSlidebarPress","slidebarPressX","offsetX","slidebarPressDirection","slidebarPressTime","slidebarPressStartTime","isSlidebarPressCaughtUp","slidebarPressFrame","stopSlidebarPress","SLIDEBAR_CLICK_DURATION","direction","segmentWidth","round","getTrackPositionForSlidebar","elapsed","step","SLIDEBAR_PRESS_SPEED","removeSlidebarWindowListeners","enableSlidebar","disableSlidebar","calculateSlidebarHandleWidth","appendChild","inFooter","removeSlidebarElementListeners","maxTrackPosition","handleWidth","toPosition","currentTrackPosition","syncAutoplay","pauseAutoplay","stop","playing","allowSameIndex","moveTo","getIndexOfPage","getAdjacentIndex","snapPage","destinationIndex","computeDestIndex","steps","approximatelyEqual","loopIndex","end","desired","between","remainder","lastPageSize","canShift","shiftPosition","startTransition","preventLoop","loopPosition","backwards","excess","size","neededShifts","minDistance","Infinity","trimming","offset","shifted","scrollWidth","done","EASING","duration","_this$autoplayToggle3","test","_len","arguments","sources","_key","source","isArray","current","point","pageY","pageX","TouchEvent","MouseEvent","icon","svg","arrow","standardName","Spacebar","Right","Left","Up","Down","x","y","epsilon","number","exclusive","minimum","maximum","customElements","get","define"],"sourceRoot":""}